Rust was written by these fine people:
-A.J. Gardner <mrhota@users.noreply.github.com>
Aaron Friel <mayreply@aaronfriel.com>
+Aaron Gallagher <_@habnab.it>
Aaron Laursen <aaronlaursen@gmail.com>
Aaron Liblong <liblonga@physics.utoronto.ca>
Aaron Raimist <aaron@aaronraimist.com>
Aaron Todd <github@opprobrio.us>
Aaron Turon <aturon@mozilla.com>
Aaron Weiss <aaronweiss74@gmail.com>
-Abhishek Chanda <abhishek@cloudscaling.com>
+Abhishek Chanda <abhishek.becs@gmail.com>
Adam Bozanich <adam.boz@gmail.com>
Adam Jacob <adam@opscode.com>
Adam Roben <adam@roben.org>
Ahmed Charles <ahmedcharles@gmail.com>
Aidan Cully <github@aidan.users.panix.com>
Aidan Hobson Sayers <aidanhs@cantab.net>
+A.J. Gardner <mrhota@users.noreply.github.com>
Akos Kiss <akiss@inf.u-szeged.hu>
+Akshay Chiwhane <achiwhane@gmail.com>
Alan Andrade <alan.andradec@gmail.com>
Alan Cutter <alancutter@chromium.org>
Alan Williams <mralert@gmail.com>
Aleksander Balicki <balicki.aleksander@gmail.com>
Aleksandr Koshlo <sash7ko@gmail.com>
-Alex Crichton <alex@alexcrichton.com>
-Alex Gaynor <alex.gaynor@gmail.com>
-Alex Lyon <arcterus@mail.com>
-Alex Quach <alex@clinkle.com>
-Alex Rønne Petersen <alex@lycus.org>
-Alex Whitney <aw1209@ic.ac.uk>
+Alexander Artemenko <svetlyak.40wt@gmail.com>
Alexander Bliskovsky <alexander.bliskovsky@gmail.com>
Alexander Campbell <alexanderhcampbell@gmail.com>
Alexander Chernyakhovsky <achernya@mit.edu>
Alexander Korolkov <alexander.korolkov@gmail.com>
Alexander Light <allight@cs.brown.edu>
+Alexander Polakov <plhk@sdf.org>
Alexander Stavonin <a.stavonin@gmail.com>
Alexandre Gagnon <alxgnon@gmail.com>
Alexandros Tasos <sdi1100085@di.uoa.gr>
+Alex Burka <durka42+github@gmail.com>
+Alex Crichton <alex@alexcrichton.com>
Alexei Sholik <alcosholik@gmail.com>
+Alex Gaynor <alex.gaynor@gmail.com>
Alexis Beingessner <a.beingessner@gmail.com>
+Alex Lyon <arcterus@mail.com>
+Alex Quach <alex@clinkle.com>
+Alex Rønne Petersen <alex@lycus.org>
+Alex Stokes <r.alex.stokes@gmail.com>
+Alex Whitney <aw1209@ic.ac.uk>
Alfie John <alfie@alfie.wtf>
-Ali Smesseim <smesseim.ali@gmail.com>
Alisdair Owens <awo101@zepler.net>
+Ali Smesseim <smesseim.ali@gmail.com>
Aljaž "g5pw" Srebrnič <a2piratesoft@gmail.com>
Amol Mundayoor <amol.com@gmail.com>
Amy Unger <amy.e.unger@gmail.com>
+Anatoly Ikorsky <aikorsky@gmail.com>
Anders Kaseorg <andersk@mit.edu>
-Andre Arko <andre@arko.net>
Andrea Canciani <ranma42@gmail.com>
+Andre Arko <andre@arko.net>
Andreas Gal <gal@mozilla.com>
Andreas Martens <andreasm@fastmail.fm>
Andreas Neuhaus <zargony@zargony.com>
Andreas Ots <andreasots@gmail.com>
Andreas Tolfsen <ato@mozilla.com>
Andrei Formiga <archimedes_siracusa@hotmail.com>
+Andrei Oprea <andrei.br92@gmail.com>
Andrew Barchuk <raindev@icloud.com>
Andrew Cann <shum@canndrew.org>
Andrew Chin <achin@eminence32.net>
Andrew Dunham <andrew@du.nham.ca>
+Andrew Foote <afoote97@gmail.com>
Andrew Gallant <jamslam@gmail.com>
Andrew Hobden <andrew@hoverbear.org>
+Andrew Kensler <andrew@eastfarthing.com>
Andrew Paseltiner <apaseltiner@gmail.com>
Andrew Poelstra <asp11@sfu.ca>
Andrew Seidl <dev@aas.io>
+Andrew Straw <strawman@astraw.com>
Andrew Wagner <drewm1980@gmail.com>
+Andrzej Janik <vosen@vosen.pl>
Angus Lees <gus@inodes.org>
Anthony Juckel <ajuckel@gmail.com>
Anton Löfgren <anton.lofgren@gmail.com>
Aram Visser <aramvisser@gmail.com>
-Areski Belaid <areski@gmail.com>
Arcterus <Arcterus@mail.com>
+Areski Belaid <areski@gmail.com>
Ariel Ben-Yehuda <arielb1@mail.tau.ac.il>
Arjan Topolovec <arjan.top@gmail.com>
Arkaitz Jimenez <arkaitzj@gmail.com>
Arpad Borsos <arpad.borsos@googlemail.com>
Artem <artemciy@gmail.com>
Arthur Liao <arthurtw8@gmail.com>
+arturo <arturo@openframeworks.cc>
Ashok Gautham <ScriptDevil@gmail.com>
Augusto Hack <hack.augusto@gmail.com>
+auREAX <mark@xn--hwg34fba.ws>
Austin Bonander <austin.bonander@gmail.com>
+Austin Hellyer <hello@austinhellyer.me>
Austin King <shout@ozten.com>
Austin Seipp <mad.one@gmail.com>
+Avdi Grimm <avdi@avdi.org>
+awlnx <alecweber1994@gmail.com>
Axel Viala <axel.viala@darnuria.eu>
Aydin Kim <ladinjin@hanmail.net>
+bachm <Ab@vapor.com>
Barosl Lee <vcs@barosl.com>
+bcoopers <coopersmithbrian@gmail.com>
Ben Alpert <ben@benalpert.com>
+benaryorg <binary@benary.org>
Ben Ashford <ben@bcash.org>
Ben Blum <bblum@andrew.cmu.edu>
+ben fleis <ben.fleis@gmail.com>
Ben Foppa <benjamin.foppa@gmail.com>
Ben Gamari <bgamari.foss@gmail.com>
+Ben Gesoff <ben.gesoff@gmail.com>
Ben Harris <mail@bharr.is>
-Ben Kelly <ben@wanderview.com>
-Ben Noordhuis <info@bnoordhuis.nl>
-Ben Sago <ogham@users.noreply.github.com>
-Ben Striegel <ben.striegel@gmail.com>
Benjamin Adamson <adamson.benjamin@gmail.com>
Benjamin Herr <ben@0x539.de>
Benjamin Jackman <ben@jackman.biz>
Benjamin Kircher <benjamin.kircher@gmail.com>
Benjamin Peterson <benjamin@python.org>
+Ben Kelly <ben@wanderview.com>
+Ben Noordhuis <info@bnoordhuis.nl>
+Ben Sago <ogham@users.noreply.github.com>
+Ben Striegel <ben.striegel@gmail.com>
Bheesham Persaud <bheesham123@hotmail.com>
Bilal Husain <bilal@bilalhusain.com>
Bill Fallon <bill.fallon@robos.li>
Bill Wendling <wendling@apple.com>
Birunthan Mohanathas <birunthan@mohanathas.com>
Björn Steinbrink <bsteinbr@gmail.com>
+blake2-ppc <ulrik.sverdrup@gmail.com>
+bluss <bluss>
+bluss <bluss@users.noreply.github.com>
Boris Egorov <egorov@linux.com>
+bors <bors@rust-lang.org>
Bouke van der Bijl <boukevanderbijl@gmail.com>
+Brad King <brad.king@kitware.com>
Brandon Sanderson <singingboyo@gmail.com>
Brandon Waskiewicz <brandon.waskiewicz@gmail.com>
Branimir <branimir@volomp.com>
Brian J. Burg <burg@cs.washington.edu>
Brian Koropoff <bkoropoff@gmail.com>
Brian Leibig <brian@brianleibig.com>
+Brian Quinlan <brian@sweetapp.com>
Bruno de Oliveira Abinader <bruno.d@partner.samsung.com>
Bryan Dunsmore <dunsmoreb@gmail.com>
Byron Williams <byron@112percent.com>
Cadence Marseille <cadencemarseille@gmail.com>
Caitlin Potter <snowball@defpixel.com>
-Cam Jackson <camjackson89@gmail.com>
Cameron Zwarich <zwarich@mozilla.com>
Camille Roussel <camille@rousselfamily.com>
Camille TJHOA <camille.tjhoa@outlook.com>
-CarVac <c.lo.to.da.down.lo@gmail.com>
-Carl Lerche <me@carllerche.com>
+Cam Jackson <camjackson89@gmail.com>
Carl-Anton Ingmarsson <mail@carlanton.se>
+Carl Lerche <me@carllerche.com>
Carlos Galarza <carloslfu@gmail.com>
Carol (Nichols || Goulding) <carol.nichols@gmail.com>
Carol Willing <carolcode@willingconsulting.com>
Carter Hinsley <carterhinsley@gmail.com>
Carter Tazio Schonwald <carter.schonwald@gmail.com>
+CarVac <c.lo.to.da.down.lo@gmail.com>
Caspar Krieger <caspar@asparck.com>
Chase Southwood <chase.southwood@gmail.com>
Ches Martin <ches@whiskeyandgrits.net>
+chitra
Chloe <5paceToast@users.noreply.github.com>
Chris Double <chris.double@double.co.nz>
+Chris Hellmuth <chellmuth@gmail.com>
Chris Morgan <me@chrismorgan.info>
Chris Nixon <chris.nixon@sigma.me.uk>
Chris Peterson <cpeterson@mozilla.com>
Chris Sainty <csainty@hotmail.com>
Chris Shea <cmshea@gmail.com>
Chris Thorn <chris@thorn.co>
-Chris Wong <lambda.fairy@gmail.com>
+Christian Stadelmann <dev@genodeftest.de>
Christoph Burgdorf <christoph.burgdorf@bvsn.org>
Christopher Bergqvist <spambox0@digitalpoetry.se>
Christopher Chambers <chris.chambers@peanutcode.com>
Christopher Kendell <ckendell@outlook.com>
+Chris Wong <lambda.fairy@gmail.com>
+chromatic <chromatic@wgz.org>
+Chuck Bassett <iamchuckb@gmail.com>
Chuck Ries <chuck.ries@gmail.com>
Clark Gaebel <cg.wowus.cg@gmail.com>
+clatour <chandler.latour@gmail.com>
Clifford Caoile <piyo@users.sf.net>
Clinton Ryan <clint.ryan3@gmail.com>
Cody P Schafer <dev@codyps.com>
Cody Schroeder <codys@cs.washington.edu>
Cole Mickens <cole.mickens@gmail.com>
+Cole Reynolds <cpjreynolds@gmail.com>
Colin Davidson <colrdavidson@gmail.com>
Colin Sherratt <colin.sherratt@gmail.com>
+Colin Walters <walters@verbum.org>
+comex <comexk@gmail.com>
Conrad Kleinespel <conradk@conradk.com>
Corey Farwell <coreyf+rust@rwell.org>
Corey Ford <corey@coreyford.name>
Corey Richardson <corey@octayn.net>
-Cristi Burcă <scribu@gmail.com>
+Cornel Punga <cornel.punga@gmail.com>
+crhino <piraino.chris@gmail.com>
Cristian Kubis <cristian.kubis@tsunix.de>
-DJUrsus <colinvh@divitu.com>
-David Ross <daboross@daboross.net>
+Cristi Burcă <scribu@gmail.com>
+critiqjo <john.ch.fr@gmail.com>
+Cruz Julian Bishop <cruzjbishop@gmail.com>
Damian Gryski <damian@gryski.com>
Damien Grassart <damien@grassart.com>
Damien Radtke <dradtke@channeliq.com>
Dan Burkert <dan@danburkert.com>
Dan Callahan <dan.callahan@gmail.com>
Dan Connolly <dckc@madmode.com>
-Dan Luu <danluu@gmail.com>
-Dan Schatzberg <schatzberg.dan@gmail.com>
-Dan W. <1danwade@gmail.com>
-Dan Yang <dsyang@fb.com>
Daniel Brooks <db48x@db48x.net>
Daniel Fagnan <dnfagnan@gmail.com>
Daniel Farina <daniel@fdr.io>
Daniel Patterson <dbp@riseup.net>
Daniel Raloff <draloff@side2.com>
Daniel Ralston <Wubbulous@gmail.com>
+Daniel Ramos <dan@daramos.com>
Daniel Rosenwasser <DanielRosenwasser@gmail.com>
Daniel Ursache Dogariu <contact@danniel.net>
Daniil Smirnov <danslapman@gmail.com>
+Dan Luu <danluu@gmail.com>
+Dan Schatzberg <schatzberg.dan@gmail.com>
+Dan W. <1danwade@gmail.com>
+Dan Yang <dsyang@fb.com>
Darin Morrison <darinmorrison+git@gmail.com>
+darkf <lw9k123@gmail.com>
Darrell Hamilton <darrell.noice@gmail.com>
Dave Herman <dherman@mozilla.com>
Dave Hodder <dmh@dmh.org.uk>
Dave Huseby <dhuseby@mozilla.com>
+David Campbell <dcampbell24@gmail.com>
David Creswick <dcrewi@gyrae.net>
David Forsythe <dforsythe@gmail.com>
David Halperin <halperin.dr@gmail.com>
David Mally <djmally@gmail.com>
David Manescu <david.manescu@gmail.com>
David Rajchenbach-Teller <dteller@mozilla.com>
+David Reid <dreid@dreid.org>
David Renshaw <dwrenshaw@gmail.com>
+David Ross <daboross@daboross.net>
+David Stygstra <david.stygstra@gmail.com>
David Vazgenovich Shakaryan <dvshakaryan@gmail.com>
+David Voit <david.voit@gmail.com>
Davis Silverman <sinistersnare@gmail.com>
+defuz <defuz.net@gmail.com>
Denis Defreyne <denis.defreyne@stoneship.org>
Derecho <derecho@sector5d.org>
Derek Chiang <derekchiang93@gmail.com>
Derek Guenther <dguenther9@gmail.com>
Derek Harland <derek.harland@finq.co.nz>
+dgoon <dgoon@dgoon.net>
Diego Giagio <diego@giagio.com>
Diego Ongaro <ongaro@cs.stanford.edu>
Diggory Blake <diggsey@googlemail.com>
Diggory Hardy <diggory.hardy@gmail.com>
Dimitri Krassovski <labria@startika.com>
Dirk Gadsden <dirk@esherido.com>
-Dirk Leifeld <leifeld@posteo.de>
Dirkjan Bussink <d.bussink@gmail.com>
+Dirk Leifeld <leifeld@posteo.de>
Div Shekhar <div@pagerduty.com>
+diwic <diwic@users.noreply.github.com>
+DJUrsus <colinvh@divitu.com>
+dmgawel <dgkonik@gmail.com>
Dmitry Ermolov <epdmitry@yandex.ru>
Dmitry Promsky <dmitry@willworkforcookies.com>
Dmitry Vasiliev <dima@hlabs.org>
-Do Nhat Minh <mrordinaire@gmail.com>
-Dominic van Berkel <dominic@baudvine.net>
Dominick Allen <dominick.allen1989@gmail.com>
+Dominic van Berkel <dominic@baudvine.net>
Dominik Inführ <dominik.infuehr@gmail.com>
+Do Nhat Minh <mrordinaire@gmail.com>
+donkopotamus <general@chocolate-fish.com>
Donovan Preston <donovanpreston@gmail.com>
+Don Petersen <don@donpetersen.net>
Douglas Young <rcxdude@gmail.com>
Drew Crawford <drew@sealedabstract.com>
Drew Willcoxon <adw@mozilla.com>
Dylan Ede <dylanede@googlemail.com>
Dzmitry Malyshau <kvarkus@gmail.com>
Earl St Sauver <estsauver@gmail.com>
+econoplas <econoplas@gmail.com>
Eduard Bopp <eduard.bopp@aepsil0n.de>
Eduard Burtescu <edy.burt@gmail.com>
Eduardo Bautista <me@eduardobautista.com>
Edward Z. Yang <ezyang@cs.stanford.edu>
Ehsanul Hoque <ehsanul@ehsanul.com>
Elantsev Serj <elantsev@yandex-team.ru>
+Eli Friedman <eli.friedman@gmail.com>
+eliovir <eliovir@gmail.com>
Elliott Slaughter <elliottslaughter@gmail.com>
Elly Fong-Jones <elly@leptoquark.net>
+elszben <notgonna@tellyou>
+emanueLczirai <emanueLczirai@cryptoLab.net>
Emanuel Rylke <ema-fox@web.de>
Emeliov Dmitrii <demelev1990@gmail.com>
+Emilio Cobos Álvarez <ecoal95@gmail.com>
+Emily Dunham <edunham@mozilla.com>
Eric Allen <ericpallen@gmail.com>
Eric Biggers <ebiggers3@gmail.com>
Eric Holk <eric.holk@gmail.com>
Eric Holmes <eric@ejholmes.net>
Eric Kidd <git@randomhacks.net>
+Erick Rivas <chemical.rivas@gmail.com>
+Erick Tryzelaar <erick.tryzelaar@gmail.com>
Eric Martin <e.a.martin1337@gmail.com>
Eric Platon <eric.platon@waku-waku.ne.jp>
Eric Reed <ecreed@cs.washington.edu>
-Erick Rivas <chemical.rivas@gmail.com>
-Erick Tryzelaar <erick.tryzelaar@gmail.com>
+Eric Ye <me@ericye16.com>
Erik Lyon <elyon001@local.fake>
+Erik Michaels-Ober <sferik@gmail.com>
Erik Price <erik.price16@gmail.com>
Erik Rose <erik@mozilla.com>
Erwan <erwan.ricq@gmail.com>
Felix Crux <felixc@felixcrux.com>
Felix Raimundo <felix.raimundo@telecom-paristech.fr>
Felix S. Klock II <pnkfelix@pnkfx.org>
+fenduru <fenduru@users.noreply.github.com>
Fenhl <fenhl@fenhl.net>
Filip Szczepański <jazz2rulez@gmail.com>
Flaper Fesp <flaper87@gmail.com>
+flo-l <lacknerflo@gmail.com>
Florian Gilcher <florian.gilcher@asquera.de>
Florian Hahn <flo@fhahn.com>
Florian Hartwig <florian.j.hartwig@gmail.com>
Florian Wilkens <mrfloya_github@outlook.com>
Florian Zeitz <florob@babelmonkeys.de>
+fort <e@mail.com>
Francisco Souza <f@souza.cc>
+frankamp <frankamp@gmail.com>
Franklin Chen <franklinchen@franklinchen.com>
+Franziska Hinkelmann <franziska.hinkelmann@gmail.com>
+free-Runner <aali07@students.poly.edu>
FuGangqiang <fu_gangqiang@163.com>
+funkill <funkill2@gmail.com>
+g3xzh <g3xzh@yahoo.com>
+Gábor Horváth <xazax.hun@gmail.com>
+Gábor Lehel <glaebhoerl@gmail.com>
Gabriel <g2p.code@gmail.com>
+gamazeps <gamaz3ps@gmail.com>
Gareth Daniel Smith <garethdanielsmith@gmail.com>
+gareth <gareth@gareth-N56VM.(none)>
+Garming Sam <garming_sam@outlook.com>
Garrett Heel <garrettheel@gmail.com>
Gary Linscott <glinscott@gmail.com>
Gary M. Josack <gary@byoteki.com>
Gavin Baker <gavinb@antonym.org>
+gentlefolk <cemacken@gmail.com>
Geoff Hill <geoff@geoffhill.org>
Geoffrey Thomas <geofft@ldpreload.com>
Geoffroy Couprie <geo.couprie@gmail.com>
+Geoffry Song <goffrie@gmail.com>
George Papanikolaou <g3orge.app@gmail.com>
Georges Dubus <georges.dubus@gmail.com>
Germano Gabbianelli <tyrion@users.noreply.github.com>
Gil Cottle <rc@redtown.org>
Gioele Barabucci <gioele@svario.it>
+github-monoculture <eocene@gmx.com>
Gleb Kozyrev <gleb@gkoz.com>
Glenn Willen <gwillen@nerdnet.org>
Gonçalo Cabrita <_@gmcabrita.com>
-Graham Fawcett <graham.fawcett@gmail.com>
Grahame Bowland <grahame@angrygoats.net>
+Graham Fawcett <graham.fawcett@gmail.com>
Graydon Hoare <graydon@pobox.com>
Greg Chapple <gregchapple1@gmail.com>
Grigoriy <ohaistarlight@gmail.com>
Guillaume Gomez <guillaume1.gomez@gmail.com>
Guillaume Pinot <texitoi@texitoi.eu>
+Gulshan Singh <gsingh2011@gmail.com>
Gyorgy Andrasek <jurily@gmail.com>
-Gábor Horváth <xazax.hun@gmail.com>
-Gábor Lehel <glaebhoerl@gmail.com>
Haitao Li <lihaitao@gmail.com>
Hajime Morrita <omo@dodgson.org>
Hanno Braun <mail@hannobraun.de>
+hansjorg <hansjorg@gmail.com>
Harry Marr <harry.marr@gmail.com>
Heather <heather@cynede.net>
-Heejong Ahn <heejongahn@gmail.com
+Hech <tryctor@gmail.com>
+Heejong Ahn <heejongahn@gmail.com>
Henrik Schopmans <h.schopmans@googlemail.com>
Herman J. Radtke III <herman@hermanradtke.com>
HeroesGrave <heroesgrave@gmail.com>
+Hika Hibariya <hibariya@gmail.com>
Hong Chulju <ang0123dev@gmail.com>
Honza Strnad <hanny.strnad@gmail.com>
Huachao Huang <huachao.huang@gmail.com>
Huon Wilson <dbau.pp+github@gmail.com>
Hyeon Kim <simnalamburt@gmail.com>
Ian Connolly <iconnolly@mozilla.com>
-Ian D. Bollinger <ian.bollinger@gmail.com>
Ian Daniher <it.daniher@gmail.com>
+Ian D. Bollinger <ian.bollinger@gmail.com>
Ignacio Corderi <icorderi@msn.com>
Igor Bukanov <igor@mir2.org>
Igor Strebezhev <xamgore@ya.ru>
Ilya Dmitrichenko <ilya@xively.com>
Ilyong Cho <ilyoan@gmail.com>
Ingo Blechschmidt <iblech@web.de>
+inrustwetrust <inrustwetrust@users.noreply.github.com>
Isaac Aggrey <isaac.aggrey@gmail.com>
Isaac Dupree <antispam@idupree.com>
+Isaac Ge <acgtyrant@gmail.com>
Ivan Enderlin <ivan.enderlin@hoa-project.net>
+Ivano Coppola <rgbfirefox@gmail.com>
Ivan Petkov <ivanppetkov@gmail.com>
Ivan Radanov Ivanov <ivanradanov@yahoo.co.uk>
Ivan Ukhov <ivan.ukhov@gmail.com>
-Ivano Coppola <rgbfirefox@gmail.com>
-J. J. Weber <jjweber@gmail.com>
-J.C. Moyer <jmoyer1992@gmail.com>
-JONNALAGADDA Srinivas <js@ojuslabs.com>
-JP Sugarbroad <jpsugar@google.com>
-JP-Ellis <coujellis@gmail.com>
+Iven Hsu <ivenvd@gmail.com>
Jack Heizer <jack.heizer@gmail.com>
Jack Moffitt <jack@metajack.im>
Jacob Edelman <edelman.jd@gmail.com>
Jaemin Moon <jaemin.moon@samsung.com>
Jag Talon <talon.jag@gmail.com>
Jake Goulding <jake.goulding@gmail.com>
+Jake Hickey <empty@cqdr.es>
Jake Kaufman <theevocater@gmail.com>
Jake Kerr <kodafox@gmail.com>
Jake Scott <jake.net@gmail.com>
Jakub Bukaj <jakub@jakub.cc>
-Jakub Wieczorek <jakubw@jakubw.net>
Jakub Vrána <jakub@vrana.cz>
+Jakub Wieczorek <jakubw@jakubw.net>
James Deng <cnjamesdeng@gmail.com>
James Hurst <jamesrhurst@users.noreply.github.com>
James Lal <james@lightsofapollo.com>
James Laverack <james@jameslaverack.com>
-James Miller <james@aatch.net>
+jamesluke <jamesluke@users.noreply.github.com>
+James Miller <bladeon@gmail.com>
+James Perry <james.austin.perry@gmail.com>
James Rowe <jroweboy@gmail.com>
James Sanders <sanderjd@gmail.com>
James Tranovich <james@openhorizonlabs.com>
+Jan Andersson <jan.andersson@gmail.com>
+Jan Bujak <j@exia.io>
+Jan-Erik Rediger <janerik@fnordig.de>
Jan Kobler <eng1@koblersystems.de>
Jan Niklas Hasse <jhasse@gmail.com>
Jannis Harder <jix@jixco.de>
+Jannis Redmann <mail@jannisr.de>
Jared Roesch <roeschinc@gmail.com>
Jarod Liu <liuyuanzhi@gmail.com>
Jashank Jeremy <jashank@rulingia.com>
Jason Orendorff <jorendorff@mozilla.com>
Jason Thompson <jason@jthompson.ca>
Jason Toffaletti <toffaletti@gmail.com>
+Jason Yeo <jasonyeo88@gmail.com>
+jatinn <jatinn@users.noreply.github.com>
Jauhien Piatlicki <jauhien@gentoo.org>
Jay Anderson <jayanderson0@gmail.com>
Jay True <glacjay@gmail.com>
+J Bailey <jj2baile@uwaterloo.ca>
+jbranchaud <jbranchaud@gmail.com>
+J.C. Moyer <jmoyer1992@gmail.com>
Jeaye <jeaye@arrownext.com>
Jed Davis <jld@panix.com>
Jed Estep <aje@jhu.edu>
Jens Nockert <jens@nockert.se>
Jeong YunWon <jeong@youknowone.org>
Jeremy Letang <letang.jeremy@gmail.com>
+Jeremy Schlatter <jeremy.schlatter@gmail.com>
Jesse Jones <jesse9jones@gmail.com>
Jesse Luehrs <doy@tozt.net>
Jesse Ray <jesse@localhost.localdomain>
Jesse Ruderman <jruderman@gmail.com>
Jessy Diamond Exum <jessy.diamondman@gmail.com>
+Jexell <Jexell@users.noreply.github.com>
Jihyeok Seo <me@limeburst.net>
Jihyun Yu <j.yu@navercorp.com>
Jim Apple <jbapple+rust@google.com>
Jim Blandy <jimb@red-bean.com>
-Jim Radford <radford@blackbean.org>
Jimmie Elvenmark <flugsio@gmail.com>
Jimmy Lu <jimmy.lu.2011@gmail.com>
Jimmy Zelinskie <jimmyzelinskie@gmail.com>
+Jim Radford <radford@blackbean.org>
Jiří Stránský <jistr@jistr.com>
+J. J. Weber <jjweber@gmail.com>
+jmgrosen <jmgrosen@gmail.com>
+jmu303 <muj@bc.edu>
João Oliveira <hello@jxs.pt>
Joe Pletcher <joepletcher@gmail.com>
Joe Schafer <joe@jschaf.com>
-Johann Hofmann <mail@johann-hofmann.com>
Johannes Hoff <johshoff@gmail.com>
Johannes Löthberg <johannes@kyriasis.com>
Johannes Muenzel <jmuenzel@gmail.com>
Johannes Oertel <johannes.oertel@uni-due.de>
+Johann Hofmann <git@johann-hofmann.com>
+Johann Tuffe <tafia973@gmail.com>
John Albietz <inthecloud247@gmail.com>
John Barker <jebarker@gmail.com>
John Clements <clements@racket-lang.org>
John Schmidt <john.schmidt.h@gmail.com>
John Simon <john@johnsoft.com>
John Talling <inrustwetrust@users.noreply.github.com>
+John Van Enk <vanenkj@gmail.com>
John Zhang <john@zhang.io>
-Jon Haddad <jon@jonhaddad.com>
-Jon Morton <jonanin@gmail.com>
+joliv <joliv@users.noreply.github.com>
Jonas Hietala <tradet.h@gmail.com>
Jonathan Bailey <jbailey@mozilla.com>
Jonathan Boyett <jonathan@failingservers.com>
Jonathan Reem <jonathan.reem@gmail.com>
Jonathan S <gereeter@gmail.com>
Jonathan Sternberg <jonathansternberg@gmail.com>
+Jon Haddad <jon@jonhaddad.com>
+Jon Morton <jonanin@gmail.com>
+JONNALAGADDA Srinivas <js@ojuslabs.com>
+jooert <jooert@users.noreply.github.com>
Joonas Javanainen <joonas.javanainen@gmail.com>
+Jordan Humphreys <mrsweaters@users.noreply.github.com>
Jordan Woehr <jordanwoehr@gmail.com>
Jordi Boggiano <j.boggiano@seld.be>
Jorge Aparicio <japaricious@gmail.com>
Josh Stone <cuviper@gmail.com>
Josh Triplett <josh@joshtriplett.org>
Joshua Clark <joshua.clark@txstate.edu>
+Joshua Landau <joshua@landau.ws>
Joshua Wise <joshua@joshuawise.com>
Joshua Yanovski <pythonesque@gmail.com>
+JP-Ellis <coujellis@gmail.com>
+JP Sugarbroad <jpsugar@google.com>
+jrincayc <jrincayc@users.noreply.github.com>
Julia Evans <julia@jvns.ca>
Julian Orth <ju.orth@gmail.com>
Julian Viereck <julian.viereck@gmail.com>
Junyoung Cho <june0.cho@samsung.com>
JustAPerson <jpriest8@ymail.com>
Justin Noah <justinnoah@gmail.com>
+juxiliary <juxiliary@gmail.com>
+jxv <joevargas@hush.com>
Jyun-Yan You <jyyou.tw@gmail.com>
Kang Seonghoon <kang.seonghoon@mearie.org>
Kasey Carrothers <kaseyc.808@gmail.com>
Kevin Rauwolf <sweetpea-git@tentacle.net>
Kevin Walter <kevin.walter.private@googlemail.com>
Kevin Yap <me@kevinyap.ca>
+kgv <mail@kgv.name>
Kiet Tran <ktt3ja@gmail.com>
Kim Røen <kim@pam.no>
+kjpgit <kjpgit@users.noreply.github.com>
+klutzy <klutzytheklutzy@gmail.com>
KokaKiwi <kokakiwi+rust@kokakiwi.net>
+korenchkin <korenchkin2@gmail.com>
Kostas Karachalios <vrinek@me.com>
+Krzysztof Drewniak <krzysdrewniak@gmail.com>
+Kubilay Kocak <koobs@users.noreply.github.com>
+kulakowski <george.kulakowski@gmail.com>
+kwantam <kwantam@gmail.com>
Kyeongwoon Lee <kyeongwoon.lee@samsung.com>
Lai Jiangshan <laijs@cn.fujitsu.com>
Lars Bergstrom <lbergstrom@mozilla.com>
Lauri Lehmijoki <lauri.lehmijoki@iki.fi>
Lawrence Velázquez <larryv@alum.mit.edu>
Leah Hanson <astrieanna@gmail.com>
+Lee Aronson <lee@libertad.ucsd.edu>
+Lee Jeffery <leejeffery@gmail.com>
Lee Wondong <wdlee91@gmail.com>
LemmingAvalanche <haugsbakk@yahoo.no>
Lennart Kudling <github@kudling.de>
-Leo Testard <leo.testard@gmail.com>
+Leo Correa <lcorr005@gmail.com>
Leonids Maslovs <leonids.maslovs@galeoconsulting.com>
+Leo Testard <leo.testard@gmail.com>
+leunggamciu <gamciuleung@gmail.com>
Liam Monahan <liam@monahan.io>
Liigo Zhuang <com.liigo@gmail.com>
Lindsey Kuper <lindsey@composition.al>
Lionel Flandrin <lionel.flandrin@parrot.com>
Logan Chien <tzuhsiang.chien@gmail.com>
Loïc Damien <loic.damien@dzamlo.ch>
+Lorenz <lorenzb@student.ethz.ch>
+lpy <pylaurent1314@gmail.com>
Luca Bruno <lucab@debian.org>
+lucy <ne.tetewi@gmail.com>
Luis de Bethencourt <luis@debethencourt.com>
+Łukasz Niemier <lukasz@niemier.pl>
Luke Francl <look@recursion.org>
Luke Gallagher <luke@hypergeometric.net>
Luke Metz <luke.metz@students.olin.edu>
Luke Steensen <luke.steensen@gmail.com>
+lummax <luogpg@googlemail.com>
Luqman Aden <me@luqman.ca>
-Łukasz Niemier <lukasz@niemier.pl>
+lyuts <dioxinu@gmail.com>
+madmalik <matthias.tellen@googlemail.com>
Magnus Auvinen <magnus.auvinen@gmail.com>
Mahmut Bulut <mahmutbulut0@gmail.com>
+maikklein <maikklein@googlemail.com>
Makoto Nakashima <makoto.nksm+github@gmail.com>
Manish Goregaokar <manishsmail@gmail.com>
Manuel Hoffmann <manuel@polythematik.de>
+marcell <marcell.pardavi@gmail.com>
+Marcel Müller <neikos@neikos.email>
Marcel Rodrigues <marcelgmr@gmail.com>
+Marcus Klaas <mail@marcusklaas.nl>
Margaret Meyerhofer <mmeyerho@andrew.cmu.edu>
Marijn Haverbeke <marijnh@gmail.com>
+Marin Atanasov Nikolov <dnaeon@gmail.com>
+Mário Feroldi <thelost-t@live.com>
Mark Lacey <641@rudkx.com>
Mark Mossberg <mark.mossberg@gmail.com>
Mark Rowe <mrowe@bdash.net.nz>
Mark Sinclair <mark.edward.x@gmail.com>
-Mark Vian <mrv.caseus@gmail.com>
Markus Siemens <siemens1993@gmail.com>
Markus Unterwaditzer <markus@unterwaditzer.net>
-Marti Raudsepp <marti@juffo.org>
+Markus Westerlind <marwes91@gmail.com>
+Mark Vian <mrv.caseus@gmail.com>
Martin DeMello <martindemello@gmail.com>
Martin Olsson <martin@minimum.se>
Martin Pool <mbp@sourcefrog.net>
+Marti Raudsepp <marti@juffo.org>
Marvin Löbel <loebel.marvin@gmail.com>
+masklinn <github.com@masklinn.net>
Matej Lach <matej.lach@gmail.com>
Mateusz Czapliński <czapkofan@gmail.com>
+Mathieu David <mathieudavid@mathieudavid.org>
Mathieu Poumeyrol <kali@zoy.org>
+Mathieu Rochette <mathieu@rochette.cc>
Mathijs van de Nes <git@mathijs.vd-nes.nl>
Matt Brubeck <mbrubeck@limpet.net>
Matt Carberry <carberry.matt@gmail.com>
Matt Coffin <mcoffin13@gmail.com>
Matt Cox <mattcoxpdx@gmail.com>
-Matt McPherrin <git@mcpherrin.ca>
-Matt Murphy <matthew.john.murphy@gmail.com>
-Matt Roche <angst7@gmail.com>
-Matt Windsor <mattwindsor@btinternet.com>
+Matthew Astley <mca@sanger.ac.uk>
Matthew Auld <matthew.auld@intel.com>
Matthew Iselin <matthew@theiselins.net>
Matthew McPherrin <matthew@mcpherrin.ca>
Matthias Einwag <matthias.einwag@live.com>
Matthijs Hofstra <thiezz@gmail.com>
Matthijs van der Vleuten <git@zr40.nl>
-Max Penet <max.penet@gmail.com>
-Maxim Kolganov <kolganov.mv@gmail.com>
+Matt McPherrin <git@mcpherrin.ca>
+Matt Murphy <matthew.john.murphy@gmail.com>
+Matt Roche <angst7@gmail.com>
+Matt Windsor <mattwindsor@btinternet.com>
+Mátyás Mustoha <mmatyas@inf.u-szeged.hu>
Maxime Quandalle <maxime@quandalle.com>
Maximilian Haack <mxhaack@gmail.com>
+Maxim Kolganov <kolganov.mv@gmail.com>
+Max Jacobson <max@hardscrabble.net>
+Max Penet <max.penet@gmail.com>
Maya Nitu <maya_nitu@yahoo.com>
+mchaput <matt@whoosh.ca>
+mdinger <mdinger.bugzilla@gmail.com>
Meyer S. Jacobs <meyermagic@gmail.com>
Micah Chalmer <micah@micahchalmer.net>
Michael Alexander <beefsack@gmail.com>
Michael Fairley <michaelfairley@gmail.com>
Michael Gehring <mg@ebfe.org>
Michael Kainer <kaini1123@gmail.com>
+Michael Layzell <michael@thelayzells.com>
Michael Letterle <michael.letterle@gmail.com>
+Michael Macias <zaeleus@gmail.com>
Michael Matuzak <mmatuzak@gmail.com>
Michael Neumann <mneumann@ntecs.de>
Michael Pankov <work@michaelpankov.com>
+Michael Park <mcypark@gmail.com>
Michael Pratt <michael@pratt.im>
Michael Reinhard <mcreinhard@users.noreply.github.com>
+Michael Rosenberg <42micro@gmail.com>
Michael Sproul <micsproul@gmail.com>
Michael Sullivan <sully@msully.net>
Michael Williams <m.t.williams@live.com>
Michael Woerister <michaelwoerister@posteo>
+Michael Wu <mwu@mozilla.com>
Michael Zhou <moz@google.com>
Michał Czardybon <mczard@poczta.onet.pl>
Michał Krasnoborski <mkrdln@gmail.com>
-Mick Koch <kchmck@gmail.com>
Mickaël Delahaye <mickael.delahaye@gmail.com>
Mickaël Raybaud-Roig <raybaudroigm@gmail.com>
Mickaël Salaün <mic@digikod.net>
+Mick Koch <kchmck@gmail.com>
Mihnea Dobrescu-Balaur <mihnea@linux.com>
Mike Boutin <mike.boutin@gmail.com>
Mike Dilger <mike@efx.co.nz>
Mike English <mike.english@atomicobject.com>
Mike Pedersen <noctune9@gmail.com>
Mike Robinson <mikeprobinsonuk@gmail.com>
+Mike Sampson <mike@sambodata.com>
Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
Mikko Perttunen <cyndis@kapsi.fi>
+mitchmindtree <mitchell.nordine@gmail.com>
+Mohammed Attia <skeuomorf@gmail.com>
+moonglum <moonglum@moonbeamlabs.com>
+mrec <mike.capp@gmail.com>
+mr.Shu <mr@shu.io>
Ms2ger <ms2ger@gmail.com>
Mukilan Thiagarajan <mukilanthiagarajan@gmail.com>
Murarth <murarth@gmail.com>
-Mátyás Mustoha <mmatyas@inf.u-szeged.hu>
-NODA, Kai <nodakai@gmail.com>
+musitdev <philippe.delrieu@free.fr>
Nafis <nhoss2@gmail.com>
+nathan dotz <nathan.dotz@gmail.com>
Nathan Froyd <froydnj@gmail.com>
+Nathaniel Herman <nherman@post.harvard.edu>
+Nathaniel Theis <nttheis@gmail.com>
+Nathan Long <nathanmlong@gmail.com>
Nathan Stoddard <nstodda@purdue.edu>
Nathan Typanski <ntypanski@gmail.com>
Nathan Wilson <wilnathan@gmail.com>
Nathan Zadoks <nathan@nathan7.eu>
-Nathaniel Herman <nherman@post.harvard.edu>
-Nathaniel Theis <nttheis@gmail.com>
Neil Pankey <npankey@gmail.com>
+Nelo Onyiah <nelo.onyiah@gmail.com>
Nelson Chen <crazysim@gmail.com>
NiccosSystem <niccossystem@gmail.com>
Nicholas Bishop <nicholasbishop@gmail.com>
Nicholas Mazzuca <npmazzuca@gmail.com>
Nick Cameron <ncameron@mozilla.com>
Nick Desaulniers <ndesaulniers@mozilla.com>
+Nick Fitzgerald <fitzgen@gmail.com>
Nick Hamann <nick@wabbo.org>
Nick Howell <howellnick@gmail.com>
-Nick Sarten <gen.battle@gmail.com>
Nick Platt <platt.nicholas@gmail.com>
+Nick Sarten <gen.battle@gmail.com>
Nicolas Silva <nical.silva@gmail.com>
Niels Egberts <git@nielsegberts.nl>
Niels langager Ellegaard <niels.ellegaard@gmail.com>
Nikita Pekin <contact@nikitapek.in>
Niklas Koep <niklas.koep@gmail.com>
Niko Matsakis <niko@alum.mit.edu>
+Nils Liberg <nils@nilsliberg.se>
+Nils Winter <nils.winter@gmail.com>
+noam <noam@clusterfoo.com>
Noam Yorav-Raphael <noamraph@gmail.com>
+NODA, Kai <nodakai@gmail.com>
Noufal Ibrahim <noufal@nibrahim.net.in>
+novalis <novalis@novalis.org>
+nsf <no.smile.face@gmail.com>
+nwin <nwin@users.noreply.github.com>
Oak <White-Oak@users.noreply.github.com>
-O S K Chaitanya <osk@medhas.org>
OGINO Masanori <masanori.ogino@gmail.com>
+OlegTsyba <idethrone1@gmail.com>
+Oliver Schneider <git1984941651981@oli-obk.de>
Oliver Schneider <github6541940@oli-obk.de>
Olivier Saut <osaut@airpost.net>
+olivren <o.renaud@gmx.fr>
Olle Jonsson <olle.jonsson@gmail.com>
+olombard <lombard-olivier@bbox.fr>
Or Brostovski <tohava@gmail.com>
-Or Neeman <oneeman@gmail.com>
Oren Hazi <oren.hazi@gmail.com>
-Orpheus Lummis <o@orpheuslummis.com>
+Or Neeman <oneeman@gmail.com>
Orphée Lafond-Lummis <o@orftz.com>
+Orpheus Lummis <o@orpheuslummis.com>
+osa1 <omeragacan@gmail.com>
+O S K Chaitanya <osk@medhas.org>
Ožbolt Menegatti <ozbolt.menegatti@gmail.com>
P1start <rewi-github@whanau.org>
Pablo Brasero <pablo@pablobm.com>
Palmer Cox <p@lmercox.com>
Paolo Falabella <paolo.falabella@gmail.com>
+Parker Moore <parkrmoore@gmail.com>
Pascal Hertleif <killercup@gmail.com>
Patrick Reisert <kpreisert@gmail.com>
Patrick Walton <pcwalton@mimiga.net>
Patrick Yevsukov <patrickyevsukov@users.noreply.github.com>
Patrik Kårlin <patrik.karlin@gmail.com>
Paul ADENOT <paul@paul.cx>
+Paul Banks <banks@banksdesigns.co.uk>
Paul Collier <paul@paulcollier.ca>
Paul Collins <paul@ondioline.org>
Paul Crowley <paulcrowley@google.com>
+Paul Faria <paul_faria@ultimatesoftware.com>
+Paul Oliver <puzza007@gmail.com>
Paul Osborne <osbpau@gmail.com>
Paul Quint <DrKwint@gmail.com>
Paul Stansifer <paul.stansifer@gmail.com>
Pawel Olzacki <p.olzacki2@samsung.com>
Pedro Larroy <pedro.larroy@here.com>
Peer Aramillo Irizar <peer.aramillo.irizar@gmail.com>
+peferron <pe.ferron@gmail.com>
+Pete Hunt <petehunt@users.noreply.github.com>
Peter Atashian <retep998@gmail.com>
-Peter Elmers <peter.elmers@rice.edu>
+Peter Elmers <peter.elmers@yahoo.com>
Peter Hull <peterhull90@gmail.com>
Peter Marheine <peter@taricorp.net>
Peter Minten <peter@pminten.nl>
Peter Williams <peter@newton.cx>
Peter Zotov <whitequark@whitequark.org>
Petter Remen <petter.remen@gmail.com>
+pez <james.austin.perry@gmail.com>
Phil Dawes <phil@phildawes.net>
-Phil Ruffwind <rf@rufflewind.com>
Philip Munksgaard <pmunksgaard@gmail.com>
Philipp Brüschweiler <blei42@gmail.com>
Philipp Gesang <phg42.2a@gmail.com>
+Phil Ruffwind <rf@rufflewind.com>
Pierre Baillet <pierre@baillet.name>
Piotr Czarnecki <pioczarn@gmail.com>
Piotr Jawniak <sawyer47@gmail.com>
Piotr Szotkowski <chastell@chastell.net>
Piotr Zolnierek <pz@anixe.pl>
Poga Po <poga.bahamut@gmail.com>
+posixphreak <posixphreak@gmail.com>
Potpourri <pot_pourri@mail.ru>
Prudhvi Krishna Surapaneni <me@prudhvi.net>
-Przemek Wesołek <jest@go.art.pl>
+Przemysław Wesołek <jest@go.art.pl>
Pyfisch <pyfisch@gmail.com>
Pyry Kontio <pyry.kontio@drasa.eu>
Q.P.Liu <qpliu@yahoo.com>
+qwitwa <qwitwa@gmail.com>
Rafael Ávila de Espíndola <respindola@mozilla.com>
Rahul Horé <hore.rahul@gmail.com>
Ralph Bodenner <rkbodenner+github@gmail.com>
Raphael Speyer <rspeyer@gmail.com>
Raul Gutierrez S <rgs@itevenworks.net>
Ray Clanan <rclanan@utopianconcept.com>
+ray glover <ray@rayglover.net>
+reedlepee <reedlepee123@gmail.com>
Reilly Watson <reillywatson@gmail.com>
+Rein Henrichs <reinh@reinh.com>
+Rémi Audebert <halfr@lse.epita.fr>
Remi Rampin <remirampin@gmail.com>
Renato Alves <alves.rjc@gmail.com>
Renato Riccieri Santos Zannon <renato@rrsz.com.br>
Reuben Morais <reuben.morais@gmail.com>
-Ricardo M. Correia <rcorreia@wizy.org>
+reus <reusee@ymail.com>
Ricardo Martins <ricardo@scarybox.net>
-Rich Lane <rlane@club.cc.cmu.edu>
+Ricardo M. Correia <rcorreia@wizy.org>
Richard Diamond <wichard@vitalitystudios.com>
+Rich Lane <rlane@club.cc.cmu.edu>
Richo Healey <richo@psych0tik.net>
Rick Waldron <waldron.rick@gmail.com>
Ricky Taylor <rickytaylor26@gmail.com>
+rjz <rj@rjzaworski.com>
Rob Arnold <robarnold@cs.cmu.edu>
-Rob Hoelz <rob@hoelz.ro>
Robert Buonpastore <robert.buonpastore@gmail.com>
Robert Clipsham <robert@octarineparrot.com>
-Robert Gawdzik <rgawdzik@hotmail.com>
Robert Foss <dev@robertfoss.se>
+Robert Gawdzik <rgawdzik@hotmail.com>
Robert Irelan <rirelan@gmail.com>
Robert Knight <robertknight@gmail.com>
Robert Millar <robert.millar@cantab.net>
+Rob Hoelz <rob@hoelz.ro>
Robin Gloster <robin@loc-com.de>
Robin Kruppe <robin.kruppe@gmail.com>
Robin Stocker <robin@nibor.org>
+Rob Young <rob.young@digital.cabinet-office.gov.uk>
Rohit Joshi <rohitjoshi@users.noreply.github.com>
Roland Tanglao <roland@rolandtanglao.com>
Rolf Timmermans <rolftimmermans@voormedia.com>
Rolf van de Krol <info@rolfvandekrol.nl>
Ron Dahlgren <ronald.dahlgren@gmail.com>
+Rory O’Kane <rory@roryokane.com>
Roy Crihfield <rscrihf@gmail.com>
Roy Frostig <rfrostig@mozilla.com>
+Rüdiger Sonderfeld <ruediger@c-plusplus.de>
+rundrop1 <rundrop1@zoho.com>
Russell Johnston <rpjohnst@gmail.com>
+Russell McClellan <russell.mcclellan@gmail.com>
Ruud van Asseldonk <dev@veniogames.com>
Ryan Levick <ryan@6wunderkinder.com>
Ryan Mulligan <ryan@ryantm.com>
Ryan Prichard <ryan.prichard@gmail.com>
Ryan Riginding <marc.riginding@gmail.com>
Ryan Scheel <ryan.havvy@gmail.com>
-Rüdiger Sonderfeld <ruediger@c-plusplus.de>
-S Pradeep Kumar <gohanpra@gmail.com>
+Ryman <haqkrs@gmail.com>
+らいどっと <ryogo.yoshimura@gmail.com>
Sae-bom Kim <sae-bom.kim@samsung.com>
Salem Talha <salem.a.talha@gmail.com>
+saml <saml@users.noreply.github.com>
Samuel Chase <samebchase@gmail.com>
Samuel Neves <sneves@dei.uc.pt>
Sander Mathijs van Veen <smvv@kompiler.org>
Sebastian N. Fernandez <cachobot@gmail.com>
Sebastian Rasmussen <sebras@gmail.com>
Sebastian Zaha <sebastian.zaha@gmail.com>
+Sébastien Chauvel <eichi237@mailoo.org>
+Sébastien Crozet <developer@crozet.re>
+Sébastien Marie <semarie@users.noreply.github.com>
Sebastien Martini <seb@dbzteam.org>
-Seo Sanghyeon <sanxiyn@gmail.com>
+Sébastien Paolacci <sebastien.paolacci@gmail.com>
Seonghyun Kim <sh8281.kim@samsung.com>
+Seo Sanghyeon <sanxiyn@gmail.com>
Sergio Benitez <sbenitez@mit.edu>
Seth Faxon <seth.faxon@gmail.com>
Seth Pink <sethpink@gmail.com>
Seth Pollack <sethpollack@users.noreply.github.com>
+sevrak <sevrak@rediffmail.com>
Shamir Khodzha <khodzha.sh@gmail.com>
+sheroze1123 <mss385@cornell.edu>
+Shmuale Mark <shm.mark@gmail.com>
SiegeLord <slabode@aim.com>
+Simonas Kazlauskas <git@kazlauskas.me>
Simon Barber-Dueck <sbarberdueck@gmail.com>
+Simon Kern <simon.kern@rwth-aachen.de>
Simon Persson <simon@flaskpost.org>
-Simon Sapin <simon.sapin@exyr.org>
+Simon Sapin <simon@exyr.org>
Simon Wollwage <mail.wollwage@gmail.com>
-Simonas Kazlauskas <git@kazlauskas.me>
+simplex <theemptystring@gmail.com>
+Sindre Johansen <sindre@sindrejohansen.no>
+sinkuu <sinkuupump@gmail.com>
+Skyler <skyler.lipthay@gmail.com>
+smenardpw <sebastien@knoglr.com>
Son <leson.phung@gmail.com>
+sp3d <sp3d@github>
+S Pradeep Kumar <gohanpra@gmail.com>
Squeaky <squeaky_pl@gmx.com>
+startling <tdixon51793@gmail.com>
Stefan Bucur <stefan.bucur@epfl.ch>
Stefan Plantikow <stefan.plantikow@googlemail.com>
Stepan Koltsov <stepan.koltsov@gmail.com>
Sterling Greene <sterling.greene@gmail.com>
+Steve Gury <steve.gury@gmail.com>
Steve Klabnik <steve@steveklabnik.com>
Steven Allen <steven@stebalien.com>
Steven Crockett <crockett.j.steven@gmail.com>
Steven Fackler <sfackler@gmail.com>
Steven Sheldon <steven@sasheldon.com>
Steven Stewart-Gallus <sstewartgallus00@langara.bc.ca>
+Steven Walter <stevenrwalter@gmail.com>
Strahinja Val Markovic <val@markovic.io>
Stuart Pernsteiner <stuart@pernsteiner.org>
Subhash Bhushan <subhash.bhushan@kaybus.com>
+sumito3478 <sumito3478@gmail.com>
+Swaroop C H <swaroop@swaroopch.com>
Sylvestre Ledru <sylvestre@debian.org>
-Sébastien Chauvel <eichi237@mailoo.org>
-Sébastien Crozet <developer@crozet.re>
-Sébastien Marie <semarie@users.noreply.github.com>
-Sébastien Paolacci <sebastien.paolacci@gmail.com>
+Tamir Duberstein <tamird@gmail.com>
Tamir Duberstein <tamird@squareup.com>
Taras Shpot <mrshpot@gmail.com>
+tav <tav@espians.com>
Taylor Hutchison <seanthutchison@gmail.com>
Ted Horst <ted.horst@earthlink.net>
Tero Hänninen <lgvz@users.noreply.github.com>
+th0114nd <th0114nd@gmail.com>
Thad Guidry <thadguidry@gmail.com>
Theo Belaire <theo.belaire@gmail.com>
+theptrk <patrick.tran06@gmail.com>
Thiago Carvalho <thiago.carvalho@westwing.de>
+thiagopnts <thiagopnts@gmail.com>
Thiago Pontes <email@thiago.me>
Thomas Backman <serenity@exscape.org>
Thomas Bracht Laumann Jespersen <laumann.thomas@gmail.com>
Thomas Daede <daede003@umn.edu>
+Thomas Jespersen <laumann.thomas@gmail.com>
+Thomas Karpiniec <tk@1.21jiggawatts.net>
Tiago Nobrega <tigarmo@gmail.com>
Tibor Benke <ihrwein@gmail.com>
Till Hoeppner <till@hoeppner.ws>
Tim Cuthbertson <tim@gfxmonk.net>
Tim Joseph Dumol <tim@timdumol.com>
Tim Kuehn <tkuehn@cmu.edu>
-Tim Parenti <timparenti@gmail.com>
-Tim Taubert <tim@timtaubert.de>
Timon Rapp <timon@zaeda.net>
Timothée Ravier <tim@siosm.fr>
+Tim Parenti <timparenti@gmail.com>
+Tim Ringenbach <tim.ringenbach@gmail.com>
+Tim Taubert <tim@timtaubert.de>
+tinaun <tinagma@gmail.com>
+Tincan <tincann@users.noreply.github.com>
+Ting-Yu Lin <aethanyc@gmail.com>
Titouan Vervack <tivervac@gmail.com>
Tobba <tobias.haegermarck@gmail.com>
Tobias Bucher <tobiasbucher5991@gmail.com>
Toby Scrace <toby.scrace@gmail.com>
Tohava <tohava@tohava-laptop.(none)>
+Tomas Sedovic <tomas@sedovic.cz>
Tom Chittenden <thchittenden@cmu.edu>
Tom Jakubowski <tom@crystae.net>
Tom Lee <github@tomlee.co>
-Tomas Sedovic <tomas@sedovic.cz>
Tommy M. McGuire <mcguire@crsr.net>
Tomoki Aonuma <uasi@99cm.org>
Toni Cárdenas <toni@tcardenas.me>
Trent Ogren <tedwardo2@gmail.com>
Trinick <slicksilver555@mac.com>
Tristan Storch <tstorch@math.uni-bielefeld.de>
+tshakah <tshakah@gmail.com>
Tshepang Lekhonkhobe <tshepang@gmail.com>
Tuncer Ayaz <tuncer.ayaz@gmail.com>
-Ty Overby <ty@pre-alpha.com>
Tycho Sci <tychosci@gmail.com>
Tyler Bindon <martica@martica.org>
Tyler Thrailkill <tylerbthrailkill@gmail.com>
+tynopex <tynopex@users.noreply.github.com>
+Ty Overby <ty@pre-alpha.com>
Ulrik Sverdrup <root@localhost>
Ulysse Carion <ulysse@ulysse.io>
User Jyyou <jyyou@plaslab.cs.nctu.edu.tw>
Victory <git@dfhu.org>
Vijay Korapaty <rust@korapaty.com>
Viktor Dahl <pazaconyoman@gmail.com>
+ville-h <ville3.14159@gmail.com>
Vincent Belliard <vincent@famillebelliard.fr>
Vinzent Steinberg <Vinzent.Steinberg@gmail.com>
Virgile Andreani <virgile.andreani@anbuco.fr>
+visualfc <visualfc@gmail.com>
Vitali Haravy <HumaneProgrammer@gmail.com>
Vivek Galatage <vivekgalatage@gmail.com>
Vladimir Matveev <vladimir.matweev@gmail.com>
Wade Mealing <wmealing@gmail.com>
Wangshan Lu <wisagan@gmail.com>
WebeWizard <webewizard@gmail.com>
+webmobster <webmobster@users.noreply.github.com>
+Wei-Ming Yang <rick68@users.noreply.github.com>
Wendell Smith <wendell.smith@yale.edu>
Wesley Wiser <wwiser@gmail.com>
-Will <will@glozer.net>
+whataloadofwhat <unusualmoniker@gmail.com>
+wickerwaka <martin.donlon@gmail.com>
+Wilfred Hughes <me@wilfred.me.uk>
+Will Andrews <will@firepipe.net>
+Will Engler <engler.will@gmail.com>
Will Hipschman <whipsch@gmail.com>
William Ting <io@williamting.com>
Willson Mock <willson.mock@gmail.com>
+Will <will@glozer.net>
+Wojciech Ogrodowczyk <github@haikuco.de>
+wonyong kim <wonyong.kim@samsung.com>
+xales <xales@naveria.com>
+Xuefeng Wu <benewu@gmail.com>
+XuefengWu <benewu@gmail.com>
+Xuefeng Wu <xfwu@thoughtworks.com>
Xue Fuqiao <xfq.free@gmail.com>
Yasuhiro Fujii <y-fujii@mimosa-pudica.net>
YawarRaza7349 <YawarRaza7349@gmail.com>
Yazhong Liu <yorkiefixer@gmail.com>
Yehuda Katz <wycats@gmail.com>
+Yongqian Li <yongqli@kerrmetric.com>
York Xiang <bombless@126.com>
Young-il Choi <duddlf.choi@samsung.com>
Youngmin Yoo <youngmin.yoo@samsung.com>
Youngsoo Son <ysson83@gmail.com>
+Young Wu <doomsplayer@gmail.com>
Yuri Albuquerque <yuridenommus@gmail.com>
Yuri Kunde Schlesner <yuriks@yuriks.net>
+Z1 <MazinZ1@users.noreply.github.com>
Zach Kamsler <smoo.master@gmail.com>
Zach Pomerantz <zmp@umich.edu>
Zack Corr <zack@z0w0.me>
Zack Slayton <zack.slayton@gmail.com>
Zbigniew Siciarz <zbigniew@siciarz.net>
Ziad Hatahet <hatahet@gmail.com>
-Zooko Wilcox-O'Hearn <zooko@zooko.com>
-arturo <arturo@openframeworks.cc>
-auREAX <mark@xn--hwg34fba.ws>
-awlnx <alecweber1994@gmail.com>
-aydin.kim <aydin.kim@samsung.com>
-bachm <Ab@vapor.com>
-bcoopers <coopersmithbrian@gmail.com>
-Anatoly Ikorsky <aikorsky@gmail.com>
-blake2-ppc <ulrik.sverdrup@gmail.com>
-bluss <bluss>
-bors <bors@rust-lang.org>
-chitra
-chromatic <chromatic@wgz.org>
-comex <comexk@gmail.com>
-crhino <piraino.chris@gmail.com>
-Daniel Ramos <dan@daramos.com>
-darkf <lw9k123@gmail.com>
-defuz <defuz.net@gmail.com>
-dgoon <dgoon@dgoon.net>
-donkopotamus <general@chocolate-fish.com>
-eliovir <eliovir@gmail.com>
-elszben <notgonna@tellyou>
-emanueLczirai <emanueLczirai@cryptoLab.net>
-fenduru <fenduru@users.noreply.github.com>
-flo-l <lacknerflo@gmail.com>
-fort <e@mail.com>
-free-Runner <aali07@students.poly.edu>
-g3xzh <g3xzh@yahoo.com>
-gamazeps <gamaz3ps@gmail.com>
-gareth <gareth@gareth-N56VM.(none)>
-gentlefolk <cemacken@gmail.com>
-github-monoculture <eocene@gmx.com>
-hansjorg <hansjorg@gmail.com>
-jamesluke <jamesluke@users.noreply.github.com>
-jatinn <jatinn@users.noreply.github.com>
-jbranchaud <jbranchaud@gmail.com>
-jmgrosen <jmgrosen@gmail.com>
-jmu303 <muj@bc.edu>
-jrincayc <jrincayc@users.noreply.github.com>
-juxiliary <juxiliary@gmail.com>
-jxv <joevargas@hush.com>
-kgv <mail@kgv.name>
-kjpgit <kjpgit@users.noreply.github.com>
-klutzy <klutzytheklutzy@gmail.com>
-korenchkin <korenchkin2@gmail.com>
-kulakowski <george.kulakowski@gmail.com>
-kwantam <kwantam@gmail.com>
-lpy <pylaurent1314@gmail.com>
-lucy <ne.tetewi@gmail.com>
-lummax <luogpg@googlemail.com>
-lyuts <dioxinu@gmail.com>
-madmalik <matthias.tellen@googlemail.com>
-maikklein <maikklein@googlemail.com>
-masklinn <github.com@masklinn.net>
-mchaput <matt@whoosh.ca>
-mdinger <mdinger.bugzilla@gmail.com>
-mitchmindtree <mitchell.nordine@gmail.com>
-moonglum <moonglum@moonbeamlabs.com>
-mr.Shu <mr@shu.io>
-mrec <mike.capp@gmail.com>
-musitdev <philippe.delrieu@free.fr>
-nathan dotz <nathan.dotz@gmail.com>
-Nils Winter <nils.winter@gmail.com>
-noam <noam@clusterfoo.com>
-novalis <novalis@novalis.org>
-nsf <no.smile.face@gmail.com>
-olivren <o.renaud@gmx.fr>
-osa1 <omeragacan@gmail.com>
-pez <james.austin.perry@gmail.com>
-posixphreak <posixphreak@gmail.com>
-qwitwa <qwitwa@gmail.com>
-ray glover <ray@rayglover.net>
-reedlepee <reedlepee123@gmail.com>
-reus <reusee@ymail.com>
-rjz <rj@rjzaworski.com>
-rundrop1 <rundrop1@zoho.com>
-sevrak <sevrak@rediffmail.com>
-sheroze1123 <mss385@cornell.edu>
-smenardpw <sebastien@knoglr.com>
-sp3d <sp3d@github>
-startling <tdixon51793@gmail.com>
-tav <tav@espians.com>
-th0114nd <th0114nd@gmail.com>
-theptrk <patrick.tran06@gmail.com>
-thiagopnts <thiagopnts@gmail.com>
-tinaun <tinagma@gmail.com>
-tshakah <tshakah@gmail.com>
-ville-h <ville3.14159@gmail.com>
-visualfc <visualfc@gmail.com>
-whataloadofwhat <unusualmoniker@gmail.com>
-wickerwaka <martin.donlon@gmail.com>
-wonyong kim <wonyong.kim@samsung.com>
-xales <xales@naveria.com>
zofrex <zofrex@gmail.com>
+Zooko Wilcox-O'Hearn <zooko@zooko.com>
克雷 <geekcraik@users.noreply.github.com>
Please make pull requests against the `master` branch.
All pull requests are reviewed by another person. We have a bot,
-@rust-highfive, that will automatically assign a random person to review your request.
+@rust-highfive, that will automatically assign a random person to review your
+request.
If you want to request that a specific person reviews your pull request,
you can add an `r?` to the message. For example, Steve usually reviews
the other rollup-eligible patches too, and they'll get tested and merged at
the same time.
+To find documentation-related issues, sort by the [A-docs label][adocs].
+
+[adocs]: https://github.com/rust-lang/rust/issues?q=is%3Aopen+is%3Aissue+label%3AA-docs
+
## Issue Triage
Sometimes, an issue will stay open, even though the bug has been fixed. And
It can be helpful to go through older bug reports and make sure that they are
still valid. Load up an older issue, double check that it's still true, and
-leave a comment letting us know if it is or is not. The [least recently updated sort][lru] is good for finding issues like this.
+leave a comment letting us know if it is or is not. The [least recently
+updated sort][lru] is good for finding issues like this.
+
+Contributors with sufficient permissions on the Rust repo can help by adding
+labels to triage issues:
+
+* Yellow, **A**-prefixed labels state which **area** of the project an issue
+ relates to.
+
+* Magenta, **B**-prefixed labels identify bugs which **belong** elsewhere.
+
+* Green, **E**-prefixed labels explain the level of **experience** necessary
+ to fix the issue.
+
+* Red, **I**-prefixed labels indicate the **importance** of the issue. The
+ [I-nominated][inom] label indicates that an issue has been nominated for
+ prioritizing at the next triage meeting.
+
+* Orange, **P**-prefixed labels indicate a bug's **priority**. These labels
+ are only assigned during triage meetings, and replace the [I-nominated][inom]
+ label.
+
+* Blue, **T**-prefixed bugs denote which **team** the issue belongs to.
+
+* Dark blue, **beta-** labels track changes which need to be backported into
+ the beta branches.
+
+* The purple **metabug** label marks lists of bugs collected by other
+ categories.
+
+If you're looking for somewhere to start, check out the [E-easy][eeasy] tag.
+[inom]: https://github.com/rust-lang/rust/issues?q=is%3Aopen+is%3Aissue+label%3AI-nominated
+[eeasy]: https://github.com/rust-lang/rust/issues?q=is%3Aopen+is%3Aissue+label%3AE-easy
[lru]: https://github.com/rust-lang/rust/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-asc
## Out-of-tree Contributions
CFG_INFO := $(info cfg: including ctags rules)
include $(CFG_SRC_DIR)mk/ctags.mk
endif
-
-# Find all of the .d files and include them to add information about
-# header file dependencies.
-ALL_DEP_FILES := $(ALL_OBJ_FILES:%.o=%.d)
--include $(ALL_DEP_FILES)
# The Rust Programming Language
-This is a compiler for Rust, including standard libraries, tools and
-documentation. Rust is a systems programming language that is fast,
-memory safe and multithreaded, but does not employ a garbage collector
-or otherwise impose significant runtime overhead.
+Rust is a fast systems programming language that guarantees
+memory safety and offers painless concurrency ([no data races]).
+It does not employ a garbage collector and has minimal runtime overhead.
+
+This repo contains the code for `rustc`, the Rust compiler, as well
+as standard libraries, tools and documentation for Rust.
+
+[no data races]: http://blog.rust-lang.org/2015/04/10/Fearless-Concurrency.html
## Quick Start
+Version 1.2.0 (August 2015)
+===========================
+
+* ~1200 changes, numerous bugfixes
+
+Highlights
+----------
+
+* [Dynamically-sized-type coercions][dst] allow smart pointer types
+ like `Rc` to contain types without a fixed size, arrays and trait
+ objects, finally enabling use of `Rc<[T]>` and completing the
+ implementation of DST.
+* [Parallel codegen][parcodegen] is now working again, which can
+ substantially speed up large builds in debug mode; It also gets
+ another ~33% speedup when bootstrapping on a 4 core machine (using 8
+ jobs). It's not enabled by default, but will be "in the near
+ future". It can be activated with the `-C codegen-units=N` flag to
+ `rustc`.
+* This is the first release with [experimental support for linking
+ with the MSVC linker and lib C on Windows (instead of using the GNU
+ variants via MinGW)][win]. It is yet recommended only for the most
+ intrepid Rusticians.
+* Benchmark compilations are showing a 30% improvement in
+ bootstrapping over 1.1.
+
+Breaking Changes
+----------------
+
+* The [`to_uppercase`] and [`to_lowercase`] methods on `char` now do
+ unicode case mapping, which is a previously-planned change in
+ behavior and considered a bugfix.
+* [`mem::align_of`] now specifies [the *minimum alignment* for
+ T][align], which is usually the alignment programs are interested
+ in, and the same value reported by clang's
+ `alignof`. [`mem::min_align_of`] is deprecated. This is not known to
+ break real code.
+* [The `#[packed]` attribute is no longer silently accepted by the
+ compiler][packed]. This attribute did nothing and code that
+ mentioned it likely did not work as intended.
+* Associated type defaults are [now behind the
+ `associated_type_defaults` feature gate][ad]. In 1.1 associated type
+ defaults *did not work*, but could be mentioned syntactically. As
+ such this breakage has minimal impact.
+
+Language
+--------
+
+* Patterns with `ref mut` now correctly invoke [`DerefMut`] when
+ matching against dereferencable values.
+
+Libraries
+---------
+
+* The [`Extend`] trait, which grows a collection from an iterator, is
+ implemented over iterators of references, for `String`, `Vec`,
+ `LinkedList`, `VecDeque`, `EnumSet`, `BinaryHeap`, `VecMap`,
+ `BTreeSet` and `BTreeMap`. [RFC][extend-rfc].
+* The [`iter::once`] function returns an iterator that yields a single
+ element, and [`iter::empty`] returns an iterator that yields no
+ elements.
+* The [`matches`] and [`rmatches`] methods on `str` return iterators
+ over substring matches.
+* [`Cell`] and [`RefCell`] both implement `Eq`.
+* A number of methods for wrapping arithmetic are added to the
+ integral types, [`wrapping_div`], [`wrapping_rem`],
+ [`wrapping_neg`], [`wrapping_shl`], [`wrapping_shr`]. These are in
+ addition to the existing [`wrapping_add`], [`wrapping_sub`], and
+ [`wrapping_mul`] methods, and alternatives to the [`Wrapping`]
+ type.. It is illegal for the default arithmetic operations in Rust
+ to overflow; the desire to wrap must be explicit.
+* The `{:#?}` formatting specifier [displays the alternate,
+ pretty-printed][debugfmt] form of the `Debug` formatter. This
+ feature was actually introduced prior to 1.0 with little
+ fanfare.
+* [`fmt::Formatter`] implements [`fmt::Write`], a `fmt`-specific trait
+ for writing data to formatted strings, similar to [`io::Write`].
+* [`fmt::Formatter`] adds 'debug builder' methods, [`debug_struct`],
+ [`debug_tuple`], [`debug_list`], [`debug_set`], [`debug_map`]. These
+ are used by code generators to emit implementations of [`Debug`].
+* `str` has new [`to_uppercase`][strup] and [`to_lowercase`][strlow]
+ methods that convert case, following Unicode case mapping.
+* It is now easier to handle poisoned locks. The [`PoisonError`]
+ type, returned by failing lock operations, exposes `into_inner`,
+ `get_ref`, and `get_mut`, which all give access to the inner lock
+ guard, and allow the poisoned lock to continue to operate. The
+ `is_poisoned` method of [`RwLock`] and [`Mutex`] can poll for a
+ poisoned lock without attempting to take the lock.
+* On Unix the [`FromRawFd`] trait is implemented for [`Stdio`], and
+ [`AsRawFd`] for [`ChildStdin`], [`ChildStdout`], [`ChildStderr`].
+ On Windows the `FromRawHandle` trait is implemented for `Stdio`,
+ and `AsRawHandle` for `ChildStdin`, `ChildStdout`,
+ `ChildStderr`.
+* [`io::ErrorKind`] has a new variant, `InvalidData`, which indicates
+ malformed input.
+
+Misc
+----
+
+* `rustc` employs smarter heuristics for guessing at [typos].
+* `rustc` emits more efficient code for [no-op conversions between
+ unsafe pointers][nop].
+* Fat pointers are now [passed in pairs of immediate arguments][fat],
+ resulting in faster compile times and smaller code.
+
+[`Extend`]: http://doc.rust-lang.org/nightly/std/iter/trait.Extend.html
+[extend-rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0839-embrace-extend-extinguish.md
+[`iter::once`]: http://doc.rust-lang.org/nightly/std/iter/fn.once.html
+[`iter::empty`]: http://doc.rust-lang.org/nightly/std/iter/fn.empty.html
+[`matches`]: http://doc.rust-lang.org/nightly/std/primitive.str.html#method.matches
+[`rmatches`]: http://doc.rust-lang.org/nightly/std/primitive.str.html#method.rmatches
+[`Cell`]: http://doc.rust-lang.org/nightly/std/cell/struct.Cell.html
+[`RefCell`]: http://doc.rust-lang.org/nightly/std/cell/struct.RefCell.html
+[`wrapping_add`]: http://doc.rust-lang.org/nightly/std/primitive.i8.html#method.wrapping_add
+[`wrapping_sub`]: http://doc.rust-lang.org/nightly/std/primitive.i8.html#method.wrapping_sub
+[`wrapping_mul`]: http://doc.rust-lang.org/nightly/std/primitive.i8.html#method.wrapping_mul
+[`wrapping_div`]: http://doc.rust-lang.org/nightly/std/primitive.i8.html#method.wrapping_div
+[`wrapping_rem`]: http://doc.rust-lang.org/nightly/std/primitive.i8.html#method.wrapping_rem
+[`wrapping_neg`]: http://doc.rust-lang.org/nightly/std/primitive.i8.html#method.wrapping_neg
+[`wrapping_shl`]: http://doc.rust-lang.org/nightly/std/primitive.i8.html#method.wrapping_shl
+[`wrapping_shr`]: http://doc.rust-lang.org/nightly/std/primitive.i8.html#method.wrapping_shr
+[`Wrapping`]: http://doc.rust-lang.org/nightly/std/num/struct.Wrapping.html
+[`fmt::Formatter`]: http://doc.rust-lang.org/nightly/std/fmt/struct.Formatter.html
+[`fmt::Write`]: http://doc.rust-lang.org/nightly/std/fmt/trait.Write.html
+[`io::Write`]: http://doc.rust-lang.org/nightly/std/io/trait.Write.html
+[`debug_struct`]: http://doc.rust-lang.org/nightly/core/fmt/struct.Formatter.html#method.debug_struct
+[`debug_tuple`]: http://doc.rust-lang.org/nightly/core/fmt/struct.Formatter.html#method.debug_tuple
+[`debug_list`]: http://doc.rust-lang.org/nightly/core/fmt/struct.Formatter.html#method.debug_list
+[`debug_set`]: http://doc.rust-lang.org/nightly/core/fmt/struct.Formatter.html#method.debug_set
+[`debug_map`]: http://doc.rust-lang.org/nightly/core/fmt/struct.Formatter.html#method.debug_map
+[`Debug`]: http://doc.rust-lang.org/nightly/std/fmt/trait.Debug.html
+[strup]: http://doc.rust-lang.org/nightly/std/primitive.str.html#method.to_uppercase
+[strlow]: http://doc.rust-lang.org/nightly/std/primitive.str.html#method.to_lowercase
+[`to_uppercase`]: http://doc.rust-lang.org/nightly/std/primitive.char.html#method.to_uppercase
+[`to_lowercase`]: http://doc.rust-lang.org/nightly/std/primitive.char.html#method.to_lowercase
+[`PoisonError`]: http://doc.rust-lang.org/nightly/std/sync/struct.PoisonError.html
+[`RwLock`]: http://doc.rust-lang.org/nightly/std/sync/struct.RwLock.html
+[`Mutex`]: http://doc.rust-lang.org/nightly/std/sync/struct.Mutex.html
+[`FromRawFd`]: http://doc.rust-lang.org/nightly/std/os/unix/io/trait.FromRawFd.html
+[`AsRawFd`]: http://doc.rust-lang.org/nightly/std/os/unix/io/trait.AsRawFd.html
+[`Stdio`]: http://doc.rust-lang.org/nightly/std/process/struct.Stdio.html
+[`ChildStdin`]: http://doc.rust-lang.org/nightly/std/process/struct.ChildStdin.html
+[`ChildStdout`]: http://doc.rust-lang.org/nightly/std/process/struct.ChildStdout.html
+[`ChildStderr`]: http://doc.rust-lang.org/nightly/std/process/struct.ChildStderr.html
+[`io::ErrorKind`]: http://doc.rust-lang.org/nightly/std/io/enum.ErrorKind.html
+[debugfmt]: https://www.reddit.com/r/rust/comments/3ceaui/psa_produces_prettyprinted_debug_output/
+[`DerefMut`]: http://doc.rust-lang.org/nightly/std/ops/trait.DerefMut.html
+[`mem::align_of`]: http://doc.rust-lang.org/nightly/std/mem/fn.align_of.html
+[align]: https://github.com/rust-lang/rust/pull/25646
+[`mem::min_align_of`]: http://doc.rust-lang.org/nightly/std/mem/fn.min_align_of.html
+[typos]: https://github.com/rust-lang/rust/pull/26087
+[nop]: https://github.com/rust-lang/rust/pull/26336
+[fat]: https://github.com/rust-lang/rust/pull/26411
+[dst]: https://github.com/rust-lang/rfcs/blob/master/text/0982-dst-coercion.md
+[parcodegen]: https://github.com/rust-lang/rust/pull/26018
+[packed]: https://github.com/rust-lang/rust/pull/25541
+[ad]: https://github.com/rust-lang/rust/pull/27382
+[win]: https://github.com/rust-lang/rust/pull/25350
+
Version 1.1.0 (June 2015)
=========================
* Several [restrictions have been added to trait coherence][coh] in
order to make it easier for upstream authors to change traits
- without breaking downsteam code.
+ without breaking downstream code.
* Digits of binary and octal literals are [lexed more eagerly][lex] to
improve error messages and macro behavior. For example, `0b1234` is
now lexed as `0b1234` instead of two tokens, `0b1` and `234`.
-* Trait bounds [are always invariant][inv], eleminating the need for
+* Trait bounds [are always invariant][inv], eliminating the need for
the `PhantomFn` and `MarkerTrait` lang items, which have been
removed.
* ["-" is no longer a valid character in crate names][cr], the `extern crate
Version 1.0.0-alpha.2 (February 2015)
--------------------------------------
+=====================================
* ~1300 changes, numerous bugfixes
* Highlights
* The various I/O modules were [overhauled][io-rfc] to reduce
- unncessary abstractions and provide better interoperation with
+ unnecessary abstractions and provide better interoperation with
the underlying platform. The old `io` module remains temporarily
at `std::old_io`.
- * The standard library now [partipates in feature gating][feat],
+ * The standard library now [participates in feature gating][feat],
so use of unstable libraries now requires a `#![feature(...)]`
attribute. The impact of this change is [described on the
forum][feat-forum]. [RFC][feat-rfc].
[ufcs-rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0132-ufcs.md
[un]: https://github.com/rust-lang/rust/pull/22256
+
Version 1.0.0-alpha (January 2015)
-----------------------------------
+==================================
* ~2400 changes, numerous bugfixes
syscall when available.
* The 'serialize' crate has been renamed 'rustc-serialize' and
moved out of the distribution to Cargo. Although it is widely
- used now, it is expected to be superceded in the near future.
+ used now, it is expected to be superseded in the near future.
* The `Show` formatter, typically implemented with
`#[derive(Show)]` is [now requested with the `{:?}`
specifier][show] and is intended for use by all types, for uses
[trpl]: http://doc.rust-lang.org/book/index.html
[rbe]: http://rustbyexample.com/
+
Version 0.12.0 (October 2014)
------------------------------
+=============================
* ~1900 changes, numerous bugfixes
* Official Rust binaries on Linux are more compatible with older
kernels and distributions, built on CentOS 5.10.
+
Version 0.11.0 (July 2014)
--------------------------
+==========================
* ~1700 changes, numerous bugfixes
* Error message related to non-exhaustive match expressions have been
greatly improved.
+
Version 0.10 (April 2014)
--------------------------
+=========================
* ~1500 changes, numerous bugfixes
* search works across crates that have been rendered to the same output
directory.
+
Version 0.9 (January 2014)
---------------------------
+==========================
* ~1800 changes, numerous bugfixes
* `rustc` adds a `--dep-info` flag for communicating dependencies to
build tools.
+
Version 0.8 (September 2013)
---------------------------
+============================
* ~2200 changes, numerous bugfixes
* A new documentation backend, rustdoc_ng, is available for use. It is
still invoked through the normal `rustdoc` command.
+
Version 0.7 (July 2013)
------------------------
+=======================
* ~2000 changes, numerous bugfixes
* Various improvements to rustdoc.
* Improvements to rustpkg (see the detailed release notes).
+
Version 0.6 (April 2013)
-------------------------
+========================
* ~2100 changes, numerous bugfixes
* Rust code may be embedded in foreign code under limited circumstances
* Inline assembler supported by new asm!() syntax extension.
+
Version 0.5 (December 2012)
----------------------------
+===========================
* ~900 changes, numerous bugfixes
* Added a preliminary REPL, `rusti`
* License changed from MIT to dual MIT/APL2
+
Version 0.4 (October 2012)
---------------------------
+==========================
* ~2000 changes, numerous bugfixes
Rust-based (visitor) code
* All hash functions and tables converted to secure, randomized SipHash
+
Version 0.3 (July 2012)
-------------------------
+========================
* ~1900 changes, numerous bugfixes
* Tool improvements
* Cargo automatically resolves dependencies
+
Version 0.2 (March 2012)
--------------------------
+=========================
* >1500 changes, numerous bugfixes
* Merged per-platform std::{os*, fs*} to core::{libc, os}
* Extensive cleanup, regularization in libstd, libcore
+
Version 0.1 (January 20, 2012)
--------------------------------
+===============================
* Most language features work, including:
* Unique pointers, unique closures, move semantics
#!/bin/sh
msg() {
- echo "configure: $1"
+ echo "configure: $*"
}
step_msg() {
need_cmd() {
if command -v $1 >/dev/null 2>&1
- then msg "found program $1"
- else err "need program $1"
+ then msg "found program '$1'"
+ else err "program '$1' is missing, please install it"
fi
}
DEFAULT_BUILD="${CFG_CPUTYPE}-${CFG_OSTYPE}"
CFG_SRC_DIR="$(abs_path $(dirname $0))/"
+CFG_SRC_DIR_RELATIVE="$(dirname $0)/"
CFG_BUILD_DIR="$(pwd)/"
CFG_SELF="$0"
CFG_CONFIGURE_ARGS="$@"
# This is used by the automation to produce single-target nightlies
opt dist-host-only 0 "only install bins for the host architecture"
opt inject-std-version 1 "inject the current compiler version of libstd into programs"
-opt llvm-version-check 1 "don't check if the LLVM version is supported, build anyway"
+opt llvm-version-check 1 "check if the LLVM version is supported, build anyway"
# Optimization and debugging options. These may be overridden by the release channel, etc.
opt_nosave optimize 1 "build optimized rust code"
valopt datadir "${CFG_PREFIX}/share" "install data"
valopt infodir "${CFG_PREFIX}/share/info" "install additional info"
valopt llvm-root "" "set LLVM root"
+valopt python "" "set path to python"
valopt jemalloc-root "" "set directory where libjemalloc_pic.a is located"
valopt build "${DEFAULT_BUILD}" "GNUs ./configure syntax LLVM build triple"
valopt android-cross-path "/opt/ndk_standalone" "Android NDK standalone path"
# there's no rpath. This is where the build system itself puts libraries;
# --libdir is used to configure the installation directory.
# FIXME: This needs to parameterized over target triples. Do it in platform.mk
-if [ "$CFG_OSTYPE" = "pc-windows-gnu" ]
+if [ "$CFG_OSTYPE" = "pc-windows-gnu" ] || [ "$CFG_OSTYPE" = "pc-windows-msvc" ]
then
CFG_LIBDIR_RELATIVE=bin
else
CFG_LIBDIR_RELATIVE=`echo ${CFG_LIBDIR} | cut -c$((${#CFG_PREFIX}+${CAT_INC}))-`
-if [ "$CFG_OSTYPE" = "pc-windows-gnu" ] && [ "$CFG_LIBDIR_RELATIVE" != "bin" ]; then
+if ( [ "$CFG_OSTYPE" = "pc-windows-gnu" ] || [ "$CFG_OSTYPE" = "pc-windows-msvc" ] ) \
+ && [ "$CFG_LIBDIR_RELATIVE" != "bin" ]; then
err "libdir on windows should be set to 'bin'"
fi
step_msg "looking for build programs"
probe_need CFG_CURLORWGET curl wget
-probe_need CFG_PYTHON python2.7 python2.6 python2 python
+if [ -z "$CFG_PYTHON_PROVIDED" ]; then
+ probe_need CFG_PYTHON python2.7 python2.6 python2 python
+fi
python_version=$($CFG_PYTHON -V 2>&1)
if [ $(echo $python_version | grep -c '^Python 2\.[4567]') -ne 1 ]; then
probe CFG_MD5SUM md5sum
if [ -n "$CFG_MD5" ]
then
- CFG_HASH_COMMAND="$CFG_MD5 -q | head -c 8"
+ CFG_HASH_COMMAND="$CFG_MD5 -q | cut -c 1-8"
elif [ -n "$CFG_MD5SUM" ]
then
- CFG_HASH_COMMAND="$CFG_MD5SUM | head -c 8"
+ CFG_HASH_COMMAND="$CFG_MD5SUM | cut -c 1-8"
else
err 'could not find one of: md5 md5sum'
fi
fi
BIN_SUF=
-if [ "$CFG_OSTYPE" = "pc-windows-gnu" ]
+if [ "$CFG_OSTYPE" = "pc-windows-gnu" ] || [ "$CFG_OSTYPE" = "pc-windows-msvc" ]
then
BIN_SUF=.exe
fi
putvar CFG_LOCAL_RUST_ROOT
fi
-# Force freebsd to build with clang; gcc doesn't like us there
-if [ $CFG_OSTYPE = unknown-freebsd ]
-then
- step_msg "on FreeBSD, forcing use of clang"
- CFG_ENABLE_CLANG=1
-fi
-
# Force bitrig to build with clang; gcc doesn't like us there
if [ $CFG_OSTYPE = unknown-bitrig ]
then
CFG_DISABLE_JEMALLOC=1
fi
-if [ -z "$CFG_ENABLE_CLANG" -a -z "$CFG_GCC" ]
-then
- err "either clang or gcc is required"
-fi
-
# OS X 10.9, gcc is actually clang. This can cause some confusion in the build
# system, so if we find that gcc is clang, we should just use clang directly.
if [ $CFG_OSTYPE = apple-darwin -a -z "$CFG_ENABLE_CLANG" ]
if [ ! -z "$CFG_ENABLE_CLANG" ]
then
- if [ -z "$CC" ] || [[ $CC == *clang ]]
- then
- CFG_CLANG_VERSION=$($CFG_CC \
- --version \
- | grep version \
- | sed 's/.*\(version .*\)/\1/; s/.*based on \(LLVM .*\))/\1/' \
- | cut -d ' ' -f 2)
-
- case $CFG_CLANG_VERSION in
- (3.2* | 3.3* | 3.4* | 3.5* | 3.6*)
- step_msg "found ok version of CLANG: $CFG_CLANG_VERSION"
- if [ -z "$CC" ]
- then
- CFG_CC="clang"
- CFG_CXX="clang++"
- fi
- ;;
- (*)
- err "bad CLANG version: $CFG_CLANG_VERSION, need >=3.0svn"
- ;;
- esac
- else
- msg "skipping CFG_ENABLE_CLANG version check; provided CC=$CC"
- fi
+ case "$CC" in
+ (''|*clang)
+ CFG_CLANG_REPORTED_VERSION=$($CFG_CC --version | grep version)
+
+ if [[ $CFG_CLANG_REPORTED_VERSION == *"(based on LLVM "* ]]
+ then
+ CFG_CLANG_VERSION=$(echo $CFG_CLANG_REPORTED_VERSION | sed 's/.*(based on LLVM \(.*\))/\1/')
+ elif [[ $CFG_CLANG_REPORTED_VERSION == "Apple LLVM"* ]]
+ then
+ CFG_OSX_CLANG_VERSION=$(echo $CFG_CLANG_REPORTED_VERSION | sed 's/.*version \(.*\) .*/\1/')
+ else
+ CFG_CLANG_VERSION=$(echo $CFG_CLANG_REPORTED_VERSION | sed 's/.*version \(.*\) .*/\1/')
+ fi
+
+ if [ ! -z "$CFG_OSX_CLANG_VERSION" ]
+ then
+ case $CFG_OSX_CLANG_VERSION in
+ (7.0*)
+ step_msg "found ok version of APPLE CLANG: $CFG_OSX_CLANG_VERSION"
+ ;;
+ (*)
+ err "bad APPLE CLANG version: $CFG_OSX_CLANG_VERSION, need >=7.0"
+ ;;
+ esac
+ else
+ case $CFG_CLANG_VERSION in
+ (3.2* | 3.3* | 3.4* | 3.5* | 3.6* | 3.7*)
+ step_msg "found ok version of CLANG: $CFG_CLANG_VERSION"
+ ;;
+ (*)
+ err "bad CLANG version: $CFG_CLANG_VERSION, need >=3.0svn"
+ ;;
+ esac
+ fi
+
+ if [ -z "$CC" ]
+ then
+ CFG_CC="clang"
+ CFG_CXX="clang++"
+ fi
+ esac
fi
if [ ! -z "$CFG_ENABLE_CCACHE" ]
err "musl libc $CFG_MUSL_ROOT/lib/libc.a not found"
fi
;;
+
+ x86_64-*-msvc)
+ # Currently the build system is not configured to build jemalloc
+ # with MSVC, so we omit this optional dependency.
+ step_msg "targeting MSVC, disabling jemalloc"
+ CFG_DISABLE_JEMALLOC=1
+ putvar CFG_DISABLE_JEMALLOC
+
+ # There are some MSYS python builds which will auto-translate
+ # windows-style paths to MSYS-style paths in Python itself.
+ # Unfortunately this breaks LLVM's build system as somewhere along
+ # the line LLVM prints a path into a file from Python and then CMake
+ # later tries to interpret that path. If Python prints a MSYS path
+ # and CMake tries to use it as a Windows path, you're gonna have a
+ # Bad Time.
+ #
+ # Consequently here we try to detect when that happens and print an
+ # error if it does.
+ if $CFG_PYTHON -c 'import sys; print sys.argv[1]' `pwd` | grep '^/'
+ then
+ err "python is silently translating windows paths to MSYS paths \
+ and the build will fail if this python is used.\n\n \
+ Either an official python install must be used or an \
+ alternative python package in MinGW must be used."
+ fi
+
+ # MSVC requires cmake because that's how we're going to build LLVM
+ probe_need CFG_CMAKE cmake
+
+ # Use the REG program to figure out where VS is installed
+ # We need to figure out where cl.exe and link.exe are, so we do some
+ # munging and some probing here. We also look for the default
+ # INCLUDE and LIB variables for MSVC so we can set those in the
+ # build system as well.
+ install=$(reg QUERY \
+ 'HKLM\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\12.0' \
+ -v InstallDir)
+ need_ok "couldn't find visual studio install root"
+ CFG_MSVC_ROOT=$(echo "$install" | grep InstallDir | sed 's/.*REG_SZ[ ]*//')
+ CFG_MSVC_ROOT=$(dirname "$CFG_MSVC_ROOT")
+ CFG_MSVC_ROOT=$(dirname "$CFG_MSVC_ROOT")
+ CFG_MSVC_CL="${CFG_MSVC_ROOT}/VC/bin/amd64/cl.exe"
+ CFG_MSVC_LIB="${CFG_MSVC_ROOT}/VC/bin/amd64/lib.exe"
+ CFG_MSVC_LINK="${CFG_MSVC_ROOT}/VC/bin/amd64/link.exe"
+
+ vcvarsall="${CFG_MSVC_ROOT}/VC/vcvarsall.bat"
+ CFG_MSVC_INCLUDE_PATH=$(cmd /c "\"$vcvarsall\" amd64 && cmd /c echo %INCLUDE%")
+ need_ok "failed to learn about MSVC's INCLUDE"
+ CFG_MSVC_LIB_PATH=$(cmd /c "\"$vcvarsall\" amd64 && cmd /c echo %LIB%")
+ need_ok "failed to learn about MSVC's LIB"
+
+ putvar CFG_MSVC_ROOT
+ putvar CFG_MSVC_CL
+ putvar CFG_MSVC_LIB
+ putvar CFG_MSVC_LINK
+ putvar CFG_MSVC_INCLUDE_PATH
+ putvar CFG_MSVC_LIB_PATH
+ ;;
+
*)
;;
esac
do
make_dir $t/rt/stage$s
make_dir $t/rt/jemalloc
+ make_dir $t/rt/compiler-rt
for i in \
isaac sync test \
arch/i386 arch/x86_64 arch/arm arch/aarch64 arch/mips arch/powerpc
for t in $CFG_HOST
do
do_reconfigure=1
+ is_msvc=0
+ case "$t" in
+ (*-msvc)
+ is_msvc=1
+ ;;
+ esac
if [ -z $CFG_LLVM_ROOT ]
then
LLVM_ASSERTION_OPTS="--disable-assertions"
else
LLVM_ASSERTION_OPTS="--enable-assertions"
- LLVM_INST_DIR=${LLVM_INST_DIR}+Asserts
+
+ # Apparently even if we request assertions be enabled for MSVC,
+ # LLVM's CMake build system ignore this and outputs in `Release`
+ # anyway.
+ if [ ${is_msvc} -eq 0 ]; then
+ LLVM_INST_DIR=${LLVM_INST_DIR}+Asserts
+ fi
fi
else
msg "not reconfiguring LLVM, external LLVM root"
done
fi
- if [ ${do_reconfigure} -ne 0 ]
+ if [ ${do_reconfigure} -ne 0 ] && [ ${is_msvc} -ne 0 ]
+ then
+ msg "configuring LLVM for $t with cmake"
+
+ CMAKE_ARGS="-DLLVM_INCLUDE_TESTS=OFF"
+ if [ ! -z "$CFG_DISABLE_OPTIMIZE_LLVM" ]; then
+ CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_BUILD_TYPE=Debug"
+ else
+ CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_BUILD_TYPE=Release"
+ fi
+ if [ -z "$CFG_ENABLE_LLVM_ASSERTIONS" ]
+ then
+ CMAKE_ARGS="$CMAKE_ARGS -DLLVM_ENABLE_ASSERTIONS=OFF"
+ else
+ CMAKE_ARGS="$CMAKE_ARGS -DLLVM_ENABLE_ASSERTIONS=ON"
+ fi
+
+ msg "configuring LLVM with:"
+ msg "$CMAKE_ARGS"
+ (cd $LLVM_BUILD_DIR && "$CFG_CMAKE" $CFG_LLVM_SRC_DIR \
+ -G "Visual Studio 12 2013 Win64" \
+ $CMAKE_ARGS)
+ need_ok "LLVM cmake configure failed"
+ fi
+
+ if [ ${do_reconfigure} -ne 0 ] && [ ${is_msvc} -eq 0 ]
then
# LLVM's configure doesn't recognize the new Windows triples yet
gnu_t=$(to_gnu_triple $t)
# (llvm's configure tries to find pthread first, so we have to disable it explicitly.)
# Also note that pthreads works badly on mingw-w64 systems: #8996
case "$CFG_BUILD" in
- (*-windows-*)
+ (*-windows-gnu)
LLVM_OPTS="$LLVM_OPTS --disable-pthreads"
;;
esac
step_msg "writing configuration"
putvar CFG_SRC_DIR
+putvar CFG_SRC_DIR_RELATIVE
putvar CFG_BUILD_DIR
putvar CFG_OSTYPE
putvar CFG_CPUTYPE
putvar $CFG_LLVM_INST_DIR
done
-# Munge any paths that appear in config.mk back to posix-y
-cp config.tmp config.tmp.bak
-sed -e 's@ \([a-zA-Z]\):[/\\]@ /\1/@g;' <config.tmp.bak >config.tmp
-rm -f config.tmp.bak
-
msg
copy_if_changed ${CFG_SRC_DIR}Makefile.in ./Makefile
move_if_changed config.tmp config.mk
-.TH RUSTC "1" "June 2015" "rustc 1.1.0" "User Commands"
+.TH RUSTC "1" "August 2015" "rustc 1.2.0" "User Commands"
.SH NAME
rustc \- The Rust compiler
.SH SYNOPSIS
-.TH RUSTDOC "1" "June 2015" "rustdoc 1.1.0" "User Commands"
+.TH RUSTDOC "1" "August 2015" "rustdoc 1.2.0" "User Commands"
.SH NAME
rustdoc \- generate documentation from Rust source code
.SH SYNOPSIS
CFG_IOS_SDK_aarch64-apple-ios := $(shell xcrun --show-sdk-path -sdk iphoneos 2>/dev/null)
CFG_IOS_SDK_FLAGS_aarch64-apple-ios := -target aarch64-apple-darwin -isysroot $(CFG_IOS_SDK_aarch64-apple-ios) -mios-version-min=7.0 -arch arm64
CC_aarch64-apple-ios = $(shell xcrun -find -sdk iphoneos clang)
+LINK_aarch64-apple-ios = $(shell xcrun -find -sdk iphoneos clang)
CXX_aarch64-apple-ios = $(shell xcrun -find -sdk iphoneos clang++)
CPP_aarch64-apple-ios = $(shell xcrun -find -sdk iphoneos clang++)
AR_aarch64-apple-ios = $(shell xcrun -find -sdk iphoneos ar)
--- /dev/null
+# x86_64-pc-windows-msvc configuration
+CC_x86_64-pc-windows-msvc="$(CFG_MSVC_CL)" -nologo
+LINK_x86_64-pc-windows-msvc="$(CFG_MSVC_LINK)" -nologo
+CXX_x86_64-pc-windows-msvc="$(CFG_MSVC_CL)" -nologo
+CPP_x86_64-pc-windows-msvc="$(CFG_MSVC_CL)" -nologo
+AR_x86_64-pc-windows-msvc="$(CFG_MSVC_LIB)" -nologo
+CFG_LIB_NAME_x86_64-pc-windows-msvc=$(1).dll
+CFG_STATIC_LIB_NAME_x86_64-pc-windows-msvc=$(1).lib
+CFG_LIB_GLOB_x86_64-pc-windows-msvc=$(1)-*.{dll,lib}
+CFG_LIB_DSYM_GLOB_x86_64-pc-windows-msvc=$(1)-*.dylib.dSYM
+CFG_JEMALLOC_CFLAGS_x86_64-pc-windows-msvc :=
+CFG_GCCISH_CFLAGS_x86_64-pc-windows-msvc := -MD
+CFG_GCCISH_CXXFLAGS_x86_64-pc-windows-msvc := -MD
+CFG_GCCISH_LINK_FLAGS_x86_64-pc-windows-msvc :=
+CFG_GCCISH_DEF_FLAG_x86_64-pc-windows-msvc :=
+CFG_LLC_FLAGS_x86_64-pc-windows-msvc :=
+CFG_INSTALL_NAME_x86_64-pc-windows-msvc =
+CFG_EXE_SUFFIX_x86_64-pc-windows-msvc := .exe
+CFG_WINDOWSY_x86_64-pc-windows-msvc := 1
+CFG_UNIXY_x86_64-pc-windows-msvc :=
+CFG_LDPATH_x86_64-pc-windows-msvc :=
+CFG_RUN_x86_64-pc-windows-msvc=$(2)
+CFG_RUN_TARG_x86_64-pc-windows-msvc=$(call CFG_RUN_x86_64-pc-windows-msvc,,$(2))
+CFG_GNU_TRIPLE_x86_64-pc-windows-msvc := x86_64-pc-win32
+
+# These two environment variables are scraped by the `./configure` script and
+# are necessary for `cl.exe` to find standard headers (the INCLUDE variable) and
+# for `link.exe` to find standard libraries (the LIB variable).
+ifdef CFG_MSVC_INCLUDE_PATH
+export INCLUDE := $(CFG_MSVC_INCLUDE_PATH)
+endif
+ifdef CFG_MSVC_LIB_PATH
+export LIB := $(CFG_MSVC_LIB_PATH)
+endif
+
+# Unfortunately `link.exe` is also a program in `/usr/bin` on MinGW installs,
+# but it's not the one that we want. As a result we make sure that our detected
+# `link.exe` shows up in PATH first.
+ifdef CFG_MSVC_LINK
+export PATH := $(CFG_MSVC_ROOT)/VC/bin/amd64:$(PATH)
+endif
+
+# There are more comments about this available in the target specification for
+# Windows MSVC in the compiler, but the gist of it is that we use `llvm-ar.exe`
+# instead of `lib.exe` for assembling archives, so we need to inject this custom
+# dependency here.
+NATIVE_TOOL_DEPS_core_T_x86_64-pc-windows-msvc += llvm-ar.exe
+INSTALLED_BINS_x86_64-pc-windows-msvc += llvm-ar.exe
+
+# When working with MSVC on windows, each DLL needs to explicitly declare its
+# interface to the outside world through some means. The options for doing so
+# include:
+#
+# 1. A custom attribute on each function itself
+# 2. A linker argument saying what to export
+# 3. A file which lists all symbols that need to be exported
+#
+# The Rust compiler takes care (1) for us for all Rust code by annotating all
+# public-facing functions with dllexport, but we have a few native dependencies
+# which need to cross the DLL boundary. The most important of these dependencies
+# is LLVM which is linked into `rustc_llvm.dll` but primarily used from
+# `rustc_trans.dll`. This means that many of LLVM's C API functions need to be
+# exposed from `rustc_llvm.dll` to be forwarded over the boundary.
+#
+# Unfortunately, at this time, LLVM does not handle this sort of exportation on
+# Windows for us, so we're forced to do it ourselves if we want it (which seems
+# like the path of least resistance right now). To do this we generate a `.DEF`
+# file [1] which we then custom-pass to the linker when building the rustc_llvm
+# crate. This DEF file list all symbols that are exported from
+# `src/librustc_llvm/lib.rs` and is generated by a small python script.
+#
+# Fun times!
+#
+# [1]: https://msdn.microsoft.com/en-us/library/28d6s79h.aspx
+RUSTFLAGS_rustc_llvm_T_x86_64-pc-windows-msvc += \
+ -C link-args="-DEF:x86_64-pc-windows-msvc/rt/rustc_llvm.def"
+CUSTOM_DEPS_rustc_llvm_T_x86_64-pc-windows-msvc += \
+ x86_64-pc-windows-msvc/rt/rustc_llvm.def
+
+x86_64-pc-windows-msvc/rt/rustc_llvm.def: $(S)src/etc/mklldef.py \
+ $(S)src/librustc_llvm/lib.rs
+ $(CFG_PYTHON) $^ $@ rustc_llvm-$(CFG_FILENAME_EXTRA)
+
+# All windows nightiles are currently a GNU triple, so this MSVC triple is not
+# bootstrapping from itself. This is relevant during stage0, and other parts of
+# the build system take this into account.
+BOOTSTRAP_FROM_x86_64-pc-windows-msvc := x86_64-pc-windows-gnu
CXX_x86_64-unknown-linux-musl=notaprogram
CPP_x86_64-unknown-linux-musl=$(CFG_MUSL_ROOT)/bin/musl-gcc -E
AR_x86_64-unknown-linux-musl=$(AR)
+CFG_INSTALL_ONLY_RLIB_x86_64-unknown-linux-musl = 1
CFG_LIB_NAME_x86_64-unknown-linux-musl=lib$(1).so
CFG_STATIC_LIB_NAME_x86_64-unknown-linux-musl=lib$(1).a
CFG_LIB_GLOB_x86_64-unknown-linux-musl=lib$(1)-*.so
$(eval $(foreach target, $(CFG_TARGET), \
$(eval $(foreach stage, 0 1 2 3, \
$(eval $(call CLEAN_TARGET_STAGE_N,$(stage),$(target),$(host))))))))
-
-define DEF_CLEAN_LLVM_HOST
-ifeq ($(CFG_LLVM_ROOT),)
-clean-llvm$(1):
- $$(Q)$$(MAKE) -C $$(CFG_LLVM_BUILD_DIR_$(1)) clean
-else
-clean-llvm$(1): ;
-
-endif
-endef
-
-$(foreach host, $(CFG_HOST), \
- $(eval $(call DEF_CLEAN_LLVM_HOST,$(host))))
# Documented-by-default crates
DOC_CRATES := std alloc collections core libc rustc_unicode
-# Installed objects/libraries by default
-INSTALLED_OBJECTS := libmorestack.a libcompiler-rt.a
-
################################################################################
# You should not need to edit below this line
################################################################################
#
# $(1) is the crate to generate variables for
define RUST_CRATE
-CRATEFILE_$(1) := $$(S)src/lib$(1)/lib.rs
+CRATEFILE_$(1) := $$(SREL)src/lib$(1)/lib.rs
RSINPUTS_$(1) := $$(call rwildcard,$(S)src/lib$(1)/,*.rs)
RUST_DEPS_$(1) := $$(filter-out native:%,$$(DEPS_$(1)))
NATIVE_DEPS_$(1) := $$(patsubst native:%,%,$$(filter native:%,$$(DEPS_$(1))))
## GDB ##
DEBUGGER_RUSTLIB_ETC_SCRIPTS_GDB=gdb_load_rust_pretty_printers.py \
- gdb_rust_pretty_printing.py
+ gdb_rust_pretty_printing.py \
+ debugger_pretty_printers_common.py
DEBUGGER_RUSTLIB_ETC_SCRIPTS_GDB_ABS=\
$(foreach script,$(DEBUGGER_RUSTLIB_ETC_SCRIPTS_GDB), \
$(CFG_SRC_DIR)src/etc/$(script))
## LLDB ##
-DEBUGGER_RUSTLIB_ETC_SCRIPTS_LLDB=lldb_rust_formatters.py
+DEBUGGER_RUSTLIB_ETC_SCRIPTS_LLDB=lldb_rust_formatters.py \
+ debugger_pretty_printers_common.py
DEBUGGER_RUSTLIB_ETC_SCRIPTS_LLDB_ABS=\
$(foreach script,$(DEBUGGER_RUSTLIB_ETC_SCRIPTS_LLDB), \
$(CFG_SRC_DIR)src/etc/$(script))
dist-install-dir-$(1): PREPARE_LIB_CMD=$(DEFAULT_PREPARE_LIB_CMD)
dist-install-dir-$(1): PREPARE_MAN_CMD=$(DEFAULT_PREPARE_MAN_CMD)
dist-install-dir-$(1): PREPARE_CLEAN=true
-dist-install-dir-$(1): prepare-base-dir-$(1) docs compiler-docs
+dist-install-dir-$(1): prepare-base-dir-$(1) docs
$$(Q)mkdir -p $$(PREPARE_DEST_DIR)/share/doc/rust
$$(Q)$$(PREPARE_MAN_CMD) $$(S)COPYRIGHT $$(PREPARE_DEST_DIR)/share/doc/rust
$$(Q)$$(PREPARE_MAN_CMD) $$(S)LICENSE-APACHE $$(PREPARE_DEST_DIR)/share/doc/rust
@$(call E, build: $$@)
# Copy essential gcc components into installer
ifdef CFG_WINDOWSY_$(1)
+ifeq ($$(findstring gnu,$(1)),gnu)
$$(Q)rm -Rf tmp/dist/win-rust-gcc-$(1)
$$(Q)$$(CFG_PYTHON) $$(S)src/etc/make-win-dist.py tmp/dist/$$(PKG_NAME)-$(1)-image tmp/dist/win-rust-gcc-$(1) $(1)
$$(Q)cp -r $$(S)src/etc/third-party tmp/dist/$$(PKG_NAME)-$(1)-image/share/doc/
+endif
endif
$$(Q)$$(S)src/rust-installer/gen-installer.sh \
--product-name=Rust \
--legacy-manifest-dirs=rustlib,cargo
$$(Q)rm -R tmp/dist/$$(PKG_NAME)-$(1)-image
-dist-doc-install-dir-$(1): docs compiler-docs
+dist-doc-install-dir-$(1): docs
$$(Q)mkdir -p tmp/dist/$$(DOC_PKG_NAME)-$(1)-image/share/doc/rust
$$(Q)cp -r doc tmp/dist/$$(DOC_PKG_NAME)-$(1)-image/share/doc/rust/html
dist-install-dirs: $(foreach host,$(CFG_HOST),dist-install-dir-$(host))
ifdef CFG_WINDOWSY_$(CFG_BUILD)
-MAYBE_MINGW_TARBALLS=$(foreach host,$(CFG_HOST),dist/$(MINGW_PKG_NAME)-$(host).tar.gz)
+define BUILD_MINGW_TARBALL
+ifeq ($$(findstring gnu,$(1)),gnu)
+MAYBE_MINGW_TARBALLS += dist/$(MINGW_PKG_NAME)-$(1).tar.gz
+endif
+endef
+
+$(foreach host,$(CFG_HOST),\
+ $(eval $(call BUILD_MINGW_TARBALL,$(host))))
endif
ifeq ($(CFG_DISABLE_DOCS),)
# Just copy the docs to a folder under dist with the appropriate name
# for uploading to S3
-dist-docs: docs compiler-docs
+dist-docs: docs
$(Q) rm -Rf dist/doc
$(Q) mkdir -p dist/doc/
$(Q) cp -r doc dist/doc/$(CFG_PACKAGE_VERS)
doc/not_found.html: $(D)/not_found.md $(HTML_DEPS) | doc/
@$(call E, rustdoc: $@)
$(Q)$(RUSTDOC) $(RUSTDOC_HTML_OPTS_NO_CSS) \
+ --markdown-no-toc \
--markdown-css http://doc.rust-lang.org/rust.css $<
define DEF_DOC
$(foreach crate,$(CRATES),$(eval $(call DEF_LIB_DOC,$(crate))))
COMPILER_DOC_TARGETS := $(CRATES:%=doc/%/index.html)
-ifdef CFG_COMPILER_DOCS
+ifdef CFG_ENABLE_COMPILER_DOCS
DOC_TARGETS += $(COMPILER_DOC_TARGETS)
else
DOC_TARGETS += $(DOC_CRATES:%=doc/%/index.html)
LLVM_DEPS=$(LLVM_DEPS_SRC) $(LLVM_DEPS_INC)
endif
+ifdef CFG_DISABLE_OPTIMIZE_LLVM
+LLVM_BUILD_CONFIG_MODE := Debug
+else
+LLVM_BUILD_CONFIG_MODE := Release
+endif
+
define DEF_LLVM_RULES
# If CFG_LLVM_ROOT is defined then we don't build LLVM ourselves
LLVM_STAMP_$(1) = $$(CFG_LLVM_BUILD_DIR_$(1))/llvm-auto-clean-stamp
+ifeq ($$(findstring msvc,$(1)),msvc)
+
+$$(LLVM_CONFIG_$(1)): $$(LLVM_DEPS) $$(LLVM_STAMP_$(1))
+ @$$(call E, cmake: llvm)
+ $$(Q)$$(CFG_CMAKE) --build $$(CFG_LLVM_BUILD_DIR_$(1)) \
+ --config $$(LLVM_BUILD_CONFIG_MODE)
+ $$(Q)touch $$(LLVM_CONFIG_$(1))
+
+clean-llvm$(1):
+
+else
+
$$(LLVM_CONFIG_$(1)): $$(LLVM_DEPS) $$(LLVM_STAMP_$(1))
@$$(call E, make: llvm)
$$(Q)$$(MAKE) -C $$(CFG_LLVM_BUILD_DIR_$(1)) $$(CFG_LLVM_BUILD_ENV_$(1)) ONLY_TOOLS="$$(LLVM_TOOLS)"
$$(Q)touch $$(LLVM_CONFIG_$(1))
+
+clean-llvm$(1):
+ $$(Q)$$(MAKE) -C $$(CFG_LLVM_BUILD_DIR_$(1)) clean
+
endif
+else
+clean-llvm$(1):
+endif
+
+$$(LLVM_AR_$(1)): $$(LLVM_CONFIG_$(1))
+
# This is used to independently force an LLVM clean rebuild
# when we changed something not otherwise captured by builtin
# dependencies. In these cases, commit a change that touches
# This can't be done in target.mk because it's included before this file.
define LLVM_LINKAGE_DEPS
-$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.rustc_llvm: $$(LLVM_LINKAGE_PATH_$(3))
+$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.rustc_llvm: $$(LLVM_LINKAGE_PATH_$(2))
endef
$(foreach source,$(CFG_HOST), \
######################################################################
# The version number
-CFG_RELEASE_NUM=1.1.0
+CFG_RELEASE_NUM=1.2.0
# An optional number to put after the label, e.g. '.2' -> '-beta.2'
# NB Make sure it starts with a dot to conform to semver pre-release
# versions (section 9)
-CFG_PRERELEASE_VERSION=.5
+CFG_PRERELEASE_VERSION=.6
# Append a version-dependent hash to each library, so we can install different
# versions in the same place
# More configuration
######################################################################
-# We track all of the object files we might build so that we can find
-# and include all of the .d files in one fell swoop.
-ALL_OBJ_FILES :=
-
MKFILE_DEPS := config.stamp $(call rwildcard,$(CFG_SRC_DIR)mk/,*)
MKFILES_FOR_TARBALL:=$(MKFILE_DEPS)
ifneq ($(NO_MKFILE_DEPS),)
ifdef CFG_ENABLE_DEBUG_ASSERTIONS
$(info cfg: enabling debug assertions (CFG_ENABLE_DEBUG_ASSERTIONS))
- CFG_RUSTC_FLAGS += --cfg debug -C debug-assertions=on
-else
- CFG_RUSTC_FLAGS += --cfg ndebug
+ CFG_RUSTC_FLAGS += -C debug-assertions=on
endif
ifdef CFG_ENABLE_DEBUGINFO
# Any rules that depend on LLVM should depend on LLVM_CONFIG
LLVM_CONFIG_$(1):=$$(CFG_LLVM_INST_DIR_$(1))/bin/llvm-config$$(X_$(1))
LLVM_MC_$(1):=$$(CFG_LLVM_INST_DIR_$(1))/bin/llvm-mc$$(X_$(1))
+LLVM_AR_$(1):=$$(CFG_LLVM_INST_DIR_$(1))/bin/llvm-ar$$(X_$(1))
LLVM_VERSION_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --version)
LLVM_BINDIR_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --bindir)
LLVM_INCDIR_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --includedir)
LLVM_LIBDIR_RUSTFLAGS_$(1)=-L "$$(LLVM_LIBDIR_$(1))"
LLVM_LIBS_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --libs $$(LLVM_COMPONENTS))
LLVM_LDFLAGS_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --ldflags)
+ifeq ($$(findstring freebsd,$(1)),freebsd)
# On FreeBSD, it may search wrong headers (that are for pre-installed LLVM),
# so we replace -I with -iquote to ensure that it searches bundled LLVM first.
LLVM_CXXFLAGS_$(1)=$$(subst -I, -iquote , $$(shell "$$(LLVM_CONFIG_$(1))" --cxxflags))
+else
+LLVM_CXXFLAGS_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --cxxflags)
+endif
LLVM_HOST_TRIPLE_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --host-target)
LLVM_AS_$(1)=$$(CFG_LLVM_INST_DIR_$(1))/bin/llvm-as$$(X_$(1))
# exported
export CFG_SRC_DIR
+export CFG_SRC_DIR_RELATIVE
export CFG_BUILD_DIR
ifdef CFG_VER_DATE
export CFG_VER_DATE
# Prerequisites for using the stageN compiler to build target artifacts
TSREQ$(1)_T_$(2)_H_$(3) = \
$$(HSREQ$(1)_H_$(3)) \
- $$(foreach obj,$$(INSTALLED_OBJECTS),\
- $$(TLIB$(1)_T_$(2)_H_$(3))/$$(obj)) \
$$(foreach obj,$$(INSTALLED_OBJECTS_$(2)),\
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(obj))
endif
endif
-# These flags will cause the compiler to produce a .d file
-# next to the .o file that lists header deps.
-CFG_DEPEND_FLAGS = -MMD -MP -MT $(1) -MF $(1:%.o=%.d)
-
AR := ar
define SET_FROM_CFG
include $(wildcard $(CFG_SRC_DIR)mk/cfg/*.mk)
+define ADD_INSTALLED_OBJECTS
+ INSTALLED_OBJECTS_$(1) += $$(call CFG_STATIC_LIB_NAME_$(1),morestack) \
+ $$(call CFG_STATIC_LIB_NAME_$(1),compiler-rt)
+endef
+
+$(foreach target,$(CFG_TARGET), \
+ $(eval $(call ADD_INSTALLED_OBJECTS,$(target))))
+
+define DEFINE_LINKER
+ ifndef LINK_$(1)
+ LINK_$(1) := $$(CC_$(1))
+ endif
+endef
+
+$(foreach target,$(CFG_TARGET), \
+ $(eval $(call DEFINE_LINKER,$(target))))
+
# The -Qunused-arguments sidesteps spurious warnings from clang
define FILTER_FLAGS
ifeq ($$(CFG_USING_CLANG),1)
$(foreach target,$(CFG_TARGET), \
$(eval $(call FILTER_FLAGS,$(target))))
+# Configure various macros to pass gcc or cl.exe style arguments
+define CC_MACROS
+ CFG_CC_INCLUDE_$(1)=-I $$(1)
+ ifeq ($$(findstring msvc,$(1)),msvc)
+ CFG_CC_OUTPUT_$(1)=-Fo:$$(1)
+ CFG_CREATE_ARCHIVE_$(1)=$$(AR_$(1)) -OUT:$$(1)
+ else
+ CFG_CC_OUTPUT_$(1)=-o $$(1)
+ CFG_CREATE_ARCHIVE_$(1)=$$(AR_$(1)) crus $$(1)
+ endif
+endef
+
+$(foreach target,$(CFG_TARGET), \
+ $(eval $(call CC_MACROS,$(target))))
+
ifeq ($(CFG_CCACHE_CPP2),1)
CCACHE_CPP2=1
define CFG_MAKE_TOOLCHAIN
# Prepend the tools with their prefix if cross compiling
ifneq ($(CFG_BUILD),$(1))
+ ifneq ($$(findstring msvc,$(1)),msvc)
CC_$(1)=$(CROSS_PREFIX_$(1))$(CC_$(1))
CXX_$(1)=$(CROSS_PREFIX_$(1))$(CXX_$(1))
CPP_$(1)=$(CROSS_PREFIX_$(1))$(CPP_$(1))
AR_$(1)=$(CROSS_PREFIX_$(1))$(AR_$(1))
- RUSTC_CROSS_FLAGS_$(1)=-C linker=$$(call FIND_COMPILER,$$(CC_$(1))) \
+ LINK_$(1)=$(CROSS_PREFIX_$(1))$(LINK_$(1))
+ RUSTC_CROSS_FLAGS_$(1)=-C linker=$$(call FIND_COMPILER,$$(LINK_$(1))) \
-C ar=$$(call FIND_COMPILER,$$(AR_$(1))) $(RUSTC_CROSS_FLAGS_$(1))
RUSTC_FLAGS_$(1)=$$(RUSTC_CROSS_FLAGS_$(1)) $(RUSTC_FLAGS_$(1))
+ endif
endif
CFG_COMPILE_C_$(1) = $$(CC_$(1)) \
$$(CFG_GCCISH_CFLAGS) \
$$(CFG_GCCISH_CFLAGS_$(1)) \
- $$(CFG_DEPEND_FLAGS) \
- -c -o $$(1) $$(2)
+ -c $$(call CFG_CC_OUTPUT_$(1),$$(1)) $$(2)
CFG_LINK_C_$(1) = $$(CC_$(1)) \
$$(CFG_GCCISH_LINK_FLAGS) -o $$(1) \
$$(CFG_GCCISH_LINK_FLAGS_$(1)) \
$$(CFG_GCCISH_CXXFLAGS) \
$$(CFG_GCCISH_CFLAGS_$(1)) \
$$(CFG_GCCISH_CXXFLAGS_$(1)) \
- $$(CFG_DEPEND_FLAGS) \
- -c -o $$(1) $$(2)
+ -c $$(call CFG_CC_OUTPUT_$(1),$$(1)) $$(2)
CFG_LINK_CXX_$(1) = $$(CXX_$(1)) \
$$(CFG_GCCISH_LINK_FLAGS) -o $$(1) \
$$(CFG_GCCISH_LINK_FLAGS_$(1)) \
# We're using llvm-mc as our assembler because it supports
# .cfi pseudo-ops on mac
- CFG_ASSEMBLE_$(1)=$$(CPP_$(1)) -E $$(CFG_DEPEND_FLAGS) $$(2) | \
+ CFG_ASSEMBLE_$(1)=$$(CPP_$(1)) -E $$(2) | \
$$(LLVM_MC_$$(CFG_BUILD)) \
-assemble \
-relocation-model=$$(LLVM_MC_RELOCATION_MODEL) \
# For the ARM, AARCH64, MIPS and POWER crosses, use the toolchain assembler
# FIXME: We should be able to use the LLVM assembler
CFG_ASSEMBLE_$(1)=$$(CC_$(1)) $$(CFG_GCCISH_CFLAGS_$(1)) \
- $$(CFG_DEPEND_FLAGS) $$(2) -c -o $$(1)
+ $$(2) -c -o $$(1)
endif
# Create a directory
# $(1) is the directory
+#
+# XXX: These defines are called to generate make steps.
+# Adding blank lines means two steps from different defines will not end up on
+# the same line.
define PREPARE_DIR
- @$(Q)$(call E, prepare: $(1))
+
+ @$(call E, prepare: $(1))
$(Q)$(PREPARE_DIR_CMD) $(1)
+
endef
# Copy an executable
# $(1) is the filename/libname-glob
+#
+# See above for an explanation on the surrounding blank lines
define PREPARE_BIN
+
@$(call E, prepare: $(PREPARE_DEST_BIN_DIR)/$(1))
$(Q)$(PREPARE_BIN_CMD) $(PREPARE_SOURCE_BIN_DIR)/$(1) $(PREPARE_DEST_BIN_DIR)/$(1)
+
endef
# Copy a dylib or rlib
# $(1) is the filename/libname-glob
#
-# XXX: Don't remove the $(nop) command below!
-# Yeah, that's right, it's voodoo. Something in the way this macro is being expanded
-# causes it to parse incorrectly. Throwing in that empty command seems to fix the
-# problem. I'm sorry, just don't remove the $(nop), alright?
+# See above for an explanation on the surrounding blank lines
define PREPARE_LIB
- $(nop)
+
@$(call E, prepare: $(PREPARE_WORKING_DEST_LIB_DIR)/$(1))
$(Q)LIB_NAME="$(notdir $(lastword $(wildcard $(PREPARE_WORKING_SOURCE_LIB_DIR)/$(1))))"; \
MATCHES="$(filter-out %$(notdir $(lastword $(wildcard $(PREPARE_WORKING_SOURCE_LIB_DIR)/$(1)))), \
echo " at destination $(PREPARE_WORKING_DEST_LIB_DIR):" && \
echo $$MATCHES ; \
fi
- $(Q)$(PREPARE_LIB_CMD) `ls -drt1 $(PREPARE_WORKING_SOURCE_LIB_DIR)/$(1) | tail -1` $(PREPARE_WORKING_DEST_LIB_DIR)/
+ $(Q)$(PREPARE_LIB_CMD) `ls -drt1 $(PREPARE_WORKING_SOURCE_LIB_DIR)/$(1)` $(PREPARE_WORKING_DEST_LIB_DIR)/
+
endef
# Copy a man page
# $(1) - source dir
+#
+# See above for an explanation on the surrounding blank lines
define PREPARE_MAN
+
@$(call E, prepare: $(PREPARE_DEST_MAN_DIR)/$(1))
$(Q)$(PREPARE_MAN_CMD) $(PREPARE_SOURCE_MAN_DIR)/$(1) $(PREPARE_DEST_MAN_DIR)/$(1)
+
endef
PREPARE_TOOLS = $(filter-out compiletest rustbook error-index-generator, $(TOOLS))
# Rebind PREPARE_*_LIB_DIR to point to rustlib, then install the libs for the targets
prepare-target-$(2)-host-$(3)-$(1)-$(4): PREPARE_WORKING_SOURCE_LIB_DIR=$$(PREPARE_SOURCE_LIB_DIR)/rustlib/$(2)/lib
prepare-target-$(2)-host-$(3)-$(1)-$(4): PREPARE_WORKING_DEST_LIB_DIR=$$(PREPARE_DEST_LIB_DIR)/rustlib/$(2)/lib
+prepare-target-$(2)-host-$(3)-$(1)-$(4): PREPARE_SOURCE_BIN_DIR=$$(PREPARE_SOURCE_LIB_DIR)/rustlib/$(3)/bin
+prepare-target-$(2)-host-$(3)-$(1)-$(4): PREPARE_DEST_BIN_DIR=$$(PREPARE_DEST_LIB_DIR)/rustlib/$(3)/bin
prepare-target-$(2)-host-$(3)-$(1)-$(4): prepare-maybe-clean-$(4) \
$$(foreach crate,$$(TARGET_CRATES), \
$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$$(crate)) \
$$(if $$(findstring $(2), $$(PREPARE_TARGETS)), \
$$(if $$(findstring $(3), $$(PREPARE_HOST)), \
$$(call PREPARE_DIR,$$(PREPARE_WORKING_DEST_LIB_DIR)) \
+ $$(call PREPARE_DIR,$$(PREPARE_DEST_BIN_DIR)) \
$$(foreach crate,$$(TARGET_CRATES), \
$$(if $$(or $$(findstring 1, $$(ONLY_RLIB_$$(crate))),$$(findstring 1,$$(CFG_INSTALL_ONLY_RLIB_$(2)))),, \
$$(call PREPARE_LIB,$$(call CFG_LIB_GLOB_$(2),$$(crate)))) \
$$(if $$(findstring $(2),$$(CFG_HOST)), \
$$(foreach crate,$$(HOST_CRATES), \
$$(call PREPARE_LIB,$$(call CFG_LIB_GLOB_$(2),$$(crate)))),) \
- $$(foreach object,$$(INSTALLED_OBJECTS) $$(INSTALLED_OBJECTS_$(2)),\
- $$(call PREPARE_LIB,$$(object))),),),)
+ $$(foreach object,$$(INSTALLED_OBJECTS_$(2)),\
+ $$(call PREPARE_LIB,$$(object))) \
+ $$(foreach bin,$$(INSTALLED_BINS_$(3)),\
+ $$(call PREPARE_BIN,$$(bin))) \
+ ,),),)
endef
define INSTALL_GDB_DEBUGGER_SCRIPTS_COMMANDS
Makefile config.mk: config.stamp
+ifeq ($(SREL),)
+SREL_ROOT := ./
+else
+SREL_ROOT := $(SREL)
+endif
+
config.stamp: $(S)configure $(S)Makefile.in $(S)src/snapshots.txt
@$(call E, cfg: reconfiguring)
- $(S)configure $(CFG_CONFIGURE_ARGS)
+ $(SREL_ROOT)configure $(CFG_CONFIGURE_ARGS)
@mkdir -p $$(@D)
@$$(call E, compile: $$@)
$$(Q)$$(call CFG_COMPILE_C_$(1), $$@, \
- -I $$(S)src/rt/hoedown/src \
- -I $$(S)src/rt \
+ $$(call CFG_CC_INCLUDE_$(1),$$(S)src/rt/hoedown/src) \
+ $$(call CFG_CC_INCLUDE_$(1),$$(S)src/rt) \
$$(RUNTIME_CFLAGS_$(1))) $$<
$$(RT_OUTPUT_DIR_$(1))/%.o: $(S)src/rt/%.S $$(MKFILE_DEPS) \
NATIVE_$(2)_$(1) := $$(call CFG_STATIC_LIB_NAME_$(1),$(2))
$$(RT_OUTPUT_DIR_$(1))/$$(NATIVE_$(2)_$(1)): $$(OBJS_$(2)_$(1))
@$$(call E, link: $$@)
- $$(Q)$$(AR_$(1)) rcs $$@ $$^
-
-ifeq ($$(findstring windows,$(1)),windows)
-$$(RT_OUTPUT_DIR_$(1))/lib$(2).a: $$(RT_OUTPUT_DIR_$(1))/$$(NATIVE_$(2)_$(1))
- $$(Q)cp $$^ $$@
-endif
+ $$(Q)$$(call CFG_CREATE_ARCHIVE_$(1),$$@) $$^
endef
$(S)src/compiler-rt/*/*/*/*)
endif
-COMPRT_NAME_$(1) := libcompiler-rt.a
+COMPRT_NAME_$(1) := $$(call CFG_STATIC_LIB_NAME_$(1),compiler-rt)
COMPRT_LIB_$(1) := $$(RT_OUTPUT_DIR_$(1))/$$(COMPRT_NAME_$(1))
COMPRT_BUILD_DIR_$(1) := $$(RT_OUTPUT_DIR_$(1))/compiler-rt
+# Note that on MSVC-targeting builds we hardwire CC/AR to gcc/ar even though
+# we're targeting MSVC. This is because although compiler-rt has a CMake build
+# config I can't actually figure out how to use it, so I'm not sure how to use
+# cl.exe to build the objects. Additionally, the compiler-rt library when built
+# with gcc has the same ABI as cl.exe, so they're largely compatible
+COMPRT_CC_$(1) := $$(CC_$(1))
+COMPRT_AR_$(1) := $$(AR_$(1))
+COMPRT_CFLAGS_$(1) := $$(CFG_GCCISH_CFLAGS_$(1))
+ifeq ($$(findstring msvc,$(1)),msvc)
+COMPRT_CC_$(1) := gcc
+COMPRT_AR_$(1) := ar
+COMPRT_CFLAGS_$(1) := $$(CFG_GCCISH_CFLAGS_$(1)) -m64
+endif
+
$$(COMPRT_LIB_$(1)): $$(COMPRT_DEPS) $$(MKFILE_DEPS)
@$$(call E, make: compiler-rt)
$$(Q)$$(MAKE) -C "$(S)src/compiler-rt" \
ProjSrcRoot="$(S)src/compiler-rt" \
ProjObjRoot="$$(abspath $$(COMPRT_BUILD_DIR_$(1)))" \
- CC="$$(CC_$(1))" \
- AR="$$(AR_$(1))" \
- RANLIB="$$(AR_$(1)) s" \
- CFLAGS="$$(CFG_GCCISH_CFLAGS_$(1))" \
+ CC='$$(COMPRT_CC_$(1))' \
+ AR='$$(COMPRT_AR_$(1))' \
+ RANLIB='$$(COMPRT_AR_$(1)) s' \
+ CFLAGS="$$(COMPRT_CFLAGS_$(1))" \
TargetTriple=$(1) \
triple-builtins
- $$(Q)cp $$(COMPRT_BUILD_DIR_$(1))/triple/builtins/libcompiler_rt.a $$(COMPRT_LIB_$(1))
+ $$(Q)cp $$(COMPRT_BUILD_DIR_$(1))/triple/builtins/libcompiler_rt.a $$@
################################################################################
# libbacktrace
# to find the llvm includes (probably because we're not actually installing
# llvm, but using it straight out of the build directory)
ifdef CFG_WINDOWSY_$(1)
-LLVM_EXTRA_INCDIRS_$(1)= -iquote $(S)src/llvm/include \
- -iquote $$(CFG_LLVM_BUILD_DIR_$(1))/include
+LLVM_EXTRA_INCDIRS_$(1)= $$(call CFG_CC_INCLUDE_$(1),$(S)src/llvm/include) \
+ $$(call CFG_CC_INCLUDE_$(1),\
+ $$(CFG_LLVM_BUILD_DIR_$(1))/include)
endif
RUSTLLVM_OBJS_CS_$(1) := $$(addprefix rustllvm/, \
ExecutionEngineWrapper.cpp RustWrapper.cpp PassWrapper.cpp)
RUSTLLVM_INCS_$(1) = $$(LLVM_EXTRA_INCDIRS_$(1)) \
- -iquote $$(LLVM_INCDIR_$(1)) \
- -iquote $$(S)src/rustllvm/include
+ $$(call CFG_CC_INCLUDE_$(1),$$(LLVM_INCDIR_$(1))) \
+ $$(call CFG_CC_INCLUDE_$(1),$$(S)src/rustllvm/include)
RUSTLLVM_OBJS_OBJS_$(1) := $$(RUSTLLVM_OBJS_CS_$(1):rustllvm/%.cpp=$(1)/rustllvm/%.o)
-ALL_OBJ_FILES += $$(RUSTLLVM_OBJS_OBJS_$(1))
+
+# Note that we appease `cl.exe` and its need for some sort of exception
+# handling flag with the `EHsc` argument here as well.
+ifeq ($$(findstring msvc,$(1)),msvc)
+EXTRA_RUSTLLVM_CXXFLAGS_$(1) := //EHsc
+endif
$$(RT_OUTPUT_DIR_$(1))/$$(call CFG_STATIC_LIB_NAME_$(1),rustllvm): \
$$(RUSTLLVM_OBJS_OBJS_$(1))
@$$(call E, link: $$@)
- $$(Q)$$(AR_$(1)) rcs $$@ $$(RUSTLLVM_OBJS_OBJS_$(1))
+ $$(Q)$$(call CFG_CREATE_ARCHIVE_$(1),$$@) $$^
+# On MSVC we need to double-escape arguments that llvm-config printed which
+# start with a '/'. The shell we're running in will auto-translate the argument
+# `/foo` to `C:/msys64/foo` but we really want it to be passed through as `/foo`
+# so the argument passed to our shell must be `//foo`.
$(1)/rustllvm/%.o: $(S)src/rustllvm/%.cpp $$(MKFILE_DEPS) $$(LLVM_CONFIG_$(1))
@$$(call E, compile: $$@)
- $$(Q)$$(call CFG_COMPILE_CXX_$(1), $$@, $$(LLVM_CXXFLAGS_$(1)) $$(RUSTLLVM_INCS_$(1))) $$<
+ $$(Q)$$(call CFG_COMPILE_CXX_$(1), $$@,) \
+ $$(subst /,//,$$(LLVM_CXXFLAGS_$(1))) \
+ $$(EXTRA_RUSTLLVM_CXXFLAGS_$(1)) \
+ $$(RUSTLLVM_INCS_$(1)) \
+ $$<
endef
# Instantiate template for all stages
$$(foreach dep,$$(NATIVE_DEPS_$(4)), \
$$(RT_OUTPUT_DIR_$(2))/$$(call CFG_STATIC_LIB_NAME_$(2),$$(dep))) \
$$(foreach dep,$$(NATIVE_DEPS_$(4)_T_$(2)), \
- $$(RT_OUTPUT_DIR_$(2))/$$(dep))
+ $$(RT_OUTPUT_DIR_$(2))/$$(dep)) \
+ $$(foreach dep,$$(NATIVE_TOOL_DEPS_$(4)_T_$(2)), \
+ $$(TBIN$(1)_T_$(3)_H_$(3))/$$(dep)) \
+ $$(CUSTOM_DEPS_$(4)_T_$(2))
endef
$(foreach host,$(CFG_HOST), \
$$(dir $$@)$$(call CFG_LIB_GLOB_$(2),$(4)))
$$(call REMOVE_ALL_OLD_GLOB_MATCHES, \
$$(dir $$@)$$(call CFG_RLIB_GLOB,$(4)))
- $(Q)CFG_LLVM_LINKAGE_FILE=$$(LLVM_LINKAGE_PATH_$(3)) \
+ $(Q)CFG_LLVM_LINKAGE_FILE=$$(LLVM_LINKAGE_PATH_$(2)) \
$$(subst @,,$$(STAGE$(1)_T_$(2)_H_$(3))) \
$$(RUST_LIB_FLAGS_ST$(1)) \
-L "$$(RT_OUTPUT_DIR_$(2))" \
$$(LLVM_LIBDIR_RUSTFLAGS_$(2)) \
$$(LLVM_STDCPP_RUSTFLAGS_$(2)) \
$$(RUSTFLAGS_$(4)) \
+ $$(RUSTFLAGS_$(4)_T_$(2)) \
--out-dir $$(@D) \
-C extra-filename=-$$(CFG_FILENAME_EXTRA) \
$$<
| $$(TLIB$(1)_T_$(2)_H_$(3))/ $$(SNAPSHOT_RUSTC_POST_CLEANUP)
@$$(call E, cp: $$@)
$$(Q)cp $$< $$@
+
+$$(TBIN$(1)_T_$(2)_H_$(3))/%: $$(CFG_LLVM_INST_DIR_$(2))/bin/% \
+ | $$(TBIN$(1)_T_$(2)_H_$(3))/ $$(SNAPSHOT_RUSTC_POST_CLEANUP)
+ @$$(call E, cp: $$@)
+ $$(Q)cp $$< $$@
endef
$(foreach source,$(CFG_HOST), \
$(foreach stage,$(STAGES), \
$(foreach tool,$(TOOLS), \
$(eval $(call TARGET_TOOL,$(stage),$(target),$(host),$(tool)))))))
+
+# We have some triples which are bootstrapped from other triples, and this means
+# that we need to fixup some of the native tools that a triple depends on.
+#
+# For example, MSVC requires the llvm-ar.exe executable to manage archives, but
+# it bootstraps from the GNU Windows triple. This means that the compiler will
+# add this directory to PATH when executing new processes:
+#
+# $SYSROOT/rustlib/x86_64-pc-windows-gnu/bin
+#
+# Unfortunately, however, the GNU triple is not known about in stage0, so the
+# tools are actually located in:
+#
+# $SYSROOT/rustlib/x86_64-pc-windows-msvc/bin
+#
+# To remedy this problem, the rules below copy all native tool dependencies into
+# the bootstrap triple's location in stage 0 so the bootstrap compiler can find
+# the right sets of tools. Later stages (1+) will have the right host triple for
+# the compiler, so there's no need to worry there.
+#
+# $(1) - stage
+# $(2) - triple that's being used as host/target
+# $(3) - triple snapshot is built for
+# $(4) - crate
+# $(5) - tool
+define MOVE_TOOLS_TO_SNAPSHOT_HOST_DIR
+ifneq (,$(3))
+$$(TLIB$(1)_T_$(2)_H_$(2))/stamp.$(4): $$(HLIB$(1)_H_$(2))/rustlib/$(3)/bin/$(5)
+
+$$(HLIB$(1)_H_$(2))/rustlib/$(3)/bin/$(5): $$(TBIN$(1)_T_$(2)_H_$(2))/$(5)
+ mkdir -p $$(@D)
+ cp $$< $$@
+endif
+endef
+
+$(foreach target,$(CFG_TARGET), \
+ $(foreach crate,$(CRATES), \
+ $(foreach tool,$(NATIVE_TOOL_DEPS_$(crate)_T_$(target)), \
+ $(eval $(call MOVE_TOOLS_TO_SNAPSHOT_HOST_DIR,0,$(target),$(BOOTSTRAP_FROM_$(target)),$(crate),$(tool))))))
$(Q)$(CFG_PYTHON) $(S)src/etc/check-summary.py tmp/*.log
# As above but don't bother running tidy.
-check-notidy: cleantmptestlogs cleantestlibs all check-stage2
+check-notidy: check-sanitycheck cleantmptestlogs cleantestlibs all check-stage2
$(Q)$(CFG_PYTHON) $(S)src/etc/check-summary.py tmp/*.log
# A slightly smaller set of tests for smoke testing.
-check-lite: cleantestlibs cleantmptestlogs \
+check-lite: check-sanitycheck cleantestlibs cleantmptestlogs \
$(foreach crate,$(TEST_TARGET_CRATES),check-stage2-$(crate)) \
check-stage2-rpass check-stage2-rpass-valgrind \
check-stage2-rfail check-stage2-cfail check-stage2-pfail check-stage2-rmake
$(Q)$(CFG_PYTHON) $(S)src/etc/check-summary.py tmp/*.log
# Only check the 'reference' tests: rpass/cfail/rfail/rmake.
-check-ref: cleantestlibs cleantmptestlogs check-stage2-rpass check-stage2-rpass-valgrind \
- check-stage2-rfail check-stage2-cfail check-stage2-pfail check-stage2-rmake
+check-ref: check-sanitycheck cleantestlibs cleantmptestlogs check-stage2-rpass \
+ check-stage2-rpass-valgrind check-stage2-rfail check-stage2-cfail check-stage2-pfail \
+ check-stage2-rmake
$(Q)$(CFG_PYTHON) $(S)src/etc/check-summary.py tmp/*.log
# Only check the docs.
-check-docs: cleantestlibs cleantmptestlogs check-stage2-docs
+check-docs: check-sanitycheck cleantestlibs cleantmptestlogs check-stage2-docs
$(Q)$(CFG_PYTHON) $(S)src/etc/check-summary.py tmp/*.log
# Some less critical tests that are not prone to breakage.
$$(CRATEFILE_$(4)) \
$$(TESTDEP_$(1)_$(2)_$(3)_$(4))
@$$(call E, rustc: $$@)
- $(Q)CFG_LLVM_LINKAGE_FILE=$$(LLVM_LINKAGE_PATH_$(3)) \
+ $(Q)CFG_LLVM_LINKAGE_FILE=$$(LLVM_LINKAGE_PATH_$(2)) \
$$(subst @,,$$(STAGE$(1)_T_$(2)_H_$(3))) -o $$@ $$< --test \
-L "$$(RT_OUTPUT_DIR_$(2))" \
$$(LLVM_LIBDIR_RUSTFLAGS_$(2)) \
CTEST_DISABLE_debuginfo-lldb = "no lldb found"
endif
-ifeq ($(CFG_CLANG),)
-CTEST_DISABLE_codegen = "no clang found"
-endif
-
ifneq ($(CFG_OSTYPE),apple-darwin)
CTEST_DISABLE_debuginfo-lldb = "lldb tests are only run on darwin"
endif
--run-lib-path $$(TLIB$(1)_T_$(2)_H_$(3)) \
--rustc-path $$(HBIN$(1)_H_$(3))/rustc$$(X_$(3)) \
--rustdoc-path $$(HBIN$(1)_H_$(3))/rustdoc$$(X_$(3)) \
- --clang-path $(if $(CFG_CLANG),$(CFG_CLANG),clang) \
--llvm-bin-path $(CFG_LLVM_INST_DIR_$(CFG_BUILD))/bin \
--aux-base $$(S)src/test/auxiliary/ \
--stage-id stage$(1)-$(2) \
$$(call TEST_OK_FILE,$(1),$(2),$(3),doc-crate-$(4)): $$(CRATEDOCTESTDEP_$(1)_$(2)_$(3)_$(4))
@$$(call E, run doc-crate-$(4) [$(2)])
$$(Q)touch $$@.start_time
- $$(Q)CFG_LLVM_LINKAGE_FILE=$$(LLVM_LINKAGE_PATH_$(3)) \
+ $$(Q)CFG_LLVM_LINKAGE_FILE=$$(LLVM_LINKAGE_PATH_$(2)) \
$$(RUSTDOC_$(1)_T_$(2)_H_$(3)) --test --cfg dox \
$$(CRATEFILE_$(4)) --test-args "$$(TESTARGS)" && \
touch -r $$@.start_time $$@ && rm $$@.start_time
@echo $*=$($*)
S := $(CFG_SRC_DIR)
+SREL := $(CFG_SRC_DIR_RELATIVE)
// The python executable
pub python: String,
- // The clang executable
- pub clang_path: Option<PathBuf>,
-
// The llvm binaries path
pub llvm_bin_path: Option<PathBuf>,
// Flags to pass to the compiler when building for the target
pub target_rustcflags: Option<String>,
- // Run tests using the JIT
- pub jit: bool,
-
// Target system to be tested
pub target: String,
#![crate_type = "bin"]
#![feature(box_syntax)]
-#![feature(collections)]
-#![feature(rustc_private)]
-#![feature(std_misc)]
-#![feature(test)]
+#![feature(dynamic_lib)]
+#![feature(libc)]
#![feature(path_ext)]
+#![feature(rustc_private)]
+#![feature(slice_extras)]
#![feature(str_char)]
-#![feature(libc)]
+#![feature(test)]
+#![feature(vec_push_all)]
#![deny(warnings)]
use std::path::{Path, PathBuf};
use getopts::{optopt, optflag, reqopt};
use common::Config;
-use common::{Pretty, DebugInfoGdb, DebugInfoLldb, Codegen};
+use common::{Pretty, DebugInfoGdb, DebugInfoLldb};
use util::logv;
pub mod procsrv;
reqopt("", "rustc-path", "path to rustc to use for compiling", "PATH"),
reqopt("", "rustdoc-path", "path to rustdoc to use for compiling", "PATH"),
reqopt("", "python", "path to python to use for doc tests", "PATH"),
- optopt("", "clang-path", "path to executable for codegen tests", "PATH"),
optopt("", "valgrind-path", "path to Valgrind executable for Valgrind tests", "PROGRAM"),
optflag("", "force-valgrind", "fail if Valgrind tests cannot be run under Valgrind"),
optopt("", "llvm-bin-path", "path to directory holding llvm binaries", "DIR"),
optopt("", "target-rustcflags", "flags to pass to rustc for target", "FLAGS"),
optflag("", "verbose", "run tests verbosely, showing all output"),
optopt("", "logfile", "file to log test execution to", "FILE"),
- optflag("", "jit", "run tests under the JIT"),
optopt("", "target", "the target to build for", "TARGET"),
optopt("", "host", "the host to build for", "HOST"),
optopt("", "gdb-version", "the version of GDB used", "VERSION STRING"),
rustc_path: opt_path(matches, "rustc-path"),
rustdoc_path: opt_path(matches, "rustdoc-path"),
python: matches.opt_str("python").unwrap(),
- clang_path: matches.opt_str("clang-path").map(|s| PathBuf::from(&s)),
valgrind_path: matches.opt_str("valgrind-path"),
force_valgrind: matches.opt_present("force-valgrind"),
llvm_bin_path: matches.opt_str("llvm-bin-path").map(|s| PathBuf::from(&s)),
runtool: matches.opt_str("runtool"),
host_rustcflags: matches.opt_str("host-rustcflags"),
target_rustcflags: matches.opt_str("target-rustcflags"),
- jit: matches.opt_present("jit"),
target: opt_str2(matches.opt_str("target")),
host: opt_str2(matches.opt_str("host")),
gdb_version: extract_gdb_version(matches.opt_str("gdb-version")),
opt_str(&config.host_rustcflags)));
logv(c, format!("target-rustcflags: {}",
opt_str(&config.target_rustcflags)));
- logv(c, format!("jit: {}", config.jit));
logv(c, format!("target: {}", config.target));
logv(c, format!("host: {}", config.host));
logv(c, format!("android-cross-path: {:?}",
let file = file.unwrap().path();
debug!("inspecting file {:?}", file.display());
if is_test(config, &file) {
- let t = make_test(config, &file, || {
- match config.mode {
- Codegen => make_metrics_test_closure(config, &file),
- _ => make_test_closure(config, &file)
- }
- });
- tests.push(t)
+ tests.push(make_test(config, &file))
}
}
tests
return valid;
}
-pub fn make_test<F>(config: &Config, testfile: &Path, f: F) -> test::TestDescAndFn where
- F: FnOnce() -> test::TestFn,
+pub fn make_test(config: &Config, testfile: &Path) -> test::TestDescAndFn
{
test::TestDescAndFn {
desc: test::TestDesc {
ignore: header::is_test_ignored(config, testfile),
should_panic: test::ShouldPanic::No,
},
- testfn: f(),
+ testfn: make_test_closure(config, &testfile),
}
}
}))
}
-pub fn make_metrics_test_closure(config: &Config, testfile: &Path) -> test::TestFn {
- let config = (*config).clone();
- let testfile = testfile.to_path_buf();
- test::DynMetricFn(box move |mm: &mut test::MetricMap| {
- runtest::run_metrics(config, &testfile, mm)
- })
-}
-
fn extract_gdb_version(full_version_line: Option<String>) -> Option<String> {
match full_version_line {
Some(ref full_version_line)
use std::fs::{self, File};
use std::io::BufReader;
use std::io::prelude::*;
-use std::iter::repeat;
use std::net::TcpStream;
use std::path::{Path, PathBuf};
use std::process::{Command, Output, ExitStatus};
-use std::str;
-use test::MetricMap;
pub fn run(config: Config, testfile: &Path) {
match &*config.target {
_=> { }
}
- let mut _mm = MetricMap::new();
- run_metrics(config, testfile, &mut _mm);
-}
-
-pub fn run_metrics(config: Config, testfile: &Path, mm: &mut MetricMap) {
if config.verbose {
// We're going to be dumping a lot of info. Start on a new line.
print!("\n\n");
Pretty => run_pretty_test(&config, &props, &testfile),
DebugInfoGdb => run_debuginfo_gdb_test(&config, &props, &testfile),
DebugInfoLldb => run_debuginfo_lldb_test(&config, &props, &testfile),
- Codegen => run_codegen_test(&config, &props, &testfile, mm),
+ Codegen => run_codegen_test(&config, &props, &testfile),
Rustdoc => run_rustdoc_test(&config, &props, &testfile),
}
}
}
fn run_rfail_test(config: &Config, props: &TestProps, testfile: &Path) {
- let proc_res = if !config.jit {
- let proc_res = compile_test(config, props, testfile);
+ let proc_res = compile_test(config, props, testfile);
- if !proc_res.status.success() {
- fatal_proc_rec("compilation failed!", &proc_res);
- }
+ if !proc_res.status.success() {
+ fatal_proc_rec("compilation failed!", &proc_res);
+ }
- exec_compiled_test(config, props, testfile)
- } else {
- jit_test(config, props, testfile)
- };
+ let proc_res = exec_compiled_test(config, props, testfile);
// The value our Makefile configures valgrind to return on failure
const VALGRIND_ERR: i32 = 100;
}
fn run_rpass_test(config: &Config, props: &TestProps, testfile: &Path) {
- if !config.jit {
- let mut proc_res = compile_test(config, props, testfile);
+ let proc_res = compile_test(config, props, testfile);
- if !proc_res.status.success() {
- fatal_proc_rec("compilation failed!", &proc_res);
- }
+ if !proc_res.status.success() {
+ fatal_proc_rec("compilation failed!", &proc_res);
+ }
- proc_res = exec_compiled_test(config, props, testfile);
+ let proc_res = exec_compiled_test(config, props, testfile);
- if !proc_res.status.success() {
- fatal_proc_rec("test run failed!", &proc_res);
- }
- } else {
- let proc_res = jit_test(config, props, testfile);
-
- if !proc_res.status.success() {
- fatal_proc_rec("jit failed!", &proc_res);
- }
+ if !proc_res.status.success() {
+ fatal_proc_rec("test run failed!", &proc_res);
}
}
format!("--target={}", config.target),
"-L".to_string(),
aux_dir.to_str().unwrap().to_string());
- args.extend(split_maybe_args(&config.target_rustcflags).into_iter());
- args.extend(split_maybe_args(&props.compile_flags).into_iter());
+ args.extend(split_maybe_args(&config.target_rustcflags));
+ args.extend(split_maybe_args(&props.compile_flags));
return ProcArgs {
prog: config.rustc_path.to_str().unwrap().to_string(),
args: args,
config.build_base.to_str().unwrap().to_string(),
"-L".to_string(),
aux_dir.to_str().unwrap().to_string());
- args.extend(split_maybe_args(&config.target_rustcflags).into_iter());
- args.extend(split_maybe_args(&props.compile_flags).into_iter());
+ args.extend(split_maybe_args(&config.target_rustcflags));
+ args.extend(split_maybe_args(&props.compile_flags));
// FIXME (#9639): This needs to handle non-utf8 paths
return ProcArgs {
prog: config.rustc_path.to_str().unwrap().to_string(),
script_str.push_str(&format!("set solib-search-path \
./{}/stage2/lib/rustlib/{}/lib/\n",
config.host, config.target));
- for line in breakpoint_lines.iter() {
+ for line in &breakpoint_lines {
script_str.push_str(&format!("break {:?}:{}\n",
testfile.file_name().unwrap()
.to_string_lossy(),
// Write debugger script:
// We don't want to hang when calling `quit` while the process is still running
- let mut script_str = String::from_str("settings set auto-confirm true\n");
+ let mut script_str = String::from("settings set auto-confirm true\n");
// Make LLDB emit its version, so we have it documented in the test output
script_str.push_str("version\n");
}
}
-fn check_expected_errors(expected_errors: Vec<errors::ExpectedError> ,
+fn check_expected_errors(expected_errors: Vec<errors::ExpectedError>,
testfile: &Path,
proc_res: &ProcRes) {
// true if we found the error in question
- let mut found_flags: Vec<_> = repeat(false).take(expected_errors.len()).collect();
+ let mut found_flags = vec![false; expected_errors.len()];
if proc_res.status.success() {
fatal("process did not return an error status");
}
}
- // A multi-line error will have followup lines which will always
- // start with one of these strings.
+ // A multi-line error will have followup lines which start with a space
+ // or open paren.
fn continuation( line: &str) -> bool {
- line.starts_with(" expected") ||
- line.starts_with(" found") ||
- // 1234
- // Should have 4 spaces: see issue 18946
- line.starts_with("(")
+ line.starts_with(" ") || line.starts_with("(")
}
// Scan and extract our error/warning messages,
compile_test_(config, props, testfile, &[])
}
-fn jit_test(config: &Config, props: &TestProps, testfile: &Path) -> ProcRes {
- compile_test_(config, props, testfile, &["--jit".to_string()])
-}
-
fn compile_test_(config: &Config, props: &TestProps,
testfile: &Path, extra_args: &[String]) -> ProcRes {
let aux_dir = aux_output_dir_name(config, testfile);
out_dir.to_str().unwrap().to_string(),
testfile.to_str().unwrap().to_string()];
args.extend(extra_args.iter().cloned());
- args.extend(split_maybe_args(&props.compile_flags).into_iter());
+ args.extend(split_maybe_args(&props.compile_flags));
let args = ProcArgs {
prog: config.rustdoc_path.to_str().unwrap().to_string(),
args: args,
vec!("--crate-type=dylib".to_string())
}
};
- crate_type.extend(extra_link_args.clone().into_iter());
+ crate_type.extend(extra_link_args.clone());
let aux_args =
make_compile_args(config,
&aux_props,
};
args.push(path.to_str().unwrap().to_string());
if props.force_host {
- args.extend(split_maybe_args(&config.host_rustcflags).into_iter());
+ args.extend(split_maybe_args(&config.host_rustcflags));
} else {
- args.extend(split_maybe_args(&config.target_rustcflags).into_iter());
+ args.extend(split_maybe_args(&config.target_rustcflags));
}
- args.extend(split_maybe_args(&props.compile_flags).into_iter());
+ args.extend(split_maybe_args(&props.compile_flags));
return ProcArgs {
prog: config.rustc_path.to_str().unwrap().to_string(),
args: args,
args.push(exe_file.to_str().unwrap().to_string());
// Add the arguments in the run_flags directive
- args.extend(split_maybe_args(&props.run_flags).into_iter());
+ args.extend(split_maybe_args(&props.run_flags));
let prog = args.remove(0);
return ProcArgs {
}
}
-// codegen tests (vs. clang)
+// codegen tests (using FileCheck)
-fn append_suffix_to_stem(p: &Path, suffix: &str) -> PathBuf {
- if suffix.is_empty() {
- p.to_path_buf()
- } else {
- let mut stem = p.file_stem().unwrap().to_os_string();
- stem.push("-");
- stem.push(suffix);
- p.with_file_name(&stem)
- }
-}
-
-fn compile_test_and_save_bitcode(config: &Config, props: &TestProps,
+fn compile_test_and_save_ir(config: &Config, props: &TestProps,
testfile: &Path) -> ProcRes {
let aux_dir = aux_output_dir_name(config, testfile);
// FIXME (#9639): This needs to handle non-utf8 paths
let mut link_args = vec!("-L".to_string(),
aux_dir.to_str().unwrap().to_string());
- let llvm_args = vec!("--emit=llvm-bc,obj".to_string(),
+ let llvm_args = vec!("--emit=llvm-ir".to_string(),
"--crate-type=lib".to_string());
- link_args.extend(llvm_args.into_iter());
+ link_args.extend(llvm_args);
let args = make_compile_args(config,
props,
link_args,
compose_and_run_compiler(config, props, testfile, args, None)
}
-fn compile_cc_with_clang_and_save_bitcode(config: &Config, _props: &TestProps,
- testfile: &Path) -> ProcRes {
- let bitcodefile = output_base_name(config, testfile).with_extension("bc");
- let bitcodefile = append_suffix_to_stem(&bitcodefile, "clang");
- let testcc = testfile.with_extension("cc");
- let proc_args = ProcArgs {
- // FIXME (#9639): This needs to handle non-utf8 paths
- prog: config.clang_path.as_ref().unwrap().to_str().unwrap().to_string(),
- args: vec!("-c".to_string(),
- "-emit-llvm".to_string(),
- "-o".to_string(),
- bitcodefile.to_str().unwrap().to_string(),
- testcc.to_str().unwrap().to_string())
- };
- compose_and_run(config, testfile, proc_args, Vec::new(), "", None, None)
-}
-
-fn extract_function_from_bitcode(config: &Config, _props: &TestProps,
- fname: &str, testfile: &Path,
- suffix: &str) -> ProcRes {
- let bitcodefile = output_base_name(config, testfile).with_extension("bc");
- let bitcodefile = append_suffix_to_stem(&bitcodefile, suffix);
- let extracted_bc = append_suffix_to_stem(&bitcodefile, "extract");
- let prog = config.llvm_bin_path.as_ref().unwrap().join("llvm-extract");
- let proc_args = ProcArgs {
- // FIXME (#9639): This needs to handle non-utf8 paths
- prog: prog.to_str().unwrap().to_string(),
- args: vec!(format!("-func={}", fname),
- format!("-o={}", extracted_bc.to_str().unwrap()),
- bitcodefile.to_str().unwrap().to_string())
- };
- compose_and_run(config, testfile, proc_args, Vec::new(), "", None, None)
-}
-
-fn disassemble_extract(config: &Config, _props: &TestProps,
- testfile: &Path, suffix: &str) -> ProcRes {
- let bitcodefile = output_base_name(config, testfile).with_extension("bc");
- let bitcodefile = append_suffix_to_stem(&bitcodefile, suffix);
- let extracted_bc = append_suffix_to_stem(&bitcodefile, "extract");
- let extracted_ll = extracted_bc.with_extension("ll");
- let prog = config.llvm_bin_path.as_ref().unwrap().join("llvm-dis");
+fn check_ir_with_filecheck(config: &Config, testfile: &Path) -> ProcRes {
+ let irfile = output_base_name(config, testfile).with_extension("ll");
+ let prog = config.llvm_bin_path.as_ref().unwrap().join("FileCheck");
let proc_args = ProcArgs {
// FIXME (#9639): This needs to handle non-utf8 paths
prog: prog.to_str().unwrap().to_string(),
- args: vec!(format!("-o={}", extracted_ll.to_str().unwrap()),
- extracted_bc.to_str().unwrap().to_string())
+ args: vec!(format!("-input-file={}", irfile.to_str().unwrap()),
+ testfile.to_str().unwrap().to_string())
};
compose_and_run(config, testfile, proc_args, Vec::new(), "", None, None)
}
-
-fn count_extracted_lines(p: &Path) -> usize {
- let mut x = Vec::new();
- File::open(&p.with_extension("ll")).unwrap().read_to_end(&mut x).unwrap();
- let x = str::from_utf8(&x).unwrap();
- x.lines().count()
-}
-
-
-fn run_codegen_test(config: &Config, props: &TestProps,
- testfile: &Path, mm: &mut MetricMap) {
+fn run_codegen_test(config: &Config, props: &TestProps, testfile: &Path) {
if config.llvm_bin_path.is_none() {
fatal("missing --llvm-bin-path");
}
- if config.clang_path.is_none() {
- fatal("missing --clang-path");
- }
-
- let mut proc_res = compile_test_and_save_bitcode(config, props, testfile);
- if !proc_res.status.success() {
- fatal_proc_rec("compilation failed!", &proc_res);
- }
-
- proc_res = extract_function_from_bitcode(config, props, "test", testfile, "");
- if !proc_res.status.success() {
- fatal_proc_rec("extracting 'test' function failed",
- &proc_res);
- }
-
- proc_res = disassemble_extract(config, props, testfile, "");
- if !proc_res.status.success() {
- fatal_proc_rec("disassembling extract failed", &proc_res);
- }
-
-
- let mut proc_res = compile_cc_with_clang_and_save_bitcode(config, props, testfile);
+ let mut proc_res = compile_test_and_save_ir(config, props, testfile);
if !proc_res.status.success() {
fatal_proc_rec("compilation failed!", &proc_res);
}
- proc_res = extract_function_from_bitcode(config, props, "test", testfile, "clang");
+ proc_res = check_ir_with_filecheck(config, testfile);
if !proc_res.status.success() {
- fatal_proc_rec("extracting 'test' function failed",
+ fatal_proc_rec("verification with 'FileCheck' failed",
&proc_res);
}
-
- proc_res = disassemble_extract(config, props, testfile, "clang");
- if !proc_res.status.success() {
- fatal_proc_rec("disassembling extract failed", &proc_res);
- }
-
- let base = output_base_name(config, testfile);
- let base_extract = append_suffix_to_stem(&base, "extract");
-
- let base_clang = append_suffix_to_stem(&base, "clang");
- let base_clang_extract = append_suffix_to_stem(&base_clang, "extract");
-
- let base_lines = count_extracted_lines(&base_extract);
- let clang_lines = count_extracted_lines(&base_clang_extract);
-
- mm.insert_metric("clang-codegen-ratio",
- (base_lines as f64) / (clang_lines as f64),
- 0.001);
}
fn charset() -> &'static str {
A nice replacement is the [lazy constructor macro][lcm] by [Marvin
Löbel][kim].
-[fqa]: https://mail.mozilla.org/pipermail/rust-dev/2013-April/003815.html
+[fqa]: http://yosefk.com/c++fqa/ctors.html#fqa-10.12
[elp]: http://ericlippert.com/2013/02/06/static-constructors-part-one/
[lcm]: https://gist.github.com/Kimundi/8782487
[kim]: https://github.com/Kimundi
## `->` for function return type
This is to make the language easier to parse for humans, especially in the face
-of higher-order functions. `fn foo<T>(f: fn(int): int, fn(T): U): U` is not
+of higher-order functions. `fn foo<T>(f: fn(i32): i32, fn(T): U): U` is not
particularly easy to read.
## Why is `let` used to introduce variables?
There aren't many large programs yet. The Rust [compiler][rustc], 60,000+ lines at the time of writing, is written in Rust. As the oldest body of Rust code it has gone through many iterations of the language, and some parts are nicer to look at than others. It may not be the best code to learn from, but [borrowck] and [resolve] were written recently.
[rustc]: https://github.com/rust-lang/rust/tree/master/src/librustc
-[resolve]: https://github.com/rust-lang/rust/blob/master/src/librustc/middle/resolve.rs
-[borrowck]: https://github.com/rust-lang/rust/blob/master/src/librustc/middle/borrowck/
+[resolve]: https://github.com/rust-lang/rust/tree/master/src/librustc_resolve
+[borrowck]: https://github.com/rust-lang/rust/tree/master/src/librustc_borrowck/borrowck
A research browser engine called [Servo][servo], currently 30,000+ lines across more than a dozen crates, will be exercising a lot of Rust's distinctive type-system and concurrency features, and integrating many native libraries.
* The standard library's [json] module. Enums and pattern matching
[sprocketnes]: https://github.com/pcwalton/sprocketnes
-[hash]: https://github.com/rust-lang/rust/blob/master/src/libstd/hash/mod.rs
-[HashMap]: https://github.com/rust-lang/rust/blob/master/src/libcollections/hashmap.rs
+[hash]: https://github.com/rust-lang/rust/tree/master/src/libcore/hash
+[HashMap]: https://github.com/rust-lang/rust/tree/master/src/libstd/collections/hash
[json]: https://github.com/rust-lang/rust/blob/master/src/libserialize/json.rs
You may also be interested in browsing [trending Rust repositories][github-rust] on GitHub.
## Is anyone using Rust in production?
-Currently, Rust is still pre-1.0, and so we don't recommend that you use Rust
-in production unless you know exactly what you're getting into.
-
-That said, there are two production deployments of Rust that we're aware of:
+Yes. For example (incomplete):
* [OpenDNS](http://labs.opendns.com/2013/10/04/zeromq-helping-us-block-malicious-domains/)
* [Skylight](http://skylight.io)
-
-Let the fact that this is an easily countable number be a warning.
+* [wit.ai](https://github.com/wit-ai/witd)
+* [Codius](https://codius.org/blog/codius-rust/)
+* [MaidSafe](http://maidsafe.net/)
+* [Terminal.com](https://terminal.com)
## Does it run on Windows?
</p><p>
This file may not be copied, modified, or distributed except according to those terms.
</p></footer>
-<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="playpen.js"></script>
## Macros
```antlr
-expr_macro_rules : "macro_rules" '!' ident '(' macro_rule * ')' ;
+expr_macro_rules : "macro_rules" '!' ident '(' macro_rule * ')' ';'
+ | "macro_rules" '!' ident '{' macro_rule * '}' ;
macro_rule : '(' matcher * ')' "=>" '(' transcriber * ')' ';' ;
matcher : '(' matcher * ')' | '[' matcher * ']'
| '{' matcher * '}' | '$' ident ':' ident
If you need help with something, or just want to talk about Rust with others,
there are a few places you can do that:
-The Rust IRC channels on [irc.mozilla.org](http://irc.mozilla.org/) are the
+The Rust IRC channels on [irc.mozilla.org](irc://irc.mozilla.org/) are the
fastest way to get help.
[`#rust`](http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust) is
the general discussion channel, and you'll find people willing to help you with
[`#rust-internals`](http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust-internals), which is for discussion of the development of Rust itself.
You can also get help on [Stack
-Overflow](http://stackoverflow.com/questions/tagged/rust). Searching for your
+Overflow](https://stackoverflow.com/questions/tagged/rust). Searching for your
problem might reveal someone who has asked it before!
-There is an active [subreddit](http://reddit.com/r/rust) with lots of
+There is an active [subreddit](https://reddit.com/r/rust) with lots of
discussion and news about Rust.
-There is also a [user forum](http://users.rust-lang.org), for all
-user-oriented discussion, and a [developer
-forum](http://internals.rust-lang.org/), where the development of Rust
+There is also a [user forum](https://users.rust-lang.org), for all
+user-oriented discussion, and a [developer
+forum](https://internals.rust-lang.org/), where the development of Rust
itself is discussed.
# Specification
Rust is still a young language, so there isn't a ton of tooling yet, but the
tools we have are really nice.
-[Cargo](http://crates.io) is Rust's package manager, and its website contains
+[Cargo](https://crates.io) is Rust's package manager, and its website contains
lots of good documentation.
[`rustdoc`](book/documentation.html) is used to generate documentation for Rust code.
If you encounter an error while compiling your code you may be able to look it
up in the [Rust Compiler Error Index](error-index.html).
+
+# Community Translations
+
+Several projects have been started to translate the documentation into other
+languages:
+
+- [Russian](https://github.com/kgv/rust_book_ru)
+- [Korean](https://github.com/rust-kr/doc.rust-kr.org)
+- [Chinese](https://github.com/KaiserY/rust-book-chinese)
+- [Spanish](https://github.com/goyox86/elpr)
+
Some things that might be helpful to you though:
-## Search
+# Search
* <form action="https://duckduckgo.com/">
<input type="text" id="site-search" name="q" size="80"></input>
</form>
* Rust doc search: <span id="core-search"></span>
-## Reference
+# Reference
* [The Rust official site](http://rust-lang.org)
* [The Rust reference](http://doc.rust-lang.org/reference.html)
-## Docs
+# Docs
* [The standard library](http://doc.rust-lang.org/std/)
```
A crate that contains a `main` function can be compiled to an executable. If a
-`main` function is present, its return type must be [`unit`](#primitive-types)
+`main` function is present, its return type must be [`unit`](#tuple-types)
and it must take no arguments.
# Items and attributes
signature. Each type parameter must be explicitly declared, in an
angle-bracket-enclosed, comma-separated list following the function name.
-```{.ignore}
-fn iter<T, F>(seq: &[T], f: F) where T: Copy, F: Fn(T) {
- for elt in seq { f(*elt); }
-}
-fn map<T, U, F>(seq: &[T], f: F) -> Vec<U> where T: Copy, U: Copy, F: Fn(T) -> U {
- let mut acc = vec![];
- for elt in seq { acc.push(f(*elt)); }
- acc
-}
+```rust,ignore
+// foo is generic over A and B
+
+fn foo<A, B>(x: A, y: B) {
```
Inside the function signature and body, the name of the type parameter can be
used as a type name. [Trait](#traits) bounds can be specified for type parameters
to allow methods with that trait to be called on values of that type. This is
-specified using the `where` syntax, as in the above example.
+specified using the `where` syntax:
+
+```rust,ignore
+fn foo<T>(x: T) where T: Debug {
+```
When a generic function is referenced, its type is instantiated based on the
-context of the reference. For example, calling the `iter` function defined
-above on `[1, 2]` will instantiate type parameter `T` with `i32`, and require
-the closure parameter to have type `Fn(i32)`.
+context of the reference. For example, calling the `foo` function here:
+
+```
+use std::fmt::Debug;
+
+fn foo<T>(x: &[T]) where T: Debug {
+ // details elided
+ # ()
+}
+
+foo(&[1, 2]);
+```
+
+will instantiate type parameter `T` with `i32`.
The type parameters can also be explicitly supplied in a trailing
[path](#paths) component after the function name. This might be necessary if
* Deadlocks
* Reading data from private fields (`std::repr`)
-* Leaks due to reference count cycles, even in the global heap
+* Leaks of memory and other resources
* Exiting without calling destructors
* Sending signals
* Accessing/modifying the file system
extern "stdcall" fn new_i32_stdcall() -> i32 { 0 }
```
-Unlike normal functions, extern fns have an `extern "ABI" fn()`. This is the
+Unlike normal functions, extern fns have type `extern "ABI" fn()`. This is the
same type as the functions declared in an extern block.
```
```
trait Foo {
fn bar(&self);
-
fn baz(&self) { println!("We called baz."); }
}
```
```
Generic functions may use traits as _bounds_ on their type parameters. This
-will have two effects: only types that have the trait may instantiate the
-parameter, and within the generic function, the methods of the trait can be
-called on values that have the parameter's type. For example:
+will have two effects:
+
+- Only types that have the trait may instantiate the parameter.
+- Within the generic function, the methods of the trait can be
+ called on values that have the parameter's type.
+
+For example:
```
# type Surface = i32;
values of the type that the implementation targets. In such an implementation,
the trait type and `for` after `impl` are omitted. Such implementations are
limited to nominal types (enums, structs), and the implementation must appear
-in the same module or a sub-module as the `self` type:
+in the same crate as the `self` type:
```
struct Point {x: i32, y: i32}
- `simd` - on certain tuple structs, derive the arithmetic operators, which
lower to the target's SIMD instructions, if any; the `simd` feature gate
is necessary to use this attribute.
-- `static_assert` - on statics whose type is `bool`, terminates compilation
- with an error if it is not initialized to `true`. To use this, the `static_assert`
- feature gate must be enabled.
- `unsafe_no_drop_flag` - on structs, remove the flag that prevents
destructors from being run twice. Destructors might be run multiple times on
the same object with this attribute. To use this, the `unsafe_no_drop_flag` feature
The following configurations must be defined by the implementation:
+* `debug_assertions`. Enabled by default when compiling without optimizations.
+ This can be used to enable extra debugging code in development but not in
+ production. For example, it controls the behavior of the standard library's
+ `debug_assert!` macro.
* `target_arch = "..."`. Target CPU architecture, such as `"x86"`, `"x86_64"`
`"mips"`, `"powerpc"`, `"arm"`, or `"aarch64"`.
* `target_endian = "..."`. Endianness of the target CPU, either `"little"` or
crate. Stability markers are also attributes: `#[stable]`,
`#[unstable]`, and `#[deprecated]` are the three levels.
-* `static_assert` - The `#[static_assert]` functionality is experimental and
- unstable. The attribute can be attached to a `static` of
- type `bool` and the compiler will error if the `bool` is
- `false` at compile time. This version of this functionality
- is unintuitive and suboptimal.
-
* `start` - Allows use of the `#[start]` attribute, which changes the entry point
into a Rust program. This capability, especially the signature for the
annotated function, is subject to change.
Like the [arithmetic operators](#arithmetic-operators), bitwise operators are
syntactic sugar for calls to methods of built-in traits. This means that
bitwise operators can be overridden for user-defined types. The default
-meaning of the operators on standard types is given here.
+meaning of the operators on standard types is given here. Bitwise `&`, `|` and
+`^` applied to boolean arguments are equivalent to logical `&&`, `||` and `!=`
+evaluated in non-lazy fashion.
* `&`
- : And.
+ : Bitwise AND.
Calls the `bitand` method of the `std::ops::BitAnd` trait.
* `|`
- : Inclusive or.
+ : Bitwise inclusive OR.
Calls the `bitor` method of the `std::ops::BitOr` trait.
* `^`
- : Exclusive or.
+ : Bitwise exclusive OR.
Calls the `bitxor` method of the `std::ops::BitXor` trait.
* `<<`
: Left shift.
Calls the `shl` method of the `std::ops::Shl` trait.
* `>>`
- : Right shift.
+ : Right shift (arithmetic).
Calls the `shr` method of the `std::ops::Shr` trait.
#### Lazy boolean operators
An example of an `as` expression:
```
-# fn sum(v: &[f64]) -> f64 { 0.0 }
-# fn len(v: &[f64]) -> i32 { 0 }
+# fn sum(values: &[f64]) -> f64 { 0.0 }
+# fn len(values: &[f64]) -> i32 { 0 }
-fn avg(v: &[f64]) -> f64 {
- let sum: f64 = sum(v);
- let sz: f64 = len(v) as f64;
- return sum / sz;
+fn average(values: &[f64]) -> f64 {
+ let sum: f64 = sum(values);
+ let size: f64 = len(values) as f64;
+ sum / size
}
```
composed with the `=` operator. The expression `lval OP= val` is equivalent to
`lval = lval OP val`. For example, `x = x + 1` may be written as `x += 1`.
-Any such expression always has the [`unit`](#primitive-types) type.
+Any such expression always has the [`unit`](#tuple-types) type.
#### Operator precedence
The primitive types are the following:
* The boolean type `bool` with values `true` and `false`.
-* The machine types.
-* The machine-dependent integer and floating-point types.
+* The machine types (integer and floating-point).
+* The machine-dependent integer types.
#### Machine types
assert!(p.0 == 10);
```
+For historical reasons and convenience, the tuple type with no elements (`()`)
+is often called ‘unit’ or ‘the unit type’.
+
### Array, and Slice types
Rust has two different types for a list of items:
in the impl, `Self` refers to the value of type `String` that is the
receiver for a call to the method `make_string`.
+## Subtyping
+
+Subtyping is implicit and can occur at any stage in type checking or
+inference. Subtyping in Rust is very restricted and occurs only due to
+variance with respect to lifetimes and between types with higher ranked
+lifetimes. If we were to erase lifetimes from types, then the only subtyping
+would be due to type equality.
+
+Consider the following example: string literals always have `'static`
+lifetime. Nevertheless, we can assign `s` to `t`:
+
+```
+fn bar<'a>() {
+ let s: &'static str = "hi";
+ let t: &'a str = s;
+}
+```
+Since `'static` "lives longer" than `'a`, `&'static str` is a subtype of
+`&'a str`.
+
+## Type coercions
+
+Coercions are defined in [RFC401]. A coercion is implicit and has no syntax.
+
+[RFC401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md
+
+### Coercion sites
+
+A coercion can only occur at certain coercion sites in a program; these are
+typically places where the desired type is explicit or can be dervied by
+propagation from explicit types (without type inference). Possible coercion
+sites are:
+
+* `let` statements where an explicit type is given.
+
+ In `let _: U = e;`, `e` is coerced to have type `U`.
+
+* `static` and `const` statements (similar to `let` statements).
+
+* arguments for function calls.
+
+ The value being coerced is the
+ actual parameter and it is coerced to the type of the formal parameter. For
+ example, let `foo` be defined as `fn foo(x: U) { ... }` and call it as
+ `foo(e);`. Then `e` is coerced to have type `U`;
+
+* instantiations of struct or variant fields.
+
+ Assume we have a `struct
+ Foo { x: U }` and instantiate it as `Foo { x: e }`. Then `e` is coerced to
+ have type `U`.
+
+* function results (either the final line of a block if it is not semicolon
+terminated or any expression in a `return` statement).
+
+ In `fn foo() -> U { e }`, `e` is coerced to to have type `U`.
+
+If the expression in one of these coercion sites is a coercion-propagating
+expression, then the relevant sub-expressions in that expression are also
+coercion sites. Propagation recurses from these new coercion sites.
+Propagating expressions and their relevant sub-expressions are:
+
+* array literals, where the array has type `[U; n]`. Each sub-expression in
+the array literal is a coercion site for coercion to type `U`.
+
+* array literals with repeating syntax, where the array has type `[U; n]`. The
+repeated sub-expression is a coercion site for coercion to type `U`.
+
+* tuples, where a tuple is a coercion site to type `(U_0, U_1, ..., U_n)`.
+Each sub-expression is a coercion site to the respective type, e.g. the
+zeroth sub-expression is a coercion site to type `U_0`.
+
+* parenthesised sub-expressions (`(e)`). If the expression has type `U`, then
+the sub-expression is a coercion site to `U`.
+
+* blocks. If a block has type `U`, then the last expression in the block (if
+it is not semicolon-terminated) is a coercion site to `U`. This includes
+blocks which are part of control flow statements, such as `if`/`else`, if
+the block has a known type.
+
+### Coercion types
+
+Coercion is allowed between the following types:
+
+* `T` to `U` if `T` is a subtype of `U` (*reflexive case*).
+
+* `T_1` to `T_3` where `T_1` coerces to `T_2` and `T_2` coerces to `T_3`
+(*transitive case*).
+
+ Note that this is not fully supported yet
+
+* `&mut T` to `&T`.
+
+* `*mut T` to `*const T`.
+
+* `&T` to `*const T`.
+
+* `&mut T` to `*mut T`.
+
+* `&T` to `&U` if `T` implements `Deref<Target = U>`. For example:
+
+```rust
+use std::ops::Deref;
+
+struct CharContainer {
+ value: char
+}
+
+impl Deref for CharContainer {
+ type Target = char;
+
+ fn deref<'a>(&'a self) -> &'a char {
+ &self.value
+ }
+}
+
+fn foo(arg: &char) {}
+
+fn main() {
+ let x = &mut CharContainer { value: 'y' };
+ foo(x); //&mut CharContainer is coerced to &char.
+}
+```
+* `&mut T` to `&mut U` if `T` implements `DerefMut<Target = U>`.
+
+* TyCtor(`T`) to TyCtor(coerce_inner(`T`)), where TyCtor(`T`) is one of
+ - `&T`
+ - `&mut T`
+ - `*const T`
+ - `*mut T`
+ - `Box<T>`
+
+ and where
+ - coerce_inner(`[T, ..n]`) = `[T]`
+ - coerce_inner(`T`) = `U` where `T` is a concrete type which implements the
+ trait `U`.
+
+ In the future, coerce_inner will be recursively extended to tuples and
+ structs. In addition, coercions from sub-traits to super-traits will be
+ added. See [RFC401] for more details.
+
# Special traits
Several traits define special evaluation behavior.
The `Drop` trait provides a destructor, to be run whenever a value of this type
is to be destroyed.
+## The `Deref` trait
+
+The `Deref<Target = U>` trait allows a type to implicitly implement all the methods
+of the type `U`. When attempting to resolve a method call, the compiler will search
+the top-level type for the implementation of the called method. If no such method is
+found, `.deref()` is called and the compiler continues to search for the method
+implementation in the returned type `U`.
+
# Memory model
A Rust program's memory consists of a static set of *items* and a *heap*.
struct Info {
name: String,
- age: int,
- rating: int
+ age: i32,
+ rating: i32
}
fn write_info(info: &Info) -> Result<(), IoError> {
struct Info {
name: String,
- age: int,
- rating: int
+ age: i32,
+ rating: i32
}
fn write_info(info: &Info) -> Result<(), IoError> {
### The `Result`-`impl` pattern [FIXME]
> **[FIXME]** Document the way that the `io` module uses trait impls
-> on `IoResult` to painlessly propagate errors.
+> on `std::io::Result` to painlessly propagate errors.
type.
Methods have numerous advantages over functions:
+
* They do not need to be imported or qualified to be used: all you
need is a value of the appropriate type.
* Their invocation performs autoborrowing (including mutable borrows).
Prefer
```rust
-fn foo<T: Iterator<int>>(c: T) { ... }
+fn foo<T: Iterator<i32>>(c: T) { ... }
```
over any of
```rust
-fn foo(c: &[int]) { ... }
-fn foo(c: &Vec<int>) { ... }
-fn foo(c: &SomeOtherCollection<int>) { ... }
+fn foo(c: &[i32]) { ... }
+fn foo(c: &Vec<i32>) { ... }
+fn foo(c: &SomeOtherCollection<i32>) { ... }
```
if the function only needs to iterate over the data.
that the caller already owns, for example to re-use a buffer:
```rust
-fn read(&mut self, buf: &mut [u8]) -> IoResult<uint>
+fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize>
```
(From the [Reader trait](http://static.rust-lang.org/doc/master/std/io/trait.Reader.html#tymethod.read).)
Note that
[`ascii::Ascii`](http://static.rust-lang.org/doc/master/std/ascii/struct.Ascii.html)
is a _wrapper_ around `u8` that guarantees the highest bit is zero; see
-[newtype patterns]() for more details on creating typesafe wrappers.
+[newtype patterns](../types/newtype.md) for more details on creating typesafe wrappers.
Static enforcement usually comes at little run-time cost: it pushes the
costs to the boundaries (e.g. when a `u8` is first converted into an
```rust
struct SearchResult {
found: bool, // item in container?
- expected_index: uint // what would the item's index be?
+ expected_index: usize // what would the item's index be?
}
fn binary_search(&self, k: Key) -> SearchResult
or
```rust
-fn binary_search(&self, k: Key) -> (bool, uint)
+fn binary_search(&self, k: Key) -> (bool, usize)
```
over
Prefer
```rust
-fn use_mutex(m: sync::mutex::Mutex<int>) {
+fn use_mutex(m: sync::mutex::Mutex<i32>) {
let guard = m.lock();
do_work(guard);
drop(guard); // unlock the lock
over
```rust
-fn use_mutex(m: sync::mutex::Mutex<int>) {
+fn use_mutex(m: sync::mutex::Mutex<i32>) {
do_work(m.lock());
// do other work
}
```rust
let foo = match bar {
- Baz => 0,
+ Baz => 0,
Quux => 1
};
```
```rust
let foo;
match bar {
- Baz => {
+ Baz => {
foo = 0;
}
Quux => {
Prefer
```rust
-s.iter().map(|x| x * 2)
- .collect::<Vec<_>>()
+let v = s.iter().map(|x| x * 2)
+ .collect::<Vec<_>>();
```
over
fn from_iter<T: Iterator<A>>(iterator: T) -> SomeCollection<A>
```
-Here, the `Iterator` trait is specifies an interface that a type `T` must
+Here, the `Iterator` trait specifies an interface that a type `T` must
explicitly implement to be used by this generic function.
**Pros**:
fn print(&self) { println!("{:?}", *self) }
}
-impl Printable for int {}
+impl Printable for i32 {}
impl Printable for String {
fn print(&self) { println!("{}", *self) }
For example, consider a function `my_transform` that returns a compound iterator
type `Enumerate<Skip<vec::MoveItems<T>>>`. We wish to hide this type from the
-client, so that the client's view of the return type is roughly `Iterator<(uint,
+client, so that the client's view of the return type is roughly `Iterator<(usize,
T)>`. We can do so using the newtype pattern:
```rust
struct MyTransformResult<T>(Enumerate<Skip<vec::MoveItems<T>>>);
-impl<T> Iterator<(uint, T)> for MyTransformResult<T> { ... }
+impl<T> Iterator<(usize, T)> for MyTransformResult<T> { ... }
fn my_transform<T, Iter: Iterator<T>>(iter: Iter) -> MyTransformResult<T> {
...
value. When possible, choose a better name: e.g. `Command` is the builder for
`Process`.
2. The builder constructor should take as parameters only the data _required_ to
- to make a `T`.
+ make a `T`.
3. The builder should offer a suite of convenient methods for configuration,
including setting up compound inputs (like slices) incrementally.
These methods should return `self` to allow chaining.
}
/// Executes the command as a child process, which is returned.
- pub fn spawn(&self) -> IoResult<Process> {
+ pub fn spawn(&self) -> std::io::Result<Process> {
...
}
}
Terminate `return` statements with semicolons:
``` rust
-fn foo(bar: int) -> Option<int> {
+fn foo(bar: i32) -> Option<i32> {
if some_condition() {
return None;
}
use option::Option;
use mem;
-let i: int = mem::transmute(Option(0));
+let i: isize = mem::transmute(Option(0));
```
> **[FIXME]** Add rationale.
``` rust
#[deprecated = "Use `bar` instead."]
-fn foo(a: uint, b: uint) -> uint {
+fn foo(a: usize, b: usize) -> usize {
a + b
}
```
[rust]: http://rust-lang.org
-“The Rust Programming Language” is split into seven sections. This introduction
+“The Rust Programming Language” is split into eight sections. This introduction
is the first. After this:
* [Getting started][gs] - Set up your computer for Rust development.
still cannot call `push`. This is because we already have a reference to an
element of the vector, `y`. Mutating something while another reference exists
is dangerous, because we may invalidate the reference. In this specific case,
-when we create the vector, we may have only allocated space for three elements.
-Adding a fourth would mean allocating a new chunk of memory for all those elements,
+when we create the vector, we may have only allocated space for two elements.
+Adding a third would mean allocating a new chunk of memory for all those elements,
copying the old values over, and updating the internal pointer to that memory.
That all works just fine. The problem is that `y` wouldn’t get updated, and so
we’d have a ‘dangling pointer’. That’s bad. Any use of `y` would be an error in
* [Learn Rust](learn-rust.md)
* [Guessing Game](guessing-game.md)
* [Dining Philosophers](dining-philosophers.md)
- * [Rust inside other languages](rust-inside-other-languages.md)
+ * [Rust Inside Other Languages](rust-inside-other-languages.md)
* [Effective Rust](effective-rust.md)
* [The Stack and the Heap](the-stack-and-the-heap.md)
* [Testing](testing.md)
Now, our clients can be abstract over a given `Graph`:
```rust,ignore
-fn distance<G: Graph>(graph: &G, start: &G::N, end: &G::N) -> uint { ... }
+fn distance<G: Graph>(graph: &G, start: &G::N, end: &G::N) -> u32 { ... }
```
No need to deal with the `E`dge type here!
Rust supports benchmark tests, which can test the performance of your
code. Let's make our `src/lib.rs` look like this (comments elided):
-```{rust,ignore}
+```rust,ignore
#![feature(test)]
extern crate test;
compiler might recognize that some calculation has no external effects and
remove it entirely.
-```{rust,ignore}
+```rust,ignore
#![feature(test)]
extern crate test;
For most types, when you want to take an owned or borrowed type, a `&T` is
enough. But one area where `Borrow` is effective is when there’s more than one
-kind of borrowed value. Slices are an area where this is especially true: you
-can have both an `&[T]` or a `&mut [T]`. If we wanted to accept both of these
-types, `Borrow` is up for it:
+kind of borrowed value. This is especially true of references and slices: you
+can have both an `&T` or a `&mut T`. If we wanted to accept both of these types,
+`Borrow` is up for it:
-```
+```rust
use std::borrow::Borrow;
use std::fmt::Display;
pattern. The unstable `box` keyword can be used to both create and destructure
a `Box`. An example usage would be:
-```
+```rust
#![feature(box_syntax, box_patterns)]
fn main() {
In many languages with pointers, you'd return a pointer from a function
so as to avoid copying a large data structure. For example:
-```{rust}
+```rust
struct BigStruct {
one: i32,
two: i32,
```
The idea is that by passing around a box, you're only copying a pointer, rather
-than the hundred `int`s that make up the `BigStruct`.
+than the hundred `i32`s that make up the `BigStruct`.
This is an antipattern in Rust. Instead, write this:
assert_eq!(4, plus_two(2));
```
-You’ll notice a few things about closures that are a bit different than regular
-functions defined with `fn`. The first of which is that we did not need to
+You’ll notice a few things about closures that are a bit different from regular
+functions defined with `fn`. The first is that we did not need to
annotate the types of arguments the closure takes or the values it returns. We
can:
While specifying the full type for named functions is helpful with things like
documentation and type inference, the types of closures are rarely documented
since they’re anonymous, and they don’t cause the kinds of error-at-a-distance
-that inferring named function types can.
+problems that inferring named function types can.
The second is that the syntax is similar, but a bit different. I’ve added spaces
-here to make them look a little closer:
+here for easier comparison:
```rust
-fn plus_one_v1 (x: i32 ) -> i32 { x + 1 }
-let plus_one_v2 = |x: i32 | -> i32 { x + 1 };
-let plus_one_v3 = |x: i32 | x + 1 ;
+fn plus_one_v1 (x: i32) -> i32 { x + 1 }
+let plus_one_v2 = |x: i32| -> i32 { x + 1 };
+let plus_one_v3 = |x: i32| x + 1 ;
```
-Small differences, but they’re similar in ways.
+Small differences, but they’re similar.
# Closures and their environment
fn main() {
let mut num = 5;
let plus_num = |x| x + num;
-
+
let y = &mut num;
}
^
```
If your closure requires it, however, Rust will take ownership and move
-the environment instead:
+the environment instead. This doesn’t work:
```rust,ignore
let nums = vec![1, 2, 3];
println!("{:?}", nums);
```
-This gives us:
+We get this error:
```text
note: `nums` moved into closure environment here because it has type
`[closure(()) -> collections::vec::Vec<i32>]`, which is non-copyable
let takes_nums = || nums;
- ^~~~~~~
+ ^~~~~~~
```
`Vec<T>` has ownership over its contents, and therefore, when we refer to it
```rust
let mut num = 5;
-{
+{
let mut add_num = |x: i32| num += x;
add_num(5);
```rust
let mut num = 5;
-{
+{
let mut add_num = move |x: i32| num += x;
add_num(5);
try to return a closure from a function:
```rust,ignore
-fn factory() -> (Fn(i32) -> Vec<i32>) {
- let vec = vec![1, 2, 3];
+fn factory() -> (Fn(i32) -> i32) {
+ let num = 5;
- |n| vec.push(n)
+ |x| x + num
}
let f = factory();
-let answer = f(4);
-assert_eq!(vec![1, 2, 3, 4], answer);
+let answer = f(1);
+assert_eq!(6, answer);
```
This gives us these long, related errors:
```text
error: the trait `core::marker::Sized` is not implemented for the type
-`core::ops::Fn(i32) -> collections::vec::Vec<i32>` [E0277]
-f = factory();
-^
-note: `core::ops::Fn(i32) -> collections::vec::Vec<i32>` does not have a
-constant size known at compile-time
-f = factory();
-^
-error: the trait `core::marker::Sized` is not implemented for the type
-`core::ops::Fn(i32) -> collections::vec::Vec<i32>` [E0277]
-factory() -> (Fn(i32) -> Vec<i32>) {
- ^~~~~~~~~~~~~~~~~~~~~
-note: `core::ops::Fn(i32) -> collections::vec::Vec<i32>` does not have a constant size known at compile-time
-fa ctory() -> (Fn(i32) -> Vec<i32>) {
- ^~~~~~~~~~~~~~~~~~~~~
-
+`core::ops::Fn(i32) -> i32` [E0277]
+fn factory() -> (Fn(i32) -> i32) {
+ ^~~~~~~~~~~~~~~~
+note: `core::ops::Fn(i32) -> i32` does not have a constant size known at compile-time
+fn factory() -> (Fn(i32) -> i32) {
+ ^~~~~~~~~~~~~~~~
+error: the trait `core::marker::Sized` is not implemented for the type `core::ops::Fn(i32) -> i32` [E0277]
+let f = factory();
+ ^
+note: `core::ops::Fn(i32) -> i32` does not have a constant size known at compile-time
+let f = factory();
+ ^
```
In order to return something from a function, Rust needs to know what
have a known size. So we’d write this:
```rust,ignore
-fn factory() -> &(Fn(i32) -> Vec<i32>) {
- let vec = vec![1, 2, 3];
+fn factory() -> &(Fn(i32) -> i32) {
+ let num = 5;
- |n| vec.push(n)
+ |x| x + num
}
let f = factory();
-let answer = f(4);
-assert_eq!(vec![1, 2, 3, 4], answer);
+let answer = f(1);
+assert_eq!(6, answer);
```
But we get another error:
We use a trait object, by `Box`ing up the `Fn`. There’s just one last problem:
```text
-error: `num` does not live long enough
+error: closure may outlive the current function, but it borrows `num`,
+which is owned by the current function [E0373]
Box::new(|x| x + num)
^~~~~~~~~~~
```
/// let five = 5;
///
/// assert_eq!(6, add_one(5));
+/// # fn add_one(x: i32) -> i32 {
+/// # x + 1
+/// # }
/// ```
fn add_one(x: i32) -> i32 {
x + 1
Rust's standard library provides a library for threads, which allow you to
run Rust code in parallel. Here's a basic example of using `std::thread`:
-```
+```rust
use std::thread;
fn main() {
new thread. It returns a handle to the thread, that can be used to
wait for the child thread to finish and extract its result:
-```
+```rust
use std::thread;
fn main() {
We can use `Arc<T>` to fix this. Here's the working version:
-```
+```rust
use std::sync::{Arc, Mutex};
use std::thread;
Here's a version of our code that uses channels for synchronization, rather
than waiting for a specific time:
-```
+```rust
use std::sync::{Arc, Mutex};
use std::thread;
use std::sync::mpsc;
While this channel is just sending a generic signal, we can send any data that
is `Send` over the channel!
-```
+```rust
use std::thread;
use std::sync::mpsc;
A `panic!` will crash the currently executing thread. You can use Rust's
threads as a simple isolation mechanism:
-```
+```rust
use std::thread;
let result = thread::spawn(move || {
As for how to enable or disable these switches, if you’re using Cargo,
they get set in the [`[features]` section][features] of your `Cargo.toml`:
-[features]: http://doc.crates.io/manifest.html#the-[features]-section
+[features]: http://doc.crates.io/manifest.html#the-%5Bfeatures%5D-section
```toml
[features]
Unlike [`let`][let] bindings, you must annotate the type of a `static`.
-[let]: variable-bindings.html
-
Statics live for the entire lifetime of a program, and therefore any
-reference stored in a constant has a [`’static` lifetime][lifetimes]:
+reference stored in a constant has a [`'static` lifetime][lifetimes]:
```rust
static NAME: &'static str = "Steve";
[unsafe]: unsafe.html
-Furthermore, any type stored in a `static` must be `Sync`.
+Furthermore, any type stored in a `static` must be `Sync`, and may not have
+a [`Drop`][drop] implementation.
+
+[drop]: drop.html
# Initializing
rare that you actually want a memory location associated with your constant,
and using a const allows for optimizations like constant propagation not only
in your crate but downstream crates.
-
-A const can be thought of as a `#define` in C: it has metadata overhead but it
-has no runtime overhead. “Should I use a #define or a static in C,” is largely
-the same question as whether you should use a const or a static in Rust.
To define each of our modules, we use the `mod` keyword. Let’s make our
`src/lib.rs` look like this:
-```
+```rust
mod english {
mod greetings {
}
Instead of declaring a module like this:
-```{rust,ignore}
+```rust,ignore
mod english {
// contents of our module go here
}
We can instead declare our module like this:
-```{rust,ignore}
+```rust,ignore
mod english;
```
`src/lib.rs` is our crate root, and looks like this:
-```{rust,ignore}
+```rust,ignore
mod english;
mod japanese;
```
chosen the second. Both `src/english/mod.rs` and `src/japanese/mod.rs` look
like this:
-```{rust,ignore}
+```rust,ignore
mod greetings;
mod farewells;
```
keyword. Let’s focus on the `english` module first, so let’s reduce our `src/main.rs`
to just this:
-```{rust,ignore}
+```rust,ignore
extern crate phrases;
fn main() {
In our `src/lib.rs`, let’s add `pub` to the `english` module declaration:
-```{rust,ignore}
+```rust,ignore
pub mod english;
mod japanese;
```
And in our `src/english/mod.rs`, let’s make both `pub`:
-```{rust,ignore}
+```rust,ignore
pub mod greetings;
pub mod farewells;
```
In our `src/english/greetings.rs`, let’s add `pub` to our `fn` declaration:
-```{rust,ignore}
+```rust,ignore
pub fn hello() -> String {
"Hello!".to_string()
}
And also in `src/english/farewells.rs`:
-```{rust,ignore}
+```rust,ignore
pub fn goodbye() -> String {
"Goodbye.".to_string()
}
Rust has a `use` keyword, which allows us to import names into our local scope.
Let’s change our `src/main.rs` to look like this:
-```{rust,ignore}
+```rust,ignore
extern crate phrases;
use phrases::english::greetings;
considered best practice to import the module, rather than the function directly. In
other words, you _can_ do this:
-```{rust,ignore}
+```rust,ignore
extern crate phrases;
use phrases::english::greetings::hello;
error. For example, if we made the `japanese` functions public, and tried to do
this:
-```{rust,ignore}
+```rust,ignore
extern crate phrases;
use phrases::english::greetings::hello;
If we’re importing multiple names from the same module, we don’t have to type it out
twice. Instead of this:
-```{rust,ignore}
+```rust,ignore
use phrases::english::greetings;
use phrases::english::farewells;
```
We can use this shortcut:
-```{rust,ignore}
+```rust,ignore
use phrases::english::{greetings, farewells};
```
Let’s look at an example. Modify your `src/main.rs` to read like this:
-```{rust,ignore}
+```rust,ignore
extern crate phrases;
use phrases::english::{greetings,farewells};
Then, modify your `src/lib.rs` to make the `japanese` mod public:
-```{rust,ignore}
+```rust,ignore
pub mod english;
pub mod japanese;
```
Next, make the two functions public, first in `src/japanese/greetings.rs`:
-```{rust,ignore}
+```rust,ignore
pub fn hello() -> String {
"こんにちは".to_string()
}
And then in `src/japanese/farewells.rs`:
-```{rust,ignore}
+```rust,ignore
pub fn goodbye() -> String {
"さようなら".to_string()
}
Finally, modify your `src/japanese/mod.rs` to read like this:
-```{rust,ignore}
+```rust,ignore
pub use self::greetings::hello;
pub use self::farewells::goodbye;
For our second project, let’s look at a classic concurrency problem. It’s
called ‘the dining philosophers’. It was originally conceived by Dijkstra in
-1965, but we’ll use the version from [this paper][paper] by Tony Hoare in 1985.
+1965, but we’ll use a lightly adapted version from [this paper][paper] by Tony
+Hoare in 1985.
[paper]: http://www.usingcsp.com/cspbook.pdf
> In ancient times, a wealthy philanthropist endowed a College to accommodate
-> five eminent philosophers. Each philosopher had a room in which he could
-> engage in his professional activity of thinking; there was also a common
+> five eminent philosophers. Each philosopher had a room in which they could
+> engage in their professional activity of thinking; there was also a common
> dining room, furnished with a circular table, surrounded by five chairs, each
> labelled by the name of the philosopher who was to sit in it. They sat
> anticlockwise around the table. To the left of each philosopher there was
> laid a golden fork, and in the centre stood a large bowl of spaghetti, which
-> was constantly replenished. A philosopher was expected to spend most of his
-> time thinking; but when he felt hungry, he went to the dining room, sat down
-> in his own chair, picked up his own fork on his left, and plunged it into the
-> spaghetti. But such is the tangled nature of spaghetti that a second fork is
-> required to carry it to the mouth. The philosopher therefore had also to pick
-> up the fork on his right. When we was finished he would put down both his
-> forks, get up from his chair, and continue thinking. Of course, a fork can be
-> used by only one philosopher at a time. If the other philosopher wants it, he
-> just has to wait until the fork is available again.
+> was constantly replenished. A philosopher was expected to spend most of
+> their time thinking; but when they felt hungry, they went to the dining
+> room, sat down in their own chair, picked up their own fork on their left,
+> and plunged it into the spaghetti. But such is the tangled nature of
+> spaghetti that a second fork is required to carry it to the mouth. The
+> philosopher therefore had also to pick up the fork on their right. When
+> they were finished they would put down both their forks, get up from their
+> chair, and continue thinking. Of course, a fork can be used by only one
+> philosopher at a time. If the other philosopher wants it, they just have
+> to wait until the fork is available again.
This classic problem shows off a few different elements of concurrency. The
reason is that it's actually slightly tricky to implement: a simple
}
fn main() {
- let p1 = Philosopher::new("Baruch Spinoza");
+ let p1 = Philosopher::new("Judith Butler");
let p2 = Philosopher::new("Gilles Deleuze");
let p3 = Philosopher::new("Karl Marx");
- let p4 = Philosopher::new("Friedrich Nietzsche");
+ let p4 = Philosopher::new("Emma Goldman");
let p5 = Philosopher::new("Michel Foucault");
}
```
# }
#
fn main() {
- let p1 = Philosopher::new("Baruch Spinoza");
+ let p1 = Philosopher::new("Judith Butler");
let p2 = Philosopher::new("Gilles Deleuze");
let p3 = Philosopher::new("Karl Marx");
- let p4 = Philosopher::new("Friedrich Nietzsche");
+ let p4 = Philosopher::new("Emma Goldman");
let p5 = Philosopher::new("Michel Foucault");
}
```
# name: String,
# }
fn main() {
- let p1 = Philosopher { name: "Baruch Spinoza".to_string() };
+ let p1 = Philosopher { name: "Judith Butler".to_string() };
let p2 = Philosopher { name: "Gilles Deleuze".to_string() };
let p3 = Philosopher { name: "Karl Marx".to_string() };
- let p4 = Philosopher { name: "Friedrich Nietzche".to_string() };
+ let p4 = Philosopher { name: "Emma Goldman".to_string() };
let p5 = Philosopher { name: "Michel Foucault".to_string() };
}
```
fn main() {
let philosophers = vec![
- Philosopher::new("Baruch Spinoza"),
+ Philosopher::new("Judith Butler"),
Philosopher::new("Gilles Deleuze"),
Philosopher::new("Karl Marx"),
- Philosopher::new("Friedrich Nietzsche"),
+ Philosopher::new("Emma Goldman"),
Philosopher::new("Michel Foucault"),
];
output:
```text
-Baruch Spinoza is done eating.
+Judith Butler is done eating.
Gilles Deleuze is done eating.
Karl Marx is done eating.
-Friedrich Nietzsche is done eating.
+Emma Goldman is done eating.
Michel Foucault is done eating.
```
fn main() {
let philosophers = vec![
- Philosopher::new("Baruch Spinoza"),
+ Philosopher::new("Judith Butler"),
Philosopher::new("Gilles Deleuze"),
Philosopher::new("Karl Marx"),
- Philosopher::new("Friedrich Nietzsche"),
+ Philosopher::new("Emma Goldman"),
Philosopher::new("Michel Foucault"),
];
We now print out two messages, with a `sleep_ms()` in the middle. This will
simulate the time it takes a philosopher to eat.
-If you run this program, You should see each philosopher eat in turn:
+If you run this program, you should see each philosopher eat in turn:
```text
-Baruch Spinoza is eating.
-Baruch Spinoza is done eating.
+Judith Butler is eating.
+Judith Butler is done eating.
Gilles Deleuze is eating.
Gilles Deleuze is done eating.
Karl Marx is eating.
Karl Marx is done eating.
-Friedrich Nietzsche is eating.
-Friedrich Nietzsche is done eating.
+Emma Goldman is eating.
+Emma Goldman is done eating.
Michel Foucault is eating.
Michel Foucault is done eating.
```
fn main() {
let philosophers = vec![
- Philosopher::new("Baruch Spinoza"),
+ Philosopher::new("Judith Butler"),
Philosopher::new("Gilles Deleuze"),
Philosopher::new("Karl Marx"),
- Philosopher::new("Friedrich Nietzsche"),
+ Philosopher::new("Emma Goldman"),
Philosopher::new("Michel Foucault"),
];
ownership of the values it’s capturing. Primarily, the `p` variable of the
`map` function.
-Inside the thread, all we do is call `eat()` on `p`.
+Inside the thread, all we do is call `eat()` on `p`. Also note that the call to `thread::spawn` lacks a trailing semicolon, making this an expression. This distinction is important, yielding the correct return value. For more details, read [Expressions vs. Statements][es].
+
+[es]: functions.html#expressions-vs.-statements
```rust,ignore
}).collect();
```text
Gilles Deleuze is eating.
Gilles Deleuze is done eating.
-Friedrich Nietzsche is eating.
-Friedrich Nietzsche is done eating.
+Emma Goldman is eating.
+Emma Goldman is done eating.
Michel Foucault is eating.
-Baruch Spinoza is eating.
-Baruch Spinoza is done eating.
+Judith Butler is eating.
+Judith Butler is done eating.
Karl Marx is eating.
Karl Marx is done eating.
Michel Foucault is done eating.
}
```
-This `Table` has an vector of `Mutex`es. A mutex is a way to control
+This `Table` has a vector of `Mutex`es. A mutex is a way to control
concurrency: only one thread can access the contents at once. This is exactly
the property we need with our forks. We use an empty tuple, `()`, inside the
mutex, since we’re not actually going to use the value, just hold onto it.
]});
let philosophers = vec![
- Philosopher::new("Baruch Spinoza", 0, 1),
+ Philosopher::new("Judith Butler", 0, 1),
Philosopher::new("Gilles Deleuze", 1, 2),
Philosopher::new("Karl Marx", 2, 3),
- Philosopher::new("Friedrich Nietzsche", 3, 4),
+ Philosopher::new("Emma Goldman", 3, 4),
Philosopher::new("Michel Foucault", 0, 4),
];
```rust,ignore
let philosophers = vec![
- Philosopher::new("Baruch Spinoza", 0, 1),
+ Philosopher::new("Judith Butler", 0, 1),
Philosopher::new("Gilles Deleuze", 1, 2),
Philosopher::new("Karl Marx", 2, 3),
- Philosopher::new("Friedrich Nietzsche", 3, 4),
+ Philosopher::new("Emma Goldman", 3, 4),
Philosopher::new("Michel Foucault", 0, 4),
];
```
Finally, inside of our `map()`/`collect()` loop, we call `table.clone()`. The
`clone()` method on `Arc<T>` is what bumps up the reference count, and when it
-goes out of scope, it decrements the count. You’ll notice we can introduce a
-new binding to `table` here, and it will shadow the old one. This is often used
-so that you don’t need to come up with two unique names.
+goes out of scope, it decrements the count. This is needed so that we know how
+many references to `table` exist across our threads. If we didn’t have a count,
+we wouldn’t know how to deallocate it.
+
+You’ll notice we can introduce a new binding to `table` here, and it will
+shadow the old one. This is often used so that you don’t need to come up with
+two unique names.
With this, our program works! Only two philosophers can eat at any one time,
and so you’ll get some output like this:
```text
Gilles Deleuze is eating.
-Friedrich Nietzsche is eating.
-Friedrich Nietzsche is done eating.
+Emma Goldman is eating.
+Emma Goldman is done eating.
Gilles Deleuze is done eating.
-Baruch Spinoza is eating.
+Judith Butler is eating.
Karl Marx is eating.
-Baruch Spinoza is done eating.
+Judith Butler is done eating.
Michel Foucault is eating.
Karl Marx is done eating.
Michel Foucault is done eating.
Rust keeps track of these comments, and uses them when generating
documentation. This is important when documenting things like enums:
-```
+```rust
/// The `Option` type. See [the module level documentation](../) for more.
enum Option<T> {
/// No value
Anyway, let's cover each part of this comment in detail:
-```
+```rust
/// Constructs a new `Rc<T>`.
# fn foo() {}
```
The first line of a documentation comment should be a short summary of its
functionality. One sentence. Just the basics. High level.
-```
+```rust
///
/// Other details about constructing `Rc<T>`s, maybe describing complicated
/// semantics, maybe additional options, all kinds of stuff.
#### Special sections
-```
-/// # Examples
-# fn foo() {}
-```
-
Next, are special sections. These are indicated with a header, `#`. There
are three kinds of headers that are commonly used. They aren't special syntax,
just convention, for now.
-```
+```rust
/// # Panics
# fn foo() {}
```
least. If your function has a non-trivial contract like this, that is
detected/enforced by panics, documenting it is very important.
-```
+```rust
/// # Failures
# fn foo() {}
```
slightly less important than `Panics`, because failure is encoded into the type
system, but it's still a good thing to do.
-```
+```rust
/// # Safety
# fn foo() {}
```
If your function is `unsafe`, you should explain which invariants the caller is
responsible for upholding.
-```
+```rust
/// # Examples
///
/// ```
code block annotations, which we'll talk about in a moment, and can have
more than one section:
-```
+```rust
/// # Examples
///
/// Simple `&str` patterns:
To write some Rust code in a comment, use the triple graves:
-```
+```rust
/// ```
/// println!("Hello, world");
/// ```
If you want something that's not Rust code, you can add an annotation:
-```
+```rust
/// ```c
/// printf("Hello, world\n");
/// ```
Let's discuss our sample example documentation:
-```
+```rust
/// ```
/// println!("Hello, world");
/// ```
automatically add a main() wrapper around your code, and in the right place.
For example:
-```
+```rust
/// ```
/// use std::rc::Rc;
///
This will end up testing:
-```
+```rust
fn main() {
use std::rc::Rc;
let five = Rc::new(5);
looks different than the output:
-```
+```rust
/// Some documentation.
# fn foo() {}
```
longer examples in detail, while still preserving the testability of your
documentation. For example, this code:
-```
+```rust
let x = 5;
let y = 6;
println!("{}", x + y);
First, we set `x` to five:
-```
+```rust
let x = 5;
# let y = 6;
# println!("{}", x + y);
Next, we set `y` to six:
-```
+```rust
# let x = 5;
let y = 6;
# println!("{}", x + y);
Finally, we print the sum of `x` and `y`:
-```
+```rust
# let x = 5;
# let y = 6;
println!("{}", x + y);
Here’s an example of documenting a macro:
-```
+```rust
/// Panic with a given message unless an expression evaluates to true.
///
/// # Examples
There are a few more annotations that are useful to help `rustdoc` do the right
thing when testing your code:
-```
+```rust
/// ```ignore
/// fn foo() {
/// ```
with `text` if it's not code, or using `#`s to get a working example that
only shows the part you care about.
-```
+```rust
/// ```should_panic
/// assert!(false);
/// ```
`should_panic` tells `rustdoc` that the code should compile correctly, but
not actually pass as a test.
-```
+```rust
/// ```no_run
/// loop {
/// println!("Hello, world");
Rust has another kind of doc comment, `//!`. This comment doesn't document the next item, but the enclosing item. In other words:
-```
+```rust
mod foo {
//! This is documentation for the `foo` module.
//!
This is where you'll see `//!` used most often: for module documentation. If
you have a module in `foo.rs`, you'll often open its code and see this:
-```
+```rust
//! A module for using `foo`s.
//!
//! The `foo` module contains a lot of useful functionality blah blah blah
When you write documentation in Markdown files, you don't need to prefix
the documentation with comments. For example:
-```
+```rust
/// # Examples
///
/// ```
At a deeper level, documentation comments are sugar for documentation attributes:
-```
+```rust
/// this
# fn foo() {}
are the same, as are these:
-```
+```rust
//! this
#![doc="/// this"]
You can control a few aspects of the HTML that `rustdoc` generates through the
`#![doc]` version of the attribute:
-```
+```rust
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/")];
+ html_root_url = "http://doc.rust-lang.org/")]
```
This sets a few different options, with a logo, favicon, and a root URL.
[match]: match.html
[if-let]: if-let.html
[traits]: traits.html
+
+# Constructors as functions
+
+An enum’s constructors can also be used like functions. For example:
+
+```rust
+# enum Message {
+# Write(String),
+# }
+let m = Message::Write("Hello, world".to_string());
+```
+
+Is the same as
+
+```rust
+# enum Message {
+# Write(String),
+# }
+fn foo(x: String) -> Message {
+ Message::Write(x)
+}
+
+let x = foo("Hello, world".to_string());
+```
+
+This is not immediately useful to us, but when we get to
+[`closures`][closures], we’ll talk about passing functions as arguments to
+other functions. For example, with [`iterators`][iterators], we can do this
+to convert a vector of `String`s into a vector of `Message::Write`s:
+
+```rust
+# enum Message {
+# Write(String),
+# }
+
+let v = vec!["Hello".to_string(), "World".to_string()];
+
+let v1: Vec<Message> = v.into_iter().map(Message::Write).collect();
+```
+
+[closures]: closures.html
+[iterators]: iterators.html
is very wrong. Wrong enough that we can't continue with things in the current
state. Another example is using the `unreachable!()` macro:
-```{rust,ignore}
+```rust,ignore
enum Event {
NewRelease,
}
In the case of an error that is unexpected and not recoverable, the `panic!`
macro will induce a panic. This will crash the current thread, and give an error:
-```{rust,ignore}
+```rust,ignore
panic!("boom");
```
If we don't want to handle this error, and would rather just abort the program,
we can use the `unwrap()` method:
-```{rust,ignore}
+```rust,ignore
io::stdin().read_line(&mut buffer).unwrap();
```
There's another way of doing this that's a bit nicer than `unwrap()`:
-```{rust,ignore}
+```rust,ignore
let mut buffer = String::new();
-let input = io::stdin().read_line(&mut buffer)
- .ok()
- .expect("Failed to read line");
+let num_bytes_read = io::stdin().read_line(&mut buffer)
+ .ok()
+ .expect("Failed to read line");
```
`ok()` converts the `Result` into an `Option`, and `expect()` does the same
}
fn write_info(info: &Info) -> io::Result<()> {
- let mut file = try!(File::create("my_best_friends.txt"));
+ let mut file = File::create("my_best_friends.txt").unwrap();
try!(writeln!(&mut file, "name: {}", info.name));
try!(writeln!(&mut file, "age: {}", info.age));
length is number of elements currently contained, and the capacity is the total size in elements of
the allocated memory. The length is less than or equal to the capacity.
-```
+```rust
# #![feature(libc)]
# extern crate libc;
# use libc::{c_int, size_t};
`snappy_compress` function as an output parameter. An output parameter is also passed to retrieve
the true length after compression for setting the length.
-```
+```rust
# #![feature(libc)]
# extern crate libc;
# use libc::{size_t, c_int};
Decompression is similar, because snappy stores the uncompressed size as part of the compression
format and `snappy_uncompressed_length` will retrieve the exact buffer size required.
-```
+```rust
# #![feature(libc)]
# extern crate libc;
# use libc::{size_t, c_int};
Rust object. This could be the object that represents the wrapper for the
respective C object.
-This can be achieved by passing an unsafe pointer to the object down to the
+This can be achieved by passing an raw pointer to the object down to the
C library. The C library can then include the pointer to the Rust object in
the notification. This will allow the callback to unsafely access the
referenced Rust object.
The different `kind` values are meant to differentiate how the native library
participates in linkage. From a linkage perspective, the rust compiler creates
two flavors of artifacts: partial (rlib/staticlib) and final (dylib/binary).
-Native dynamic libraries and frameworks are propagated to the final artifact
-boundary, while static libraries are not propagated at all.
+Native dynamic library and framework dependencies are propagated to the final
+artifact boundary, while static library dependencies are not propagated at
+all, because the static libraries are integrated directly into the subsequent
+artifact.
A few examples of how this model can be used are:
# Unsafe blocks
-Some operations, like dereferencing unsafe pointers or calling functions that have been marked
+Some operations, like dereferencing raw pointers or calling functions that have been marked
unsafe are only allowed inside unsafe blocks. Unsafe blocks isolate unsafety and are a promise to
the compiler that the unsafety does not leak out of the block.
Unsafe functions, on the other hand, advertise it to the world. An unsafe function is written like
this:
-```
+```rust
unsafe fn kaboom(ptr: *const i32) -> i32 { *ptr }
```
calling foreign functions. Some foreign functions, most notably the Windows API, use other calling
conventions. Rust provides a way to tell the compiler which convention to use:
-```
+```rust
# #![feature(libc)]
extern crate libc;
You may wish to compile Rust code in a way so that it can be called from C. This is
fairly easy, but requires a few things:
-```
+```rust
#[no_mangle]
pub extern fn hello_rust() -> *const u8 {
"Hello, world!\0".as_ptr()
discussed above in "[Foreign Calling
Conventions](ffi.html#foreign-calling-conventions)". The `no_mangle`
attribute turns off Rust's name mangling, so that it is easier to link to.
+
+# FFI and panics
+
+It’s important to be mindful of `panic!`s when working with FFI. This code,
+when called from C, will `abort`:
+
+```rust
+#[no_mangle]
+pub extern fn oh_no() -> ! {
+ panic!("Oops!");
+}
+# fn main() {}
+```
+
+If you’re writing code that may panic, you should run it in another thread,
+so that the panic doesn’t bubble up to C:
+
+```rust
+use std::thread;
+
+#[no_mangle]
+pub extern fn oh_no() -> i32 {
+ let h = thread::spawn(|| {
+ panic!("Oops!");
+ });
+
+ match h.join() {
+ Ok(_) => 1,
+ Err(_) => 0,
+ }
+}
+# fn main() {}
+```
+
Rust does not have the “C-style” `for` loop on purpose. Manually controlling
each element of the loop is complicated and error prone, even for experienced C
developers.
+
+# Enumerate
+
+When you need to keep track of how many times you already looped, you can use the `.enumerate()` function.
+
+## On ranges:
+
+```rust
+for (i,j) in (5..10).enumerate() {
+ println!("i = {} and j = {}", i, j);
+}
+```
+
+Outputs:
+
+```text
+i = 0 and j = 5
+i = 1 and j = 6
+i = 2 and j = 7
+i = 3 and j = 8
+i = 4 and j = 9
+```
+
+Don't forget to add the parentheses around the range.
+
+## On iterators:
+
+```rust
+# let lines = "hello\nworld".lines();
+for (linenumber, line) in lines.enumerate() {
+ println!("{}: {}", linenumber, line);
+}
+```
+
+Outputs:
+
+```text
+0: Content of line one
+1: Content of line two
+2: Content of line tree
+3: Content of line four
+```
Note that assigning to an already-bound variable (e.g. `y = 5`) is still an
expression, although its value is not particularly useful. Unlike other
languages where an assignment evaluates to the assigned value (e.g. `5` in the
-previous example), in Rust the value of an assignment is an empty tuple `()`:
+previous example), in Rust the value of an assignment is an empty tuple `()`
+because the assigned value can have [just one owner](ownership.html), and any
+other returned value would be too surprising:
-```
+```rust
let mut y = 5;
let x = (y = 6); // x has the value `()`, not `6`
Rust has some special syntax for ‘diverging functions’, which are functions that
do not return:
-```
+```rust
fn diverges() -> ! {
panic!("This function never returns!");
}
% Generics
Sometimes, when writing a function or data type, we may want it to work for
-multiple types of arguments. Luckily, Rust has a feature that gives us a better
-way: generics. Generics are called ‘parametric polymorphism’ in type theory,
+multiple types of arguments. In Rust, we can do this with generics.
+Generics are called ‘parametric polymorphism’ in type theory,
which means that they are types or functions that have multiple forms (‘poly’
is multiple, ‘morph’ is form) over a given parameter (‘parametric’).
You can store a generic type in a `struct` as well:
-```
+```rust
struct Point<T> {
x: T,
y: T,
When a compiler is compiling your program, it does a number of different
things. One of the things that it does is turn the text of your program into an
-‘abstract syntax tree’, or‘AST’. This tree is a representation of the
+‘abstract syntax tree’, or ‘AST’. This tree is a representation of the
structure of your program. For example, `2 + 3` can be turned into a tree:
```text
```rust
fn main() {
- println!("Hello, world!")
+ println!("Hello, world!");
}
```
For example, they’re [immutable][immutable] by default. That’s why our example
uses `mut`: it makes a binding mutable, rather than immutable. `let` doesn’t
take a name on the left hand side, it actually accepts a
-‘[pattern][patterns]’. We’ll use patterns more later. It’s easy enough
+‘[pattern][patterns]’. We’ll use patterns later. It’s easy enough
to use for now:
-```
+```rust
let foo = 5; // immutable.
let mut bar = 5; // mutable
```
Cargo uses the dependencies section to know what dependencies on external
crates you have, and what versions you require. In this case, we’ve used version `0.3.0`.
Cargo understands [Semantic Versioning][semver], which is a standard for writing version
-numbers. If we wanted to use the latest version we could use `*` or we could use a range
+numbers. If we wanted to use the latest version we could use `*` or we could use a range
of versions. [Cargo’s documentation][cargodoc] contains more details.
[semver]: http://semver.org
should be a `String`, and so it doesn’t make us write out the type. And with
our `secret_number`, there are a number of types which can have a value
between one and a hundred: `i32`, a thirty-two-bit number, or `u32`, an
-unsigned thirty-two-bit number, or `i64`, a sixty-four-bit number. Or others.
+unsigned thirty-two-bit number, or `i64`, a sixty-four-bit number or others.
So far, that hasn’t mattered, and so Rust defaults to an `i32`. However, here,
Rust doesn’t know how to compare the `guess` and the `secret_number`. They
need to be the same type. Ultimately, we want to convert the `String` we
```
Note that since we're creating an executable, we used `main.rs`. If we
-want to make a library instead, we should use `lib.rs`.
+want to make a library instead, we should use `lib.rs`. This convention is required
+for Cargo to successfully compile our projects, but it can be overridden if we wish.
Custom file locations for the entry point can be specified
-with a [`[[lib]]` or `[[bin]]`][crates-custom] key in the TOML file described below.
+with a [`[lib]` or `[[bin]]`][crates-custom] key in the TOML file.
[crates-custom]: http://doc.crates.io/manifest.html#configuring-a-target
authors = [ "Your name <you@example.com>" ]
```
-This file is in the [TOML][toml] format. Let’s let it explain itself to you:
+This file is in the [TOML][toml] format. TOML is similar to INI, but has some
+extra goodies. According to the TOML docs,
> TOML aims to be a minimal configuration file format that's easy to read due
> to obvious semantics. TOML is designed to map unambiguously to a hash table.
> TOML should be easy to parse into data structures in a wide variety of
> languages.
-TOML is very similar to INI, but with some extra goodies.
-
[toml]: https://github.com/toml-lang/toml
-Once you have this file in place, we should be ready to build! Try this:
+Once you have this file in place, we should be ready to build! To do so, run:
```bash
$ cargo build
Hello, world!
```
-Bam! We build our project with `cargo build`, and run it with
+Bam! We built our project with `cargo build`, and ran it with
`./target/debug/hello_world`. We can do both in one step with `cargo run`:
```bash
```
This hasn’t bought us a whole lot over our simple use of `rustc`, but think
-about the future: when our project gets more complex, we would need to do more
+about the future: when our project gets more complex, we need to do more
things to get all of the parts to properly compile. With Cargo, as our project
-grows, we can just `cargo build`, and it’ll work the right way.
+grows, we can just run `cargo build`, and it’ll work the right way.
When your project is finally ready for release, you can use
`cargo build --release` to compile your project with optimizations.
version = "0.0.1"
```
-This file is used by Cargo to keep track of dependencies in your application.
+The `Cargo.lock` file is used by Cargo to keep track of dependencies in your application.
Right now, we don’t have any, so it’s a bit sparse. You won't ever need
to touch this file yourself, just let Cargo handle it.
$ cargo new hello_world --bin
```
-We’re passing `--bin` because we're making a binary program: if we were making
-a library, we'd leave it off.
+We’re passing `--bin` because our goal is to get straight to making an executable application, as opposed to a library. Executables are often called ‘binaries.’ (as in `/usr/bin`, if you’re on a Unix system)
Let's check out what Cargo has generated for us:
[package]
name = "hello_world"
-version = "0.0.1"
+version = "0.1.0"
authors = ["Your Name <you@example.com>"]
```
The `assembly template` is the only required parameter and must be a
literal string (i.e. `""`)
-```
+```rust
#![feature(asm)]
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
Output operands, input operands, clobbers and options are all optional
but you must add the right number of `:` if you skip them:
-```
+```rust
# #![feature(asm)]
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
# fn main() { unsafe {
Whitespace also doesn't matter:
-```
+```rust
# #![feature(asm)]
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
# fn main() { unsafe {
"constraints1"(expr1), "constraints2"(expr2), ..."`. Output operand
expressions must be mutable lvalues, or not yet assigned:
-```
+```rust
# #![feature(asm)]
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
fn add(a: i32, b: i32) -> i32 {
operand. This is useful for very low level programming, where
which register you use is important:
-```
+```rust
# #![feature(asm)]
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
# unsafe fn read_byte_in(port: u16) -> u8 {
compiler not to assume any values loaded into those registers will
stay valid.
-```
+```rust
# #![feature(asm)]
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
# fn main() { unsafe {
the compiler to insert its usual stack alignment code
3. *intel* - use intel syntax instead of the default AT&T.
-```
+```rust
# #![feature(asm)]
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
# fn main() {
The first step to using Rust is to install it! There are a number of ways to
install Rust, but the easiest is to use the `rustup` script. If you're on Linux
-or a Mac, all you need to do is this (note that you don't need to type in the
-`$`s, they just indicate the start of each command):
+or a Mac, all you need to do is this:
+
+> Note: you don't need to type in the `$`s, they just indicate the start of
+> each command. You’ll see many tutorials and examples around the web that
+> follow this convention: `$` for commands run as your regular user, and
+> `#` for commands you should be running as an administrator.
```bash
$ curl -sf -L https://static.rust-lang.org/rustup.sh | sh
`curl | sh`. Basically, when you do this, you are trusting that the good
people who maintain Rust aren't going to hack your computer and do bad things.
That's a good instinct! If you're one of those people, please check out the
-documentation on [building Rust from Source][from source], or [the official
+documentation on [building Rust from Source][from-source], or [the official
binary downloads][install-page].
-[from source]: https://github.com/rust-lang/rust#building-from-source
+[from-source]: https://github.com/rust-lang/rust#building-from-source
Oh, we should also mention the officially supported platforms:
perform efficient pointer arithmetic, one would import those functions
via a declaration like
-```
+```rust
# #![feature(intrinsics)]
# fn main() {}
The most common consumer is `collect()`. This code doesn't quite compile,
but it shows the intention:
-```{rust,ignore}
+```rust,ignore
let one_to_one_hundred = (1..101).collect();
```
`.next()` method on repeatedly, and it gives us a sequence of things.
Because you need to call the method, this means that iterators
can be *lazy* and not generate all of the values upfront. This code,
-for example, does not actually generate the numbers `1-100`, instead
+for example, does not actually generate the numbers `1-99`, instead
creating a value that merely represents the sequence:
```rust
*Iterator adapters* take an iterator and modify it somehow, producing
a new iterator. The simplest one is called `map`:
-```{rust,ignore}
+```rust,ignore
(1..100).map(|x| x + 1);
```
Laziness strikes again! That closure will never execute. This example
doesn't print any numbers:
-```{rust,ignore}
+```rust,ignore
(1..100).map(|x| println!("{}", x));
```
iterator from before:
```rust
-# #![feature(step_by)]
-for i in (1..).step_by(5).take(5) {
+for i in (1..).take(5) {
println!("{}", i);
}
```
```text
1
-6
-11
-16
-21
+2
+3
+4
+5
```
`filter()` is an adapter that takes a closure as an argument. This closure
a few times, and then consume the result. Check it out:
```rust
-(1..1000)
+(1..)
.filter(|&x| x % 2 == 0)
.filter(|&x| x % 3 == 0)
.take(5)
and one for deallocation. A freestanding program that uses the `Box`
sugar for dynamic allocations via `malloc` and `free`:
-```
+```rust
#![feature(lang_items, box_syntax, start, no_std, libc)]
#![no_std]
uses it. So why do we need a lifetime here? We need to ensure that any reference
to a `Foo` cannot outlive the reference to an `i32` it contains.
+If you have multiple references, you can use the same lifetime multiple times:
+
+```rust
+fn x_or_y<'a>(x: &'a str, y: &'a str) -> &'a str {
+# x
+# }
+```
+
+This says that `x` and `y` both are alive for the same scope, and that the
+return value is also alive for that scope. If you wanted `x` and `y` to have
+different lifetimes, you can use multiple lifetime parameters:
+
+```rust
+fn x_or_y<'a, 'b>(x: &'a str, y: &'b str) -> &'a str {
+# x
+# }
+```
+
+In this example, `x` and `y` have different valid scopes, but the return value
+has the same lifetime as `x`.
+
## Thinking in scopes
A way to think about lifetimes is to visualize the scope that a reference is
## Lifetime Elision
Rust supports powerful local type inference in function bodies, but it’s
-forbidden in item signatures to allow reasoning about the types just based in
+forbidden in item signatures to allow reasoning about the types based on
the item signature alone. However, for ergonomic reasons a very restricted
secondary inference algorithm called “lifetime elision” applies in function
signatures. It infers only based on the signature components themselves and not
fn get_str() -> &str; // ILLEGAL, no inputs
fn frob(s: &str, t: &str) -> &str; // ILLEGAL, two inputs
-fn frob<'a, 'b>(s: &'a str, t: &'b str) -> &str; // Expanded: Output lifetime is unclear
+fn frob<'a, 'b>(s: &'a str, t: &'b str) -> &str; // Expanded: Output lifetime is ambiguous
fn get_mut(&mut self) -> &mut T; // elided
fn get_mut<'a>(&'a mut self) -> &'a mut T; // expanded
# Defining a macro
-You may have seen the `vec!` macro, used to initialize a [vector][] with any
-number of elements.
+You may have seen the `vec!` macro, used to initialize a [vector][vector] with
+any number of elements.
[vector]: vectors.html
except `+` or `*`.
This system is based on
-"[Macro-by-Example](http://www.cs.indiana.edu/ftp/techreports/TR206.pdf)"
+"[Macro-by-Example](https://www.cs.indiana.edu/ftp/techreports/TR206.pdf)"
(PDF link).
# Hygiene
inside `main` is painted a different "color" from the variable `state` inside
the macro, and therefore they don’t conflict.
-[hygienic macro system]: http://en.wikipedia.org/wiki/Hygienic_macro
+[hygienic macro system]: https://en.wikipedia.org/wiki/Hygienic_macro
This also restricts the ability of macros to introduce new bindings at the
invocation site. Code such as the following will not work:
}
```
-This holds for `let` bindings and loop labels, but not for [items][].
+This holds for `let` bindings and loop labels, but not for [items][items].
So the following code does compile:
```rust
* `stmt`: a single statement. Example: `let x = 3`.
* `block`: a brace-delimited sequence of statements. Example:
`{ log(error, "hi"); return 12; }`.
-* `item`: an [item][]. Examples: `fn foo() { }`; `struct Bar;`.
+* `item`: an [item][item]. Examples: `fn foo() { }`; `struct Bar;`.
* `meta`: a "meta item", as found in attributes. Example: `cfg(target_os = "windows")`.
* `tt`: a single token tree.
There are additional rules regarding the next token after a metavariable:
-* `expr` variables must be followed by one of: `=> , ;`
-* `ty` and `path` variables must be followed by one of: `=> , : = > as`
-* `pat` variables must be followed by one of: `=> , =`
+* `expr` variables may only be followed by one of: `=> , ;`
+* `ty` and `path` variables may only be followed by one of: `=> , : = > as`
+* `pat` variables may only be followed by one of: `=> , = if in`
* Other variables may be followed by any token.
These rules provide some flexibility for Rust’s syntax to evolve without
arguments.
As an extreme example, it is possible, though hardly advisable, to implement
-the [Bitwise Cyclic Tag](http://esolangs.org/wiki/Bitwise_Cyclic_Tag) automaton
+the [Bitwise Cyclic Tag](https://esolangs.org/wiki/Bitwise_Cyclic_Tag) automaton
within Rust’s macro system.
```rust
## assert! and assert_eq!
-These two macros are used in tests. `assert!` takes a boolean, and `assert_eq!`
-takes two values and compares them. Truth passes, success `panic!`s. Like
-this:
+These two macros are used in tests. `assert!` takes a boolean. `assert_eq!`
+takes two values and checks them for equality. `true` passes, `false` `panic!`s.
+Like this:
```rust,no_run
// A-ok!
assert!(5 < 3);
assert_eq!(5, 3);
```
+
## try!
`try!` is used for error handling. It takes something that can return a
can be awkward. Consider this code:
```rust,ignore
-baz(bar(foo)));
+baz(bar(foo));
```
We would read this left-to right, and so we see ‘baz bar foo’. But this isn’t the
# Chaining method calls
So, now we know how to call a method, such as `foo.bar()`. But what about our
-original example, `foo.bar().baz()`? This is called ‘method chaining’, and we
-can do it by returning `self`.
+original example, `foo.bar().baz()`? This is called ‘method chaining’. Let’s
+look at an example:
-```
+```rust
struct Circle {
x: f64,
y: f64,
Check the return type:
-```
+```rust
# struct Circle;
# impl Circle {
fn grow(&self) -> Circle {
This ‘associated function’ builds a new `Circle` for us. Note that associated
functions are called with the `Struct::function()` syntax, rather than the
-`ref.method()` syntax. Some other langauges call associated functions ‘static
+`ref.method()` syntax. Some other languages call associated functions ‘static
methods’.
# Builder Pattern
have method overloading, named arguments, or variable arguments. We employ
the builder pattern instead. It looks like this:
-```
+```rust
struct Circle {
x: f64,
y: f64,
> * exactly one mutable reference (`&mut T`)
[ownership]: ownership.html
-[borrowing]: borrowing.html#The-Rules
+[borrowing]: references-and-borrowing.html#borrowing
So, that’s the real definition of ‘immutability’: is this safe to have two
pointers to? In `Arc<T>`’s case, yes: the mutation is entirely contained inside
[struct]: structs.html
-However, by using `Cell<T>`, you can emulate field-level mutability:
+However, by using [`Cell<T>`][cell], you can emulate field-level mutability:
-```
+```rust
use std::cell::Cell;
struct Point {
println!("y: {:?}", point.y);
```
+[cell]: ../std/cell/struct.Cell.html
+
This will print `y: Cell { value: 7 }`. We’ve successfully updated `y`.
If you're on Windows, please download either the [32-bit installer][win32] or
the [64-bit installer][win64] and run it.
-[win32]: https://static.rust-lang.org/dist/rust-1.0.0-beta-i686-pc-windows-gnu.msi
-[win64]: https://static.rust-lang.org/dist/rust-1.0.0-beta-x86_64-pc-windows-gnu.msi
+[win32]: https://static.rust-lang.org/dist/rust-nightly-i686-pc-windows-gnu.msi
+[win64]: https://static.rust-lang.org/dist/rust-nightly-x86_64-pc-windows-gnu.msi
## Uninstalling
`curl | sh`. Basically, when you do this, you are trusting that the good
people who maintain Rust aren't going to hack your computer and do bad things.
That's a good instinct! If you're one of those people, please check out the
-documentation on [building Rust from Source][from source], or [the official
-binary downloads][install page].
+documentation on [building Rust from Source][from-source], or [the official
+binary downloads][install-page].
-[from source]: https://github.com/rust-lang/rust#building-from-source
-[install page]: http://www.rust-lang.org/install.html
+[from-source]: https://github.com/rust-lang/rust#building-from-source
+[install-page]: http://www.rust-lang.org/install.html
Oh, we should also mention the officially supported platforms:
[the #rust IRC channel on irc.mozilla.org][irc], which you can access through
[Mibbit][mibbit]. Click that link, and you'll be chatting with other Rustaceans
(a silly nickname we call ourselves), and we can help you out. Other great
-resources include [the user’s forum][users], and [Stack Overflow][stack overflow].
+resources include [the user’s forum][users], and [Stack Overflow][stackoverflow].
[irc]: irc://irc.mozilla.org/#rust
[mibbit]: http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust
[users]: http://users.rust-lang.org/
-[stack overflow]: http://stackoverflow.com/questions/tagged/rust
+[stackoverflow]: http://stackoverflow.com/questions/tagged/rust
The function marked `#[start]` is passed the command line parameters
in the same format as C:
-```
+```rust
#![feature(lang_items, start, no_std, libc)]
#![no_std]
But, unlike a move, we can still use `v` afterward. This is because an `i32`
has no pointers to data somewhere else, copying it is a full copy.
+All primitive types implement the `Copy` trait and their ownership is
+therefore not moved like one would assume, following the ´ownership rules´.
+To give an example, the two following snippets of code only compile because the
+`i32` and `bool` types implement the `Copy` trait.
+
+```rust
+fn main() {
+ let a = 5;
+
+ let _y = double(a);
+ println!("{}", a);
+}
+
+fn double(x: i32) -> i32 {
+ x * 2
+}
+```
+
+```rust
+fn main() {
+ let a = true;
+
+ let _y = change_truth(a);
+ println!("{}", a);
+}
+
+fn change_truth(x: bool) -> bool {
+ !x
+}
+```
+
+If we would have used types that do not implement the `Copy` trait,
+we would have gotten a compile error because we tried to use a moved value.
+
+```text
+error: use of moved value: `a`
+println!("{}", a);
+ ^
+```
+
We will discuss how to make your own types `Copy` in the [traits][traits]
section.
This prints `Got an int!`.
+If you’re using `if` with multiple patterns, the `if` applies to both sides:
+
+```rust
+let x = 4;
+let y = false;
+
+match x {
+ 4 | 5 if y => println!("yes"),
+ _ => println!("no"),
+}
+```
+
+This prints `no`, because the `if` applies to the whole of `4 | 5`, and not to
+just the `5`, In other words, the the precedence of `if` behaves like this:
+
+```text
+(4 | 5) if y => ...
+```
+
+not this:
+
+```text
+4 | (5 if y) => ...
+```
+
# ref and ref mut
If you want to get a [reference][ref], use the `ref` keyword:
let origin = Point { x: 0, y: 0 };
match origin {
- Point { x: x, y: y } => println!("({},{})", x, y),
+ Point { x, y } => println!("({},{})", x, y),
}
```
[struct]: structs.html
+We can use `:` to give a value a different name.
+
+```rust
+struct Point {
+ x: i32,
+ y: i32,
+}
+
+let origin = Point { x: 0, y: 0 };
+
+match origin {
+ Point { x: x1, y: y1 } => println!("({},{})", x1, y1),
+}
+```
+
If we only care about some of the values, we don’t have to give them all names:
```rust
let origin = Point { x: 0, y: 0 };
match origin {
- Point { x: x, .. } => println!("x is {}", x),
+ Point { x, .. } => println!("x is {}", x),
}
```
let origin = Point { x: 0, y: 0 };
match origin {
- Point { y: y, .. } => println!("y is {}", y),
+ Point { y, .. } => println!("y is {}", y),
}
```
You can disambiguate a single-element tuple from a value in parentheses with a
comma:
-```
+```rust
(0,); // single-element tuple
(0); // zero in parentheses
```
Functions also have a type! They look like this:
-```
+```rust
fn foo(x: i32) -> i32 { x }
let x: fn(i32) -> i32 = foo;
It gives this error:
```text
-error: dereference of unsafe pointer requires unsafe function or block [E0133]
- println!("raw points at{}", *raw);
- ^~~~
+error: dereference of raw pointer requires unsafe function or block [E0133]
+ println!("raw points at {}", *raw);
+ ^~~~
```
When you dereference a raw pointer, you’re taking responsibility that it’s not
# FFI
Raw pointers are useful for FFI: Rust’s `*const T` and `*mut T` are similar to
-C’s `const T*` and `T*`, respectfully. For more about this use, consult the
+C’s `const T*` and `T*`, respectively. For more about this use, consult the
[FFI chapter][ffi].
[ffi]: ffi.html
Here’s the rules about borrowing in Rust:
-First, any borrow must last for a smaller scope than the owner. Second, you may
-have one or the other of these two kinds of borrows, but not both at the same
-time:
+First, any borrow must last for a scope no greater than that of the owner.
+Second, you may have one or the other of these two kinds of borrows, but not
+both at the same time:
-* 0 to N references (`&T`) to a resource.
+* one or more references (`&T`) to a resource.
* exactly one mutable reference (`&mut T`)
^
```
-In other words, the mutable borow is held through the rest of our example. What
+In other words, the mutable borrow is held through the rest of our example. What
we want is for the mutable borrow to end _before_ we try to call `println!` and
make an immutable borrow. In Rust, borrowing is tied to the scope that the
borrow is valid for. And our scopes look like this:
References must live as long as the resource they refer to. Rust will check the
scopes of your references to ensure that this is true.
-If Rust didn’t check that this property, we could accidentally use a reference
+If Rust didn’t check this property, we could accidentally use a reference
which was invalid. For example:
```rust,ignore
As organizations grow, they increasingly rely on a multitude of programming
languages. Different programming languages have different strengths and
weaknesses, and a polyglot stack lets you use a particular language where
-its strengths make sense, and use a different language where it’s weak.
+its strengths make sense and a different one where it’s weak.
A very common area where many programming languages are weak is in runtime
performance of programs. Often, using a language that is slower, but offers
-greater programmer productivity is a worthwhile trade-off. To help mitigate
-this, they provide a way to write some of your system in C, and then call
-the C code as though it were written in the higher-level language. This is
+greater programmer productivity, is a worthwhile trade-off. To help mitigate
+this, they provide a way to write some of your system in C and then call
+that C code as though it were written in the higher-level language. This is
called a ‘foreign function interface’, often shortened to ‘FFI’.
Rust has support for FFI in both directions: it can call into C code easily,
but crucially, it can also be called _into_ as easily as C. Combined with
Rust’s lack of a garbage collector and low runtime requirements, this makes
Rust a great candidate to embed inside of other languages when you need
-some extra oomph.
+that extra oomph.
There is a whole [chapter devoted to FFI][ffi] and its specifics elsewhere in
the book, but in this chapter, we’ll examine this particular use-case of FFI,
-with three examples, in Ruby, Python, and JavaScript.
+with examples in Ruby, Python, and JavaScript.
[ffi]: ffi.html
on an optimizer to do its job, we may want to ensure that we’re always using
primitive number types rather than some sort of object type.
-Second, many languages have a ‘global interpreter lock’, which limits
+Second, many languages have a ‘global interpreter lock’ (GIL), which limits
concurrency in many situations. This is done in the name of safety, which is
a positive effect, but it limits the amount of work that can be done at the
same time, which is a big negative.
To emphasize these two aspects, we’re going to create a little project that
-uses these two aspects heavily. Since the focus of the example is the embedding
-of Rust into the languages, rather than the problem itself, we’ll just use a
+uses these two aspects heavily. Since the focus of the example is to embed
+Rust into other languages, rather than the problem itself, we’ll just use a
toy example:
> Start ten threads. Inside each thread, count from one to five million. After
-> All ten threads are finished, print out ‘done!’.
+> all ten threads are finished, print out ‘done!’.
I chose five million based on my particular computer. Here’s an example of this
code in Ruby:
5_000_000.times do
count += 1
end
+
+ count
end
end
-threads.each {|t| t.join }
+threads.each do |t|
+ puts "Thread finished with count=#{t.value}"
+end
puts "done!"
```
core on my machine. That’s the GIL kicking in.
While it’s true that this is a synthetic program, one can imagine many problems
-that are similar to this in the real world. For our purposes, spinning up some
+that are similar to this in the real world. For our purposes, spinning up a few
busy threads represents some sort of parallel, expensive computation.
# A Rust library
-Let’s re-write this problem in Rust. First, let’s make a new project with
+Let’s rewrite this problem in Rust. First, let’s make a new project with
Cargo:
```bash
fn process() {
let handles: Vec<_> = (0..10).map(|_| {
thread::spawn(|| {
- let mut _x = 0;
- for _ in (0..5_000_001) {
- _x += 1
+ let mut x = 0;
+ for _ in (0..5_000_000) {
+ x += 1
}
+ x
})
}).collect();
for h in handles {
- h.join().ok().expect("Could not join a thread!");
+ println!("Thread finished with count={}",
+ h.join().map_err(|_| "Could not join a thread!").unwrap());
}
+ println!("done!");
}
```
Some of this should look familiar from previous examples. We spin up ten
threads, collecting them into a `handles` vector. Inside of each thread, we
-loop five million times, and add one to `_x` each time. Why the underscore?
-Well, if we remove it and compile:
-
-```bash
-$ cargo build
- Compiling embed v0.1.0 (file:///home/steve/src/embed)
-src/lib.rs:3:1: 16:2 warning: function is never used: `process`, #[warn(dead_code)] on by default
-src/lib.rs:3 fn process() {
-src/lib.rs:4 let handles: Vec<_> = (0..10).map(|_| {
-src/lib.rs:5 thread::spawn(|| {
-src/lib.rs:6 let mut x = 0;
-src/lib.rs:7 for _ in (0..5_000_001) {
-src/lib.rs:8 x += 1
- ...
-src/lib.rs:6:17: 6:22 warning: variable `x` is assigned to, but never used, #[warn(unused_variables)] on by default
-src/lib.rs:6 let mut x = 0;
- ^~~~~
-```
-
-That first warning is because we are building a library. If we had a test
-for this function, the warning would go away. But for now, it’s never
-called.
-
-The second is related to `x` versus `_x`. Because we never actually _do_
-anything with `x`, we get a warning about it. In our case, that’s perfectly
-okay, as we’re just trying to waste CPU cycles. Prefixing `x` with the
-underscore removes the warning.
-
-Finally, we join on each thread.
+loop five million times, and add one to `x` each time. Finally, we join on
+each thread.
Right now, however, this is a Rust library, and it doesn’t expose anything
that’s callable from C. If we tried to hook this up to another language right
now, it wouldn’t work. We only need to make two small changes to fix this,
-though. The first is modify the beginning of our code:
+though. The first is to modify the beginning of our code:
```rust,ignore
#[no_mangle]
We have to add a new attribute, `no_mangle`. When you create a Rust library, it
changes the name of the function in the compiled output. The reasons for this
are outside the scope of this tutorial, but in order for other languages to
-know how to call the function, we need to not do that. This attribute turns
+know how to call the function, we can’t do that. This attribute turns
that behavior off.
The other change is the `pub extern`. The `pub` means that this function should
```
This tells Rust that we want to compile our library into a standard dynamic
-library. By default, Rust compiles into an ‘rlib’, a Rust-specific format.
+library. By default, Rust compiles an ‘rlib’, a Rust-specific format.
Let’s build the project now:
# Ruby
-Open up a `embed.rb` file inside of our project, and do this:
+Open up an `embed.rb` file inside of our project, and do this:
```ruby
require 'ffi'
Hello.process
-puts "done!”
+puts 'done!'
```
Before we can run this, we need to install the `ffi` gem:
$
```
-Whoah, that was fast! On my system, this took `0.086` seconds, rather than
+Whoa, that was fast! On my system, this took `0.086` seconds, rather than
the two seconds the pure Ruby version took. Let’s break down this Ruby
code:
ffi_lib 'target/release/libembed.so'
```
-The `ffi` gem’s authors recommend using a module to scope the functions
-we’ll import from the shared library. Inside, we `extend` the necessary
-`FFI::Library` module, and then call `ffi_lib` to load up our shared
-object library. We just pass it the path that our library is stored,
-which as we saw before, is `target/release/libembed.so`.
+The `Hello` module is used to attach the native functions from the shared
+library. Inside, we `extend` the necessary `FFI::Library` module and then call
+`ffi_lib` to load up our shared object library. We just pass it the path that
+our library is stored, which, as we saw before, is
+`target/release/libembed.so`.
```ruby
attach_function :process, [], :void
This is the actual call into Rust. The combination of our `module`
and the call to `attach_function` sets this all up. It looks like
-a Ruby function, but is actually Rust!
+a Ruby function but is actually Rust!
```ruby
-puts "done!"
+puts 'done!'
```
Finally, as per our project’s requirements, we print out `done!`.
var ffi = require('ffi');
var lib = ffi.Library('target/release/libembed', {
- 'process': [ 'void', [] ]
+ 'process': ['void', []]
});
lib.process();
It looks more like the Ruby example than the Python example. We use
the `ffi` module to get access to `ffi.Library()`, which loads up
our shared object. We need to annotate the return type and argument
-types of the function, which are 'void' for return, and an empty
+types of the function, which are `void` for return and an empty
array to signify no arguments. From there, we just call it and
print the result.
`&'static str`:
```rust
-let string = "Hello there."; // string: &'static str
+let greeting = "Hello there."; // greeting: &'static str
```
This string is statically allocated, meaning that it’s saved inside our
-compiled program, and exists for the entire duration it runs. The `string`
+compiled program, and exists for the entire duration it runs. The `greeting`
binding is a reference to this statically allocated string. String slices
have a fixed size, and cannot be mutated.
`String`s will coerce into `&str` with an `&`:
-```
+```rust
fn takes_slice(slice: &str) {
println!("Got: {}", slice);
}
}
```
+This coercion does not happen for functions that accept one of `&str`’s traits
+instead of `&str`. For example, [`TcpStream::connect`][connect] has a parameter
+of type `ToSocketAddrs`. A `&str` is okay but a `String` must be explicitly
+converted using `&*`.
+
+```rust,no_run
+use std::net::TcpStream;
+
+TcpStream::connect("192.168.0.1:3000"); // &str parameter
+
+let addr_string = "192.168.0.1:3000".to_string();
+TcpStream::connect(&*addr_string); // convert addr_string to &str
+```
+
Viewing a `String` as a `&str` is cheap, but converting the `&str` to a
`String` involves allocating memory. No reason to do that unless you have to!
This emphasizes that we have to go through the whole list of `chars`.
+## Slicing
+
+You can get a slice of a string with slicing syntax:
+
+```rust
+let dog = "hachiko";
+let hachi = &dog[0..5];
+```
+
+But note that these are _byte_ offsets, not _character_ offsets. So
+this will fail at runtime:
+
+```rust,should_panic
+let dog = "忠犬ハチ公";
+let hachi = &dog[0..2];
+```
+
+with this error:
+
+```text
+thread '<main>' panicked at 'index 0 and/or 2 in `忠犬ハチ公` do not lie on
+character boundary'
+```
+
## Concatenation
If you have a `String`, you can concatenate a `&str` to the end of it:
let hello_world = hello + &world;
```
-This is because `&String` can automatically coerece to a `&str`. This is a
+This is because `&String` can automatically coerce to a `&str`. This is a
feature called ‘[`Deref` coercions][dc]’.
[dc]: deref-coercions.html
+[connect]: ../std/net/struct.TcpStream.html#method.connect
make sure that the failure message contains the provided text. A safer version
of the example above would be:
-```
+```rust
#[test]
#[should_panic(expected = "assertion failed")]
fn it_works() {
That's all there is to the basics! Let's write one 'real' test:
-```{rust,ignore}
+```rust,ignore
pub fn add_two(a: i32) -> i32 {
a + 2
}
missing the `tests` module. The idiomatic way of writing our example
looks like this:
-```{rust,ignore}
+```rust,ignore
pub fn add_two(a: i32) -> i32 {
a + 2
}
a large module, and so this is a common use of the `glob` feature. Let's change
our `src/lib.rs` to make use of it:
-```{rust,ignore}
+```rust,ignore
pub fn add_two(a: i32) -> i32 {
a + 2
To write an integration test, let's make a `tests` directory, and
put a `tests/lib.rs` file inside, with this as its contents:
-```{rust,ignore}
+```rust,ignore
extern crate adder;
#[test]
running examples in your documentation. Here's a fleshed-out `src/lib.rs`
with examples:
-```{rust,ignore}
+```rust,ignore
//! The `adder` crate provides functions that add numbers to other numbers.
//!
//! # Examples
| 0 | x | ?????? |
[drop]: drop.html
-[moving]: We can make the memory live longer by transferring ownership,
- sometimes called ‘moving out of the box’. More complex examples will
- be covered later.
+[^moving]: We can make the memory live longer by transferring ownership,
+ sometimes called ‘moving out of the box’. More complex examples will
+ be covered later.
And then the stack frame goes away, freeing all of our memory.
| (2<sup>30</sup>) - 1 | | 5 |
| ... | ... | ... |
| 12 | g | 100 |
-| 11 | f | 4 |
+| 11 | f | 9 |
| 10 | e | 9 |
| 9 | d | (2<sup>30</sup>) - 1 |
| 8 | c | 5 |
```
The `destructor` field in each vtable points to a function that will clean up
-any resources of the vtable’s type, for `u8` it is trivial, but for `String` it
+any resources of the vtable’s type: for `u8` it is trivial, but for `String` it
will free the memory. This is necessary for owning trait objects like
`Box<Foo>`, which need to clean-up both the `Box` allocation as well as the
internal type when they go out of scope. The `size` and `align` fields store
destructor, but will be used in the future, as trait objects are progressively
made more flexible.
-Suppose we’ve got some values that implement `Foo`, then the explicit form of
+Suppose we’ve got some values that implement `Foo`. The explicit form of
construction and use of `Foo` trait objects might look a bit like (ignoring the
type mismatches: they’re all just pointers anyway):
// y.method();
(y.vtable.method)(y.data);
```
-
-If `b` or `y` were owning trait objects (`Box<Foo>`), there would be a
-`(b.vtable.destructor)(b.data)` (respectively `y`) call when they went out of
-scope.
% Traits
+A trait is a language feature that tells the Rust compiler about
+functionality a type must provide.
+
Do you remember the `impl` keyword, used to call a function with [method
syntax][methodsyntax]?
we use `impl Trait for Item`, rather than just `impl Item`.
We can use traits to constrain our generics. Consider this function, which
-does not compile, and gives us a similar error:
+does not compile:
```rust,ignore
fn print_area<T>(shape: T) {
Rust complains:
```text
-error: type `T` does not implement any method in scope named `area`
+error: no method named `area` found for type `T` in the current scope
```
Because `T` can be any type, we can’t be sure that it implements the `area`
We get a compile-time error:
```text
-error: failed to find an implementation of trait main::HasArea for int
+error: the trait `HasArea` is not implemented for the type `_` [E0277]
```
So far, we’ve only added trait implementations to structs, but you can
```rust,ignore
let mut f = std::fs::File::open("foo.txt").ok().expect("Couldn’t open foo.txt");
-let result = f.write("whatever".as_bytes());
+let buf = b"whatever"; // byte string literal. buf: &[u8; 8]
+let result = f.write(buf);
# result.unwrap(); // ignore the error
```
```text
error: type `std::fs::File` does not implement any method in scope named `write`
-
-let result = f.write(b"whatever");
- ^~~~~~~~~~~~~~~~~~
+let result = f.write(buf);
+ ^~~~~~~~~~
```
We need to `use` the `Write` trait first:
use std::io::Write;
let mut f = std::fs::File::open("foo.txt").ok().expect("Couldn’t open foo.txt");
-let result = f.write("whatever".as_bytes());
+let buf = b"whatever";
+let result = f.write(buf);
# result.unwrap(); // ignore the error
```
This will compile without error.
-This means that even if someone does something bad like add methods to `int`,
+This means that even if someone does something bad like add methods to `i32`,
it won’t affect you, unless you `use` that trait.
-There’s one more restriction on implementing traits. Either the trait or the
-type you’re writing the `impl` for must be defined by you. So, we could
+There’s one more restriction on implementing traits: either the trait, or the
+type you’re writing the `impl` for, must be defined by you. So, we could
implement the `HasArea` type for `i32`, because `HasArea` is in our code. But
-if we tried to implement `Float`, a trait provided by Rust, for `i32`, we could
+if we tried to implement `ToString`, a trait provided by Rust, for `i32`, we could
not, because neither the trait nor the type are in our code.
One last thing about traits: generic functions with a trait bound use
bounds isn’t too bad, but as the number increases, the syntax gets increasingly
awkward:
-```
+```rust
use std::fmt::Debug;
fn foo<T: Clone, K: Clone + Debug>(x: T, y: K) {
Rust has a solution, and it’s called a ‘`where` clause’:
-```
+```rust
use std::fmt::Debug;
fn foo<T: Clone, K: Clone + Debug>(x: T, y: K) {
fn main() {
foo("Hello", "world");
- bar("Hello", "workd");
+ bar("Hello", "world");
}
```
and then add `where` after the parameter list. For longer lists, whitespace can
be added:
-```
+```rust
use std::fmt::Debug;
fn bar<T, K>(x: T, y: K)
`where` is also more powerful than the simpler syntax. For example:
-```
+```rust
trait ConvertTo<Output> {
fn convert(&self) -> Output;
}
fn inverse<T>() -> T
// this is using ConvertTo as if it were "ConvertFrom<i32>"
where i32: ConvertTo<T> {
- 1i32.convert()
+ 42.convert()
}
```
There’s an alternate form of `vec!` for repeating an initial value:
-```
+```rust
let v = vec![0; 10]; // ten zeroes
```
Rust also has a `while` loop. It looks like this:
-```{rust}
+```rust
let mut x = 5; // mut x: i32
let mut done = false; // mut done: bool
use std::collections::BTreeMap;
use std::fs::{read_dir, File};
use std::io::{Read, Write};
+use std::env;
use std::path::Path;
use std::error::Error;
try!(write!(&mut output_file, "<h1>Rust Compiler Error Index</h1>\n"));
- for (err_code, info) in err_map.iter() {
+ for (err_code, info) in err_map {
// Enclose each error in a div so they can be shown/hidden en masse.
let desc_desc = match info.description {
Some(_) => "error-described",
}
fn main_with_result() -> Result<(), Box<Error>> {
- let metadata_dir = get_metadata_dir();
+ let build_arch = try!(env::var("CFG_BUILD"));
+ let metadata_dir = get_metadata_dir(&build_arch);
let err_map = try!(load_all_errors(&metadata_dir));
try!(render_error_page(&err_map, Path::new("doc/error-index.html")));
Ok(())
+++ /dev/null
-#!/usr/bin/env python
-#
-# Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-# file at the top-level directory of this distribution and at
-# http://rust-lang.org/COPYRIGHT.
-#
-# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-# option. This file may not be copied, modified, or distributed
-# except according to those terms.
-
-import sys
-import subprocess
-import re
-
-
-def main():
- if len(sys.argv) <= 1:
- print('Usage: %s [ --apply ] filename1.rs filename2.rs ...'
- % sys.argv[0])
- elif sys.argv[1] == '--apply':
- for filename in sys.argv[2:]:
- patch(filename)
- else:
- for filename in sys.argv[1:]:
- diff(filename)
-
-
-def patch(filename):
- source = read(filename)
- rewritten = rewrite_bytes_macros(source)
- if rewritten is not None and rewritten != source:
- write(filename, rewritten)
-
-
-def diff(filename):
- rewritten = rewrite_bytes_macros(read(filename))
- if rewritten is not None:
- p = subprocess.Popen(['diff', '-u', filename, '-'],
- stdin=subprocess.PIPE)
- p.stdin.write(rewritten)
- p.stdin.close()
- p.wait()
-
-
-def read(filename):
- with open(filename, 'rb') as f:
- return f.read()
-
-
-def write(filename, content):
- with open(filename, 'wb') as f:
- f.write(content)
-
-
-def rewrite_bytes_macros(source):
- rewritten, num_occurrences = BYTES_MACRO_RE.subn(rewrite_one_macro, source)
- if num_occurrences > 0:
- return rewritten
-
-
-BYTES_MACRO_RE = re.compile(br'bytes!\( (?P<args> [^)]* ) \)', re.VERBOSE)
-
-
-def rewrite_one_macro(match):
- try:
- bytes = parse_bytes(split_args(match.group('args')))
- return b'b"' + b''.join(map(escape, bytes)) + b'"'
- except SkipThisRewrite:
- print('Skipped: %s' % match.group(0).decode('utf8', 'replace'))
- return match.group(0)
-
-
-class SkipThisRewrite(Exception):
- pass
-
-
-def split_args(args):
- previous = b''
- for arg in args.split(b','):
- if previous:
- arg = previous + b',' + arg
- if arg.count(b'"') % 2 == 0:
- yield arg
- previous = b''
- else:
- previous = arg
- if previous:
- yield previous
-
-
-def parse_bytes(args):
- for arg in args:
- arg = arg.strip()
- if (arg.startswith(b'"') and arg.endswith(b'"')) or (
- arg.startswith(b"'") and arg.endswith(b"'")):
- # Escaped newline means something different in Rust and Python.
- if b'\\\n' in arg:
- raise SkipThisRewrite
- for byte in eval(b'u' + arg).encode('utf8'):
- yield ord(byte)
- else:
- if arg.endswith(b'u8'):
- arg = arg[:-2]
- # Assume that all Rust integer literals
- # are valid Python integer literals
- value = int(eval(arg))
- assert value <= 0xFF
- yield value
-
-
-def escape(byte):
- c = chr(byte)
- escaped = {
- b'\0': br'\0',
- b'\t': br'\t',
- b'\n': br'\n',
- b'\r': br'\r',
- b'\'': b'\\\'',
- b'\\': br'\\',
- }.get(c)
- if escaped is not None:
- return escaped
- elif b' ' <= c <= b'~':
- return chr(byte)
- else:
- return ('\\x%02X' % byte).encode('ascii')
-
-
-if str is not bytes:
- # Python 3.x
- ord = lambda x: x
- chr = lambda x: bytes([x])
-
-
-if __name__ == '__main__':
- main()
--- /dev/null
+#!/bin/sh
+
+# Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+# This script, invoked e.g. "add-authors.sh 1.0.0..rust-lang/master",
+# will merge new authors into AUTHORS.txt, obeying the mailmap
+# file.
+#
+# After running this script, run `git diff` to manually inspect
+# changes. If there are incorrect additions fix it by editing
+# .mailmap and re-running the script.
+
+set -u -e
+
+range="$1"
+
+authors_file="./AUTHORS.txt"
+tmp_file="./AUTHORS.txt.tmp"
+old_authors="$(cat "$authors_file" | tail -n +2 | sed "/^$/d" | sort)"
+new_authors="$(git log "$range" --format="%aN <%aE>" | sort | uniq)"
+
+echo "Rust was written by these fine people:\n" > "$tmp_file"
+echo "$old_authors\n$new_authors" | sort | uniq >> "$tmp_file"
+mv -f "$tmp_file" "$authors_file"
# except according to those terms.
import os
+import subprocess
import sys
import functools
STATUS = 0
-
def error_unless_permitted(env_var, message):
global STATUS
if not os.getenv(env_var):
sys.stderr.write(message)
STATUS = 1
-
def only_on(platforms):
def decorator(func):
@functools.wraps(func)
return inner
return decorator
-
-@only_on(('linux', 'darwin', 'freebsd', 'openbsd'))
+@only_on(['linux', 'darwin', 'freebsd', 'openbsd'])
def check_rlimit_core():
import resource
soft, hard = resource.getrlimit(resource.RLIMIT_CORE)
set ALLOW_NONZERO_RLIMIT_CORE to ignore this warning
""" % (soft))
+@only_on(['win32'])
+def check_console_code_page():
+ if '65001' not in subprocess.check_output(['cmd', '/c', 'chcp']):
+ sys.stderr.write('Warning: the console output code page is not UTF-8, \
+some tests may fail. Use `cmd /c "chcp 65001"` to setup UTF-8 code page.\n')
def main():
+ check_console_code_page()
check_rlimit_core()
if __name__ == '__main__':
summaries.append((fname, summary))
def count(t):
- return sum(map(lambda (f, s): len(s.get(t, [])), summaries))
+ return sum(map(lambda f: len(f[1].get(t, [])), summaries))
logfiles = sys.argv[1:]
for files in map(glob.glob, logfiles):
failed = count('failed')
ignored = count('ignored')
measured = count('bench')
- print "summary of %d test runs: %d passed; %d failed; %d ignored; %d measured" % \
- (len(logfiles), ok, failed, ignored, measured)
- print ""
+ print("summary of %d test runs: %d passed; %d failed; %d ignored; %d measured" %
+ (len(logfiles), ok, failed, ignored, measured))
+ print("")
if failed > 0:
- print "failed tests:"
+ print("failed tests:")
for f, s in summaries:
failures = s.get('failed', [])
if len(failures) > 0:
- print " %s:" % (f)
+ print(" %s:" % (f))
for test in failures:
- print " %s" % (test)
+ print(" %s" % (test))
--- /dev/null
+# Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+"""
+This module provides an abstraction layer over common Rust pretty printing
+functionality needed by both GDB and LLDB.
+"""
+
+import re
+
+# Type codes that indicate the kind of type as it appears in DWARF debug
+# information. This code alone is not sufficient to determine the Rust type.
+# For example structs, tuples, fat pointers, or enum variants will all have
+# DWARF_TYPE_CODE_STRUCT.
+DWARF_TYPE_CODE_STRUCT = 1
+DWARF_TYPE_CODE_UNION = 2
+DWARF_TYPE_CODE_PTR = 3
+DWARF_TYPE_CODE_ARRAY = 4
+DWARF_TYPE_CODE_ENUM = 5
+
+# These constants specify the most specific kind of type that could be
+# determined for a given value.
+TYPE_KIND_UNKNOWN = -1
+TYPE_KIND_EMPTY = 0
+TYPE_KIND_SLICE = 1
+TYPE_KIND_REGULAR_STRUCT = 2
+TYPE_KIND_TUPLE = 3
+TYPE_KIND_TUPLE_STRUCT = 4
+TYPE_KIND_CSTYLE_VARIANT = 5
+TYPE_KIND_TUPLE_VARIANT = 6
+TYPE_KIND_STRUCT_VARIANT = 7
+TYPE_KIND_STR_SLICE = 8
+TYPE_KIND_STD_VEC = 9
+TYPE_KIND_STD_STRING = 10
+TYPE_KIND_REGULAR_ENUM = 11
+TYPE_KIND_COMPRESSED_ENUM = 12
+TYPE_KIND_SINGLETON_ENUM = 13
+TYPE_KIND_CSTYLE_ENUM = 14
+TYPE_KIND_PTR = 15
+TYPE_KIND_FIXED_SIZE_VEC = 16
+
+ENCODED_ENUM_PREFIX = "RUST$ENCODED$ENUM$"
+ENUM_DISR_FIELD_NAME = "RUST$ENUM$DISR"
+
+# Slice related constants
+SLICE_FIELD_NAME_DATA_PTR = "data_ptr"
+SLICE_FIELD_NAME_LENGTH = "length"
+SLICE_FIELD_NAMES = [SLICE_FIELD_NAME_DATA_PTR, SLICE_FIELD_NAME_LENGTH]
+
+# std::Vec<> related constants
+STD_VEC_FIELD_NAME_DATA_PTR = "ptr"
+STD_VEC_FIELD_NAME_LENGTH = "len"
+STD_VEC_FIELD_NAME_CAPACITY = "cap"
+STD_VEC_FIELD_NAMES = [STD_VEC_FIELD_NAME_DATA_PTR,
+ STD_VEC_FIELD_NAME_LENGTH,
+ STD_VEC_FIELD_NAME_CAPACITY]
+
+# std::String related constants
+STD_STRING_FIELD_NAMES = ["vec"]
+
+
+class Type(object):
+ """
+ This class provides a common interface for type-oriented operations.
+ Sub-classes are supposed to wrap a debugger-specific type-object and
+ provide implementations for the abstract methods in this class.
+ """
+
+ def __init__(self):
+ self.__type_kind = None
+
+ def get_unqualified_type_name(self):
+ """
+ Implementations of this method should return the unqualified name of the
+ type-object they are wrapping. Some examples:
+
+ 'int' -> 'int'
+ 'std::vec::Vec<std::string::String>' -> 'Vec<std::string::String>'
+ '&std::option::Option<std::string::String>' -> '&std::option::Option<std::string::String>'
+
+ As you can see, type arguments stay fully qualified.
+ """
+ raise NotImplementedError("Override this method")
+
+ def get_dwarf_type_kind(self):
+ """
+ Implementations of this method should return the correct
+ DWARF_TYPE_CODE_* value for the wrapped type-object.
+ """
+ raise NotImplementedError("Override this method")
+
+ def get_fields(self):
+ """
+ Implementations of this method should return a list of field-objects of
+ this type. For Rust-enums (i.e. with DWARF_TYPE_CODE_UNION) these field-
+ objects represent the variants of the enum. Field-objects must have a
+ `name` attribute that gives their name as specified in DWARF.
+ """
+ assert ((self.get_dwarf_type_kind() == DWARF_TYPE_CODE_STRUCT) or
+ (self.get_dwarf_type_kind() == DWARF_TYPE_CODE_UNION))
+ raise NotImplementedError("Override this method")
+
+ def get_wrapped_value(self):
+ """
+ Returns the debugger-specific type-object wrapped by this object. This
+ is sometimes needed for doing things like pointer-arithmetic in GDB.
+ """
+ raise NotImplementedError("Override this method")
+
+ def get_type_kind(self):
+ """This method returns the TYPE_KIND_* value for this type-object."""
+ if self.__type_kind is None:
+ dwarf_type_code = self.get_dwarf_type_kind()
+
+ if dwarf_type_code == DWARF_TYPE_CODE_STRUCT:
+ self.__type_kind = self.__classify_struct()
+ elif dwarf_type_code == DWARF_TYPE_CODE_UNION:
+ self.__type_kind = self.__classify_union()
+ elif dwarf_type_code == DWARF_TYPE_CODE_PTR:
+ self.__type_kind = TYPE_KIND_PTR
+ elif dwarf_type_code == DWARF_TYPE_CODE_ARRAY:
+ self.__type_kind = TYPE_KIND_FIXED_SIZE_VEC
+ else:
+ self.__type_kind = TYPE_KIND_UNKNOWN
+ return self.__type_kind
+
+ def __classify_struct(self):
+ assert self.get_dwarf_type_kind() == DWARF_TYPE_CODE_STRUCT
+
+ unqualified_type_name = self.get_unqualified_type_name()
+
+ # STR SLICE
+ if unqualified_type_name == "&str":
+ return TYPE_KIND_STR_SLICE
+
+ # REGULAR SLICE
+ if (unqualified_type_name.startswith("&[") and
+ unqualified_type_name.endswith("]") and
+ self.__conforms_to_field_layout(SLICE_FIELD_NAMES)):
+ return TYPE_KIND_SLICE
+
+ fields = self.get_fields()
+ field_count = len(fields)
+
+ # EMPTY STRUCT
+ if field_count == 0:
+ return TYPE_KIND_EMPTY
+
+ # STD VEC
+ if (unqualified_type_name.startswith("Vec<") and
+ self.__conforms_to_field_layout(STD_VEC_FIELD_NAMES)):
+ return TYPE_KIND_STD_VEC
+
+ # STD STRING
+ if (unqualified_type_name.startswith("String") and
+ self.__conforms_to_field_layout(STD_STRING_FIELD_NAMES)):
+ return TYPE_KIND_STD_STRING
+
+ # ENUM VARIANTS
+ if fields[0].name == ENUM_DISR_FIELD_NAME:
+ if field_count == 1:
+ return TYPE_KIND_CSTYLE_VARIANT
+ elif self.__all_fields_conform_to_tuple_field_naming(1):
+ return TYPE_KIND_TUPLE_VARIANT
+ else:
+ return TYPE_KIND_STRUCT_VARIANT
+
+ # TUPLE
+ if self.__all_fields_conform_to_tuple_field_naming(0):
+ if unqualified_type_name.startswith("("):
+ return TYPE_KIND_TUPLE
+ else:
+ return TYPE_KIND_TUPLE_STRUCT
+
+ # REGULAR STRUCT
+ return TYPE_KIND_REGULAR_STRUCT
+
+
+ def __classify_union(self):
+ assert self.get_dwarf_type_kind() == DWARF_TYPE_CODE_UNION
+
+ union_members = self.get_fields()
+ union_member_count = len(union_members)
+ if union_member_count == 0:
+ return TYPE_KIND_EMPTY
+ elif union_member_count == 1:
+ first_variant_name = union_members[0].name
+ if first_variant_name is None:
+ return TYPE_KIND_SINGLETON_ENUM
+ else:
+ assert first_variant_name.startswith(ENCODED_ENUM_PREFIX)
+ return TYPE_KIND_COMPRESSED_ENUM
+ else:
+ return TYPE_KIND_REGULAR_ENUM
+
+
+ def __conforms_to_field_layout(self, expected_fields):
+ actual_fields = self.get_fields()
+ actual_field_count = len(actual_fields)
+
+ if actual_field_count != len(expected_fields):
+ return False
+
+ for i in range(0, actual_field_count):
+ if actual_fields[i].name != expected_fields[i]:
+ return False
+
+ return True
+
+ def __all_fields_conform_to_tuple_field_naming(self, start_index):
+ fields = self.get_fields()
+ field_count = len(fields)
+
+ for i in range(start_index, field_count):
+ field_name = fields[i].name
+ if (field_name is None) or (re.match(r"__\d+$", field_name) is None):
+ return False
+ return True
+
+
+class Value(object):
+ """
+ This class provides a common interface for value-oriented operations.
+ Sub-classes are supposed to wrap a debugger-specific value-object and
+ provide implementations for the abstract methods in this class.
+ """
+ def __init__(self, ty):
+ self.type = ty
+
+ def get_child_at_index(self, index):
+ """Returns the value of the field, array element or variant at the given index"""
+ raise NotImplementedError("Override this method")
+
+ def as_integer(self):
+ """
+ Try to convert the wrapped value into a Python integer. This should
+ always succeed for values that are pointers or actual integers.
+ """
+ raise NotImplementedError("Override this method")
+
+ def get_wrapped_value(self):
+ """
+ Returns the debugger-specific value-object wrapped by this object. This
+ is sometimes needed for doing things like pointer-arithmetic in GDB.
+ """
+ raise NotImplementedError("Override this method")
+
+
+class EncodedEnumInfo(object):
+ """
+ This class provides facilities for handling enum values with compressed
+ encoding where a non-null field in one variant doubles as the discriminant.
+ """
+
+ def __init__(self, enum_val):
+ assert enum_val.type.get_type_kind() == TYPE_KIND_COMPRESSED_ENUM
+ variant_name = enum_val.type.get_fields()[0].name
+ last_separator_index = variant_name.rfind("$")
+ start_index = len(ENCODED_ENUM_PREFIX)
+ indices_substring = variant_name[start_index:last_separator_index].split("$")
+ self.__enum_val = enum_val
+ self.__disr_field_indices = [int(index) for index in indices_substring]
+ self.__null_variant_name = variant_name[last_separator_index + 1:]
+
+ def is_null_variant(self):
+ ty = self.__enum_val.type
+ sole_variant_val = self.__enum_val.get_child_at_index(0)
+ discriminant_val = sole_variant_val
+ for disr_field_index in self.__disr_field_indices:
+ discriminant_val = discriminant_val.get_child_at_index(disr_field_index)
+
+ # If the discriminant field is a fat pointer we have to consider the
+ # first word as the true discriminant
+ if discriminant_val.type.get_dwarf_type_kind() == DWARF_TYPE_CODE_STRUCT:
+ discriminant_val = discriminant_val.get_child_at_index(0)
+
+ return discriminant_val.as_integer() == 0
+
+ def get_non_null_variant_val(self):
+ return self.__enum_val.get_child_at_index(0)
+
+ def get_null_variant_name(self):
+ return self.__null_variant_name
+
+
+def get_discriminant_value_as_integer(enum_val):
+ assert enum_val.type.get_dwarf_type_kind() == DWARF_TYPE_CODE_UNION
+ # we can take any variant here because the discriminant has to be the same
+ # for all of them.
+ variant_val = enum_val.get_child_at_index(0)
+ disr_val = variant_val.get_child_at_index(0)
+ return disr_val.as_integer()
+
+
+def extract_length_ptr_and_cap_from_std_vec(vec_val):
+ assert vec_val.type.get_type_kind() == TYPE_KIND_STD_VEC
+ length_field_index = STD_VEC_FIELD_NAMES.index(STD_VEC_FIELD_NAME_LENGTH)
+ ptr_field_index = STD_VEC_FIELD_NAMES.index(STD_VEC_FIELD_NAME_DATA_PTR)
+ cap_field_index = STD_VEC_FIELD_NAMES.index(STD_VEC_FIELD_NAME_CAPACITY)
+
+ length = vec_val.get_child_at_index(length_field_index).as_integer()
+ vec_ptr_val = vec_val.get_child_at_index(ptr_field_index)
+ capacity = vec_val.get_child_at_index(cap_field_index).as_integer()
+
+ unique_ptr_val = vec_ptr_val.get_child_at_index(0)
+ data_ptr = unique_ptr_val.get_child_at_index(0)
+ assert data_ptr.type.get_dwarf_type_kind() == DWARF_TYPE_CODE_PTR
+ return (length, data_ptr, capacity)
+
+def extract_length_and_ptr_from_slice(slice_val):
+ assert (slice_val.type.get_type_kind() == TYPE_KIND_SLICE or
+ slice_val.type.get_type_kind() == TYPE_KIND_STR_SLICE)
+
+ length_field_index = SLICE_FIELD_NAMES.index(SLICE_FIELD_NAME_LENGTH)
+ ptr_field_index = SLICE_FIELD_NAMES.index(SLICE_FIELD_NAME_DATA_PTR)
+
+ length = slice_val.get_child_at_index(length_field_index).as_integer()
+ data_ptr = slice_val.get_child_at_index(ptr_field_index)
+
+ assert data_ptr.type.get_dwarf_type_kind() == DWARF_TYPE_CODE_PTR
+ return (length, data_ptr)
import re
if len(sys.argv) < 2:
- print "usage: errorck.py <src-dir>"
+ print("usage: errorck.py <src-dir>")
sys.exit(1)
src_dir = sys.argv[1]
# since the same version
# * Prints information about features
-import sys, os, re
+import sys
+import os
+import re
+import codecs
if len(sys.argv) < 2:
- print "usage: featurkck.py <src-dir>"
+ print("usage: featureck.py <src-dir>")
sys.exit(1)
src_dir = sys.argv[1]
line = line.replace("(", "").replace("),", "").replace(")", "")
parts = line.split(",")
if len(parts) != 3:
- print "error: unexpected number of components in line: " + original_line
+ print("error: unexpected number of components in line: " + original_line)
sys.exit(1)
feature_name = parts[0].strip().replace('"', "")
since = parts[1].strip().replace('"', "")
continue
path = os.path.join(dirpath, filename)
- with open(path, 'r') as f:
+ with codecs.open(filename=path, mode='r', encoding="utf-8") as f:
line_num = 0
for line in f:
line_num += 1
if not mm is None:
since = mm.group(1)
else:
- print "error: misformed stability attribute"
- print "line " + str(line_num) + " of " + path + ":"
- print line
+ print("error: misformed stability attribute")
+ print("line %d of %:" % (line_num, path))
+ print(line)
errors = True
lib_features[feature_name] = feature_name
(expected_since, source_path, source_line_num, source_line) = \
lib_features_and_level.get((feature_name, level))
if since != expected_since:
- print "error: mismatch in " + level + " feature '" + feature_name + "'"
- print "line " + str(source_line_num) + " of " + source_path + ":"
- print source_line
- print "line " + str(line_num) + " of " + path + ":"
- print line
+ print("error: mismatch in %s feature '%s'" % (level, feature_name))
+ print("line %d of %s:" % (source_line_num, source_path))
+ print(source_line)
+ print("line %d of %s:" % (line_num, path))
+ print(line)
errors = True
# Verify that this lib feature doesn't duplicate a lang feature
if feature_name in language_feature_names:
- print "error: lib feature '" + feature_name + "' duplicates a lang feature"
- print "line " + str(line_num) + " of " + path + ":"
- print line
+ print("error: lib feature '%s' duplicates a lang feature" % (feature_name))
+ print("line %d of %s:" % (line_num, path))
+ print(line)
errors = True
else:
- print "error: misformed stability attribute"
- print "line " + str(line_num) + " of " + path + ":"
- print line
+ print("error: misformed stability attribute")
+ print("line %d of %s:" % (line_num, path))
+ print(line)
errors = True
# Merge data about both lists
is_unstable = lib_features_and_level.get((name, "unstable")) is not None
if is_stable and is_unstable:
- print "error: feature '" + name + "' is both stable and unstable"
+ print("error: feature '%s' is both stable and unstable" % (name))
errors = True
if is_stable:
for name in lib_feature_stats:
if language_feature_stats.get(name) is not None:
if not name in joint_features:
- print "error: feature '" + name + "' is both a lang and lib feature but not whitelisted"
+ print("error: feature '%s' is both a lang and lib feature but not whitelisted" % (name))
errors = True
lang_status = language_feature_stats[name][3]
lib_status = lib_feature_stats[name][3]
lib_stable_since = lib_feature_stats[name][4]
if lang_status != lib_status and lib_status != "deprecated":
- print "error: feature '" + name + "' has lang status " + lang_status + \
- " but lib status " + lib_status
+ print("error: feature '%s' has lang status %s " +
+ "but lib status %s" % (name, lang_status, lib_status))
errors = True
if lang_stable_since != lib_stable_since:
- print "error: feature '" + name + "' has lang stable since " + lang_stable_since + \
- " but lib stable since " + lib_stable_since
+ print("error: feature '%s' has lang stable since %s " +
+ "but lib stable since %s" % (name, lang_stable_since, lib_stable_since))
errors = True
merged_stats[name] = (name, True, True, lang_status, lang_stable_since)
print
for line in lines:
- print "* " + line
+ print("* " + line)
print
import gdb
import re
+import debugger_pretty_printers_common as rustpp
#===============================================================================
# GDB Pretty Printing Module for Rust
#===============================================================================
+class GdbType(rustpp.Type):
-def register_printers(objfile):
- "Registers Rust pretty printers for the given objfile"
- objfile.pretty_printers.append(rust_pretty_printer_lookup_function)
+ def __init__(self, ty):
+ super(GdbType, self).__init__()
+ self.ty = ty
+ self.fields = None
+ def get_unqualified_type_name(self):
+ tag = self.ty.tag
-def rust_pretty_printer_lookup_function(val):
- "Returns the correct Rust pretty printer for the given value if there is one"
- type_code = val.type.code
+ if tag is None:
+ return tag
- if type_code == gdb.TYPE_CODE_STRUCT:
- struct_kind = classify_struct(val.type)
+ return tag.replace("&'static ", "&")
- if struct_kind == STRUCT_KIND_SLICE:
- return RustSlicePrinter(val)
+ def get_dwarf_type_kind(self):
+ if self.ty.code == gdb.TYPE_CODE_STRUCT:
+ return rustpp.DWARF_TYPE_CODE_STRUCT
- if struct_kind == STRUCT_KIND_STR_SLICE:
- return RustStringSlicePrinter(val)
+ if self.ty.code == gdb.TYPE_CODE_UNION:
+ return rustpp.DWARF_TYPE_CODE_UNION
- if struct_kind == STRUCT_KIND_STD_VEC:
- return RustStdVecPrinter(val)
+ if self.ty.code == gdb.TYPE_CODE_PTR:
+ return rustpp.DWARF_TYPE_CODE_PTR
- if struct_kind == STRUCT_KIND_STD_STRING:
- return RustStdStringPrinter(val)
+ if self.ty.code == gdb.TYPE_CODE_ENUM:
+ return rustpp.DWARF_TYPE_CODE_ENUM
- if struct_kind == STRUCT_KIND_TUPLE:
- return RustTuplePrinter(val)
+ def get_fields(self):
+ assert ((self.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_STRUCT) or
+ (self.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_UNION))
+ if self.fields is None:
+ self.fields = list(self.ty.fields())
+ return self.fields
- if struct_kind == STRUCT_KIND_TUPLE_STRUCT:
- return RustTupleStructPrinter(val, False)
+ def get_wrapped_value(self):
+ return self.ty
- if struct_kind == STRUCT_KIND_CSTYLE_VARIANT:
- return RustCStyleEnumPrinter(val[get_field_at_index(val, 0)])
- if struct_kind == STRUCT_KIND_TUPLE_VARIANT:
- return RustTupleStructPrinter(val, True)
+class GdbValue(rustpp.Value):
+ def __init__(self, gdb_val):
+ super(GdbValue, self).__init__(GdbType(gdb_val.type))
+ self.gdb_val = gdb_val
+ self.children = {}
- if struct_kind == STRUCT_KIND_STRUCT_VARIANT:
- return RustStructPrinter(val, True)
+ def get_child_at_index(self, index):
+ child = self.children.get(index)
+ if child is None:
+ gdb_field = get_field_at_index(self.gdb_val, index)
+ child = GdbValue(self.gdb_val[gdb_field])
+ self.children[index] = child
+ return child
- return RustStructPrinter(val, False)
+ def as_integer(self):
+ return int(self.gdb_val)
- # Enum handling
- if type_code == gdb.TYPE_CODE_UNION:
- enum_members = list(val.type.fields())
- enum_member_count = len(enum_members)
+ def get_wrapped_value(self):
+ return self.gdb_val
- if enum_member_count == 0:
- return RustStructPrinter(val, False)
- if enum_member_count == 1:
- first_variant_name = enum_members[0].name
- if first_variant_name is None:
- # This is a singleton enum
- return rust_pretty_printer_lookup_function(val[enum_members[0]])
- else:
- assert first_variant_name.startswith("RUST$ENCODED$ENUM$")
- # This is a space-optimized enum.
- # This means this enum has only two states, and Rust uses one
- # of the fields somewhere in the struct to determine which of
- # the two states it's in. The location of the field is encoded
- # in the name as something like
- # RUST$ENCODED$ENUM$(num$)*name_of_zero_state
- last_separator_index = first_variant_name.rfind("$")
- start_index = len("RUST$ENCODED$ENUM$")
- disr_field_indices = first_variant_name[start_index:last_separator_index].split("$")
- disr_field_indices = [int(index) for index in disr_field_indices]
-
- sole_variant_val = val[enum_members[0]]
- discriminant = sole_variant_val
- for disr_field_index in disr_field_indices:
- disr_field = get_field_at_index(discriminant, disr_field_index)
- discriminant = discriminant[disr_field]
-
- # If the discriminant field is a fat pointer we have to consider the
- # first word as the true discriminant
- if discriminant.type.code == gdb.TYPE_CODE_STRUCT:
- discriminant = discriminant[get_field_at_index(discriminant, 0)]
-
- if discriminant == 0:
- null_variant_name = first_variant_name[last_separator_index + 1:]
- return IdentityPrinter(null_variant_name)
-
- return rust_pretty_printer_lookup_function(sole_variant_val)
+def register_printers(objfile):
+ """Registers Rust pretty printers for the given objfile"""
+ objfile.pretty_printers.append(rust_pretty_printer_lookup_function)
- # This is a regular enum, extract the discriminant
- discriminant_name, discriminant_val = extract_discriminant_value(val)
- return rust_pretty_printer_lookup_function(val[enum_members[discriminant_val]])
- # No pretty printer has been found
- return None
+def rust_pretty_printer_lookup_function(gdb_val):
+ """
+ Returns the correct Rust pretty printer for the given value
+ if there is one
+ """
-#=------------------------------------------------------------------------------
-# Pretty Printer Classes
-#=------------------------------------------------------------------------------
+ val = GdbValue(gdb_val)
+ type_kind = val.type.get_type_kind()
+ if (type_kind == rustpp.TYPE_KIND_REGULAR_STRUCT or
+ type_kind == rustpp.TYPE_KIND_EMPTY):
+ return RustStructPrinter(val,
+ omit_first_field = False,
+ omit_type_name = False,
+ is_tuple_like = False)
-class RustStructPrinter:
- def __init__(self, val, hide_first_field):
- self.val = val
- self.hide_first_field = hide_first_field
+ if type_kind == rustpp.TYPE_KIND_STRUCT_VARIANT:
+ return RustStructPrinter(val,
+ omit_first_field = True,
+ omit_type_name = False,
+ is_tuple_like = False)
- def to_string(self):
- return self.val.type.tag
+ if type_kind == rustpp.TYPE_KIND_SLICE:
+ return RustSlicePrinter(val)
- def children(self):
- cs = []
- for field in self.val.type.fields():
- field_name = field.name
- # Normally the field name is used as a key to access the field
- # value, because that's also supported in older versions of GDB...
- field_key = field_name
- if field_name is None:
- field_name = ""
- # ... but for fields without a name (as in tuples), we have to
- # fall back to the newer method of using the field object
- # directly as key. In older versions of GDB, this will just
- # fail.
- field_key = field
- name_value_tuple = (field_name, self.val[field_key])
- cs.append(name_value_tuple)
-
- if self.hide_first_field:
- cs = cs[1:]
+ if type_kind == rustpp.TYPE_KIND_STR_SLICE:
+ return RustStringSlicePrinter(val)
- return cs
+ if type_kind == rustpp.TYPE_KIND_STD_VEC:
+ return RustStdVecPrinter(val)
+ if type_kind == rustpp.TYPE_KIND_STD_STRING:
+ return RustStdStringPrinter(val)
-class RustTuplePrinter:
- def __init__(self, val):
- self.val = val
+ if type_kind == rustpp.TYPE_KIND_TUPLE:
+ return RustStructPrinter(val,
+ omit_first_field = False,
+ omit_type_name = True,
+ is_tuple_like = True)
- def to_string(self):
- return None
+ if type_kind == rustpp.TYPE_KIND_TUPLE_STRUCT:
+ return RustStructPrinter(val,
+ omit_first_field = False,
+ omit_type_name = False,
+ is_tuple_like = True)
- def children(self):
- cs = []
- for field in self.val.type.fields():
- cs.append(("", self.val[field]))
+ if type_kind == rustpp.TYPE_KIND_CSTYLE_VARIANT:
+ return RustCStyleVariantPrinter(val.get_child_at_index(0))
- return cs
+ if type_kind == rustpp.TYPE_KIND_TUPLE_VARIANT:
+ return RustStructPrinter(val,
+ omit_first_field = True,
+ omit_type_name = False,
+ is_tuple_like = True)
- def display_hint(self):
- return "array"
+ if type_kind == rustpp.TYPE_KIND_SINGLETON_ENUM:
+ variant = get_field_at_index(gdb_val, 0)
+ return rust_pretty_printer_lookup_function(gdb_val[variant])
+ if type_kind == rustpp.TYPE_KIND_REGULAR_ENUM:
+ # This is a regular enum, extract the discriminant
+ discriminant_val = rustpp.get_discriminant_value_as_integer(val)
+ variant = get_field_at_index(gdb_val, discriminant_val)
+ return rust_pretty_printer_lookup_function(gdb_val[variant])
+
+ if type_kind == rustpp.TYPE_KIND_COMPRESSED_ENUM:
+ encoded_enum_info = rustpp.EncodedEnumInfo(val)
+ if encoded_enum_info.is_null_variant():
+ return IdentityPrinter(encoded_enum_info.get_null_variant_name())
-class RustTupleStructPrinter:
- def __init__(self, val, hide_first_field):
- self.val = val
- self.hide_first_field = hide_first_field
+ non_null_val = encoded_enum_info.get_non_null_variant_val()
+ return rust_pretty_printer_lookup_function(non_null_val.get_wrapped_value())
+
+ # No pretty printer has been found
+ return None
+
+
+#=------------------------------------------------------------------------------
+# Pretty Printer Classes
+#=------------------------------------------------------------------------------
+class RustStructPrinter:
+ def __init__(self, val, omit_first_field, omit_type_name, is_tuple_like):
+ self.__val = val
+ self.__omit_first_field = omit_first_field
+ self.__omit_type_name = omit_type_name
+ self.__is_tuple_like = is_tuple_like
def to_string(self):
- return self.val.type.tag
+ if self.__omit_type_name:
+ return None
+ return self.__val.type.get_unqualified_type_name()
def children(self):
cs = []
- for field in self.val.type.fields():
- cs.append(("", self.val[field]))
+ wrapped_value = self.__val.get_wrapped_value()
+
+ for field in self.__val.type.get_fields():
+ field_value = wrapped_value[field.name]
+ if self.__is_tuple_like:
+ cs.append(("", field_value))
+ else:
+ cs.append((field.name, field_value))
- if self.hide_first_field:
+ if self.__omit_first_field:
cs = cs[1:]
return cs
def display_hint(self):
- return "array"
+ if self.__is_tuple_like:
+ return "array"
+ else:
+ return ""
+
class RustSlicePrinter:
def __init__(self, val):
- self.val = val
+ self.__val = val
def display_hint(self):
return "array"
def to_string(self):
- length = int(self.val["length"])
- return self.val.type.tag + ("(len: %i)" % length)
+ (length, data_ptr) = rustpp.extract_length_and_ptr_from_slice(self.__val)
+ return (self.__val.type.get_unqualified_type_name() +
+ ("(len: %i)" % length))
def children(self):
cs = []
- length = int(self.val["length"])
- data_ptr = self.val["data_ptr"]
- assert data_ptr.type.code == gdb.TYPE_CODE_PTR
- pointee_type = data_ptr.type.target()
+ (length, data_ptr) = rustpp.extract_length_and_ptr_from_slice(self.__val)
+ assert data_ptr.type.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_PTR
+ raw_ptr = data_ptr.get_wrapped_value()
for index in range(0, length):
- cs.append((str(index), (data_ptr + index).dereference()))
+ cs.append((str(index), (raw_ptr + index).dereference()))
return cs
+
class RustStringSlicePrinter:
def __init__(self, val):
- self.val = val
+ self.__val = val
def to_string(self):
- slice_byte_len = self.val["length"]
- return '"%s"' % self.val["data_ptr"].string(encoding="utf-8", length=slice_byte_len)
+ (length, data_ptr) = rustpp.extract_length_and_ptr_from_slice(self.__val)
+ raw_ptr = data_ptr.get_wrapped_value()
+ return '"%s"' % raw_ptr.string(encoding="utf-8", length=length)
+
class RustStdVecPrinter:
def __init__(self, val):
- self.val = val
+ self.__val = val
def display_hint(self):
return "array"
def to_string(self):
- length = int(self.val["len"])
- cap = int(self.val["cap"])
- return self.val.type.tag + ("(len: %i, cap: %i)" % (length, cap))
+ (length, data_ptr, cap) = rustpp.extract_length_ptr_and_cap_from_std_vec(self.__val)
+ return (self.__val.type.get_unqualified_type_name() +
+ ("(len: %i, cap: %i)" % (length, cap)))
def children(self):
cs = []
- (length, data_ptr) = extract_length_and_data_ptr_from_std_vec(self.val)
- pointee_type = data_ptr.type.target()
-
+ (length, data_ptr, cap) = rustpp.extract_length_ptr_and_cap_from_std_vec(self.__val)
+ gdb_ptr = data_ptr.get_wrapped_value()
for index in range(0, length):
- cs.append((str(index), (data_ptr + index).dereference()))
+ cs.append((str(index), (gdb_ptr + index).dereference()))
return cs
+
class RustStdStringPrinter:
def __init__(self, val):
- self.val = val
+ self.__val = val
def to_string(self):
- (length, data_ptr) = extract_length_and_data_ptr_from_std_vec(self.val["vec"])
- return '"%s"' % data_ptr.string(encoding="utf-8", length=length)
+ vec = self.__val.get_child_at_index(0)
+ (length, data_ptr, cap) = rustpp.extract_length_ptr_and_cap_from_std_vec(vec)
+ return '"%s"' % data_ptr.get_wrapped_value().string(encoding="utf-8",
+ length=length)
-class RustCStyleEnumPrinter:
+class RustCStyleVariantPrinter:
def __init__(self, val):
- assert val.type.code == gdb.TYPE_CODE_ENUM
- self.val = val
+ assert val.type.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_ENUM
+ self.__val = val
def to_string(self):
- return str(self.val)
+ return str(self.__val.get_wrapped_value())
class IdentityPrinter:
def to_string(self):
return self.string
-STRUCT_KIND_REGULAR_STRUCT = 0
-STRUCT_KIND_TUPLE_STRUCT = 1
-STRUCT_KIND_TUPLE = 2
-STRUCT_KIND_TUPLE_VARIANT = 3
-STRUCT_KIND_STRUCT_VARIANT = 4
-STRUCT_KIND_CSTYLE_VARIANT = 5
-STRUCT_KIND_SLICE = 6
-STRUCT_KIND_STR_SLICE = 7
-STRUCT_KIND_STD_VEC = 8
-STRUCT_KIND_STD_STRING = 9
-
-
-def classify_struct(type):
- # print("\nclassify_struct: tag=%s\n" % type.tag)
- if type.tag == "&str":
- return STRUCT_KIND_STR_SLICE
-
- if type.tag.startswith("&[") and type.tag.endswith("]"):
- return STRUCT_KIND_SLICE
-
- fields = list(type.fields())
- field_count = len(fields)
-
- if field_count == 0:
- return STRUCT_KIND_REGULAR_STRUCT
-
- if (field_count == 3 and
- fields[0].name == "ptr" and
- fields[1].name == "len" and
- fields[2].name == "cap" and
- type.tag.startswith("Vec<")):
- return STRUCT_KIND_STD_VEC
-
- if (field_count == 1 and
- fields[0].name == "vec" and
- type.tag == "String"):
- return STRUCT_KIND_STD_STRING
-
- if fields[0].name == "RUST$ENUM$DISR":
- if field_count == 1:
- return STRUCT_KIND_CSTYLE_VARIANT
- elif all_fields_conform_to_tuple_field_naming(fields, 1):
- return STRUCT_KIND_TUPLE_VARIANT
- else:
- return STRUCT_KIND_STRUCT_VARIANT
-
- if all_fields_conform_to_tuple_field_naming(fields, 0):
- if type.tag.startswith("("):
- return STRUCT_KIND_TUPLE
- else:
- return STRUCT_KIND_TUPLE_STRUCT
- return STRUCT_KIND_REGULAR_STRUCT
-
-
-def extract_discriminant_value(enum_val):
- assert enum_val.type.code == gdb.TYPE_CODE_UNION
- for variant_descriptor in enum_val.type.fields():
- variant_val = enum_val[variant_descriptor]
- for field in variant_val.type.fields():
- return (field.name, int(variant_val[field]))
-
-
-def first_field(val):
- for field in val.type.fields():
- return field
-
-def get_field_at_index(val, index):
+def get_field_at_index(gdb_val, index):
i = 0
- for field in val.type.fields():
+ for field in gdb_val.type.fields():
if i == index:
return field
i += 1
return None
-
-def all_fields_conform_to_tuple_field_naming(fields, start_index):
- for i in range(start_index, len(fields)):
- if (fields[i].name is None) or (re.match(r"__\d+$", fields[i].name) is None):
- return False
- return True
-
-def extract_length_and_data_ptr_from_std_vec(vec_val):
- length = int(vec_val["len"])
- vec_ptr_val = vec_val["ptr"]
- unique_ptr_val = vec_ptr_val[first_field(vec_ptr_val)]
- data_ptr = unique_ptr_val[first_field(unique_ptr_val)]
- assert data_ptr.type.code == gdb.TYPE_CODE_PTR
- return (length, data_ptr)
import lldb
import re
+import debugger_pretty_printers_common as rustpp
-def print_val(val, internal_dict):
- '''Prints the given value with Rust syntax'''
- type_class = val.GetType().GetTypeClass()
+#===============================================================================
+# LLDB Pretty Printing Module for Rust
+#===============================================================================
- if type_class == lldb.eTypeClassStruct:
- return print_struct_val(val, internal_dict)
+class LldbType(rustpp.Type):
- if type_class == lldb.eTypeClassUnion:
- return print_enum_val(val, internal_dict)
+ def __init__(self, ty):
+ super(LldbType, self).__init__()
+ self.ty = ty
+ self.fields = None
- if type_class == lldb.eTypeClassPointer:
- return print_pointer_val(val, internal_dict)
+ def get_unqualified_type_name(self):
+ qualified_name = self.ty.GetName()
- if type_class == lldb.eTypeClassArray:
- return print_fixed_size_vec_val(val, internal_dict)
+ if qualified_name is None:
+ return qualified_name
- return val.GetValue()
+ return extract_type_name(qualified_name).replace("&'static ", "&")
+ def get_dwarf_type_kind(self):
+ type_class = self.ty.GetTypeClass()
-#=--------------------------------------------------------------------------------------------------
-# Type-Specialized Printing Functions
-#=--------------------------------------------------------------------------------------------------
+ if type_class == lldb.eTypeClassStruct:
+ return rustpp.DWARF_TYPE_CODE_STRUCT
+
+ if type_class == lldb.eTypeClassUnion:
+ return rustpp.DWARF_TYPE_CODE_UNION
+
+ if type_class == lldb.eTypeClassPointer:
+ return rustpp.DWARF_TYPE_CODE_PTR
+
+ if type_class == lldb.eTypeClassArray:
+ return rustpp.DWARF_TYPE_CODE_ARRAY
+
+ if type_class == lldb.eTypeClassEnumeration:
+ return rustpp.DWARF_TYPE_CODE_ENUM
+
+ return None
+
+ def get_fields(self):
+ assert ((self.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_STRUCT) or
+ (self.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_UNION))
+ if self.fields is None:
+ self.fields = list(self.ty.fields)
+ return self.fields
+
+ def get_wrapped_value(self):
+ return self.ty
+
+
+class LldbValue(rustpp.Value):
+ def __init__(self, lldb_val):
+ ty = lldb_val.type
+ wty = LldbType(ty)
+ super(LldbValue, self).__init__(wty)
+ self.lldb_val = lldb_val
+ self.children = {}
+
+ def get_child_at_index(self, index):
+ child = self.children.get(index)
+ if child is None:
+ lldb_field = self.lldb_val.GetChildAtIndex(index)
+ child = LldbValue(lldb_field)
+ self.children[index] = child
+ return child
+
+ def as_integer(self):
+ return self.lldb_val.GetValueAsUnsigned()
+
+ def get_wrapped_value(self):
+ return self.lldb_val
+
+
+def print_val(lldb_val, internal_dict):
+ val = LldbValue(lldb_val)
+ type_kind = val.type.get_type_kind()
-def print_struct_val(val, internal_dict):
- '''Prints a struct, tuple, or tuple struct value with Rust syntax'''
- assert val.GetType().GetTypeClass() == lldb.eTypeClassStruct
+ if (type_kind == rustpp.TYPE_KIND_REGULAR_STRUCT or
+ type_kind == rustpp.TYPE_KIND_EMPTY):
+ return print_struct_val(val,
+ internal_dict,
+ omit_first_field = False,
+ omit_type_name = False,
+ is_tuple_like = False)
- if is_vec_slice(val):
+ if type_kind == rustpp.TYPE_KIND_STRUCT_VARIANT:
+ return print_struct_val(val,
+ internal_dict,
+ omit_first_field = True,
+ omit_type_name = False,
+ is_tuple_like = False)
+
+ if type_kind == rustpp.TYPE_KIND_SLICE:
return print_vec_slice_val(val, internal_dict)
- elif is_std_vec(val):
+
+ if type_kind == rustpp.TYPE_KIND_STR_SLICE:
+ return print_str_slice_val(val, internal_dict)
+
+ if type_kind == rustpp.TYPE_KIND_STD_VEC:
return print_std_vec_val(val, internal_dict)
- else:
- return print_struct_val_starting_from(0, val, internal_dict)
+ if type_kind == rustpp.TYPE_KIND_STD_STRING:
+ return print_std_string_val(val, internal_dict)
+
+ if type_kind == rustpp.TYPE_KIND_TUPLE:
+ return print_struct_val(val,
+ internal_dict,
+ omit_first_field = False,
+ omit_type_name = True,
+ is_tuple_like = True)
+
+ if type_kind == rustpp.TYPE_KIND_TUPLE_STRUCT:
+ return print_struct_val(val,
+ internal_dict,
+ omit_first_field = False,
+ omit_type_name = False,
+ is_tuple_like = True)
+
+ if type_kind == rustpp.TYPE_KIND_CSTYLE_VARIANT:
+ return val.type.get_unqualified_type_name()
+
+ if type_kind == rustpp.TYPE_KIND_TUPLE_VARIANT:
+ return print_struct_val(val,
+ internal_dict,
+ omit_first_field = True,
+ omit_type_name = False,
+ is_tuple_like = True)
+
+ if type_kind == rustpp.TYPE_KIND_SINGLETON_ENUM:
+ return print_val(lldb_val.GetChildAtIndex(0), internal_dict)
+
+ if type_kind == rustpp.TYPE_KIND_PTR:
+ return print_pointer_val(val, internal_dict)
+
+ if type_kind == rustpp.TYPE_KIND_FIXED_SIZE_VEC:
+ return print_fixed_size_vec_val(val, internal_dict)
+
+ if type_kind == rustpp.TYPE_KIND_REGULAR_ENUM:
+ # This is a regular enum, extract the discriminant
+ discriminant_val = rustpp.get_discriminant_value_as_integer(val)
+ return print_val(lldb_val.GetChildAtIndex(discriminant_val), internal_dict)
+
+ if type_kind == rustpp.TYPE_KIND_COMPRESSED_ENUM:
+ encoded_enum_info = rustpp.EncodedEnumInfo(val)
+ if encoded_enum_info.is_null_variant():
+ return encoded_enum_info.get_null_variant_name()
-def print_struct_val_starting_from(field_start_index, val, internal_dict):
+ non_null_val = encoded_enum_info.get_non_null_variant_val()
+ return print_val(non_null_val.get_wrapped_value(), internal_dict)
+
+ # No pretty printer has been found
+ return lldb_val.GetValue()
+
+
+#=--------------------------------------------------------------------------------------------------
+# Type-Specialized Printing Functions
+#=--------------------------------------------------------------------------------------------------
+
+def print_struct_val(val, internal_dict, omit_first_field, omit_type_name, is_tuple_like):
'''
Prints a struct, tuple, or tuple struct value with Rust syntax.
Ignores any fields before field_start_index.
'''
- assert val.GetType().GetTypeClass() == lldb.eTypeClassStruct
-
- t = val.GetType()
- type_name = extract_type_name(t.GetName())
- num_children = val.num_children
-
- if (num_children - field_start_index) == 0:
- # The only field of this struct is the enum discriminant
- return type_name
+ assert val.type.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_STRUCT
- is_tuple_like = type_is_tuple_like(t)
+ if omit_type_name:
+ type_name = ""
+ else:
+ type_name = val.type.get_unqualified_type_name()
if is_tuple_like:
template = "%(type_name)s(%(body)s)"
template = "%(type_name)s {\n%(body)s\n}"
separator = ", \n"
- if type_name.startswith("("):
- # this is a tuple, so don't print the type name
- type_name = ""
+ fields = val.type.get_fields()
def render_child(child_index):
this = ""
if not is_tuple_like:
- field_name = t.GetFieldAtIndex(child_index).GetName()
+ field_name = fields[child_index].name
this += field_name + ": "
- field_val = val.GetChildAtIndex(child_index)
+ field_val = val.get_child_at_index(child_index)
- if not field_val.IsValid():
- field = t.GetFieldAtIndex(child_index)
+ if not field_val.get_wrapped_value().IsValid():
+ field = fields[child_index]
# LLDB is not good at handling zero-sized values, so we have to help
# it a little
if field.GetType().GetByteSize() == 0:
else:
return this + "<invalid value>"
- return this + print_val(field_val, internal_dict)
+ return this + print_val(field_val.get_wrapped_value(), internal_dict)
+
+ if omit_first_field:
+ field_start_index = 1
+ else:
+ field_start_index = 0
- body = separator.join([render_child(idx) for idx in range(field_start_index, num_children)])
+ body = separator.join([render_child(idx) for idx in range(field_start_index, len(fields))])
return template % {"type_name": type_name,
"body": body}
-
-def print_enum_val(val, internal_dict):
- '''Prints an enum value with Rust syntax'''
-
- assert val.GetType().GetTypeClass() == lldb.eTypeClassUnion
-
- if val.num_children == 1:
- # This is either an enum with just one variant, or it is an Option-like
- # enum where the discriminant is encoded in a non-nullable pointer
- # field. We find out which one it is by looking at the member name of
- # the sole union variant. If it starts with "RUST$ENCODED$ENUM$" then
- # we have an Option-like enum.
- first_variant_name = val.GetChildAtIndex(0).GetName()
- if first_variant_name and first_variant_name.startswith("RUST$ENCODED$ENUM$"):
-
- # This is an Option-like enum. The position of the discriminator field is
- # encoded in the name which has the format:
- # RUST$ENCODED$ENUM$<index of discriminator field>$<name of null variant>
- last_separator_index = first_variant_name.rfind("$")
- if last_separator_index == -1:
- return "<invalid enum encoding: %s>" % first_variant_name
-
- start_index = len("RUST$ENCODED$ENUM$")
-
- # Extract indices of the discriminator field
- try:
- disr_field_indices = first_variant_name[start_index:last_separator_index].split("$")
- disr_field_indices = [int(index) for index in disr_field_indices]
- except:
- return "<invalid enum encoding: %s>" % first_variant_name
-
- # Read the discriminant
- disr_val = val.GetChildAtIndex(0)
- for index in disr_field_indices:
- disr_val = disr_val.GetChildAtIndex(index)
-
- # If the discriminant field is a fat pointer we have to consider the
- # first word as the true discriminant
- if disr_val.GetType().GetTypeClass() == lldb.eTypeClassStruct:
- disr_val = disr_val.GetChildAtIndex(0)
-
- if disr_val.GetValueAsUnsigned() == 0:
- # Null case: Print the name of the null-variant
- null_variant_name = first_variant_name[last_separator_index + 1:]
- return null_variant_name
- else:
- # Non-null case: Interpret the data as a value of the non-null variant type
- return print_struct_val_starting_from(0, val.GetChildAtIndex(0), internal_dict)
- else:
- # This is just a regular uni-variant enum without discriminator field
- return print_struct_val_starting_from(0, val.GetChildAtIndex(0), internal_dict)
-
- # If we are here, this is a regular enum with more than one variant
- disr_val = val.GetChildAtIndex(0).GetChildMemberWithName("RUST$ENUM$DISR")
- disr_type = disr_val.GetType()
-
- if disr_type.GetTypeClass() != lldb.eTypeClassEnumeration:
- return "<Invalid enum value encountered: Discriminator is not an enum>"
-
- variant_index = disr_val.GetValueAsUnsigned()
- return print_struct_val_starting_from(1, val.GetChildAtIndex(variant_index), internal_dict)
-
-
def print_pointer_val(val, internal_dict):
'''Prints a pointer value with Rust syntax'''
- assert val.GetType().IsPointerType()
+ assert val.type.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_PTR
sigil = "&"
- type_name = extract_type_name(val.GetType().GetName())
- if type_name and type_name[0:1] in ["&", "~", "*"]:
+ type_name = val.type.get_unqualified_type_name()
+ if type_name and type_name[0:1] in ["&", "*"]:
sigil = type_name[0:1]
- return sigil + hex(val.GetValueAsUnsigned()) #print_val(val.Dereference(), internal_dict)
+ return sigil + hex(val.as_integer())
def print_fixed_size_vec_val(val, internal_dict):
- assert val.GetType().GetTypeClass() == lldb.eTypeClassArray
+ assert val.type.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_ARRAY
+ lldb_val = val.get_wrapped_value()
output = "["
- for i in range(val.num_children):
- output += print_val(val.GetChildAtIndex(i), internal_dict)
- if i != val.num_children - 1:
+ for i in range(lldb_val.num_children):
+ output += print_val(lldb_val.GetChildAtIndex(i), internal_dict)
+ if i != lldb_val.num_children - 1:
output += ", "
output += "]"
def print_vec_slice_val(val, internal_dict):
- length = val.GetChildAtIndex(1).GetValueAsUnsigned()
-
- data_ptr_val = val.GetChildAtIndex(0)
- data_ptr_type = data_ptr_val.GetType()
-
- return "&[%s]" % print_array_of_values(val.GetName(),
- data_ptr_val,
+ (length, data_ptr) = rustpp.extract_length_and_ptr_from_slice(val)
+ return "&[%s]" % print_array_of_values(val.get_wrapped_value().GetName(),
+ data_ptr,
length,
internal_dict)
def print_std_vec_val(val, internal_dict):
- length = val.GetChildAtIndex(1).GetValueAsUnsigned()
-
- # Vec<> -> Unique<> -> NonZero<> -> *T
- data_ptr_val = val.GetChildAtIndex(0).GetChildAtIndex(0).GetChildAtIndex(0)
- data_ptr_type = data_ptr_val.GetType()
-
- return "vec![%s]" % print_array_of_values(val.GetName(),
- data_ptr_val,
+ (length, data_ptr, cap) = rustpp.extract_length_ptr_and_cap_from_std_vec(val)
+ return "vec![%s]" % print_array_of_values(val.get_wrapped_value().GetName(),
+ data_ptr,
length,
internal_dict)
+def print_str_slice_val(val, internal_dict):
+ (length, data_ptr) = rustpp.extract_length_and_ptr_from_slice(val)
+ return read_utf8_string(data_ptr, length)
+
+def print_std_string_val(val, internal_dict):
+ vec = val.get_child_at_index(0)
+ (length, data_ptr, cap) = rustpp.extract_length_ptr_and_cap_from_std_vec(vec)
+ return read_utf8_string(data_ptr, length)
+
#=--------------------------------------------------------------------------------------------------
# Helper Functions
#=--------------------------------------------------------------------------------------------------
-unqualified_type_markers = frozenset(["(", "[", "&", "*"])
-
+UNQUALIFIED_TYPE_MARKERS = frozenset(["(", "[", "&", "*"])
def extract_type_name(qualified_type_name):
'''Extracts the type name from a fully qualified path'''
- if qualified_type_name[0] in unqualified_type_markers:
+ if qualified_type_name[0] in UNQUALIFIED_TYPE_MARKERS:
return qualified_type_name
end_of_search = qualified_type_name.find("<")
else:
return qualified_type_name[index + 2:]
-
-def type_is_tuple_like(ty):
- '''Returns true of this is a type with field names (struct, struct-like enum variant)'''
- for field in ty.fields:
- if field.GetName() == "RUST$ENUM$DISR":
- # Ignore the enum discriminant field if there is one.
- continue
- if (field.GetName() is None) or (re.match(r"__\d+$", field.GetName()) is None):
- return False
- return True
-
-
-def is_vec_slice(val):
- ty = val.GetType()
- if ty.GetTypeClass() != lldb.eTypeClassStruct:
- return False
-
- if ty.GetNumberOfFields() != 2:
- return False
-
- if ty.GetFieldAtIndex(0).GetName() != "data_ptr":
- return False
-
- if ty.GetFieldAtIndex(1).GetName() != "length":
- return False
-
- type_name = extract_type_name(ty.GetName()).replace("&'static", "&").replace(" ", "")
- return type_name.startswith("&[") and type_name.endswith("]")
-
-def is_std_vec(val):
- ty = val.GetType()
- if ty.GetTypeClass() != lldb.eTypeClassStruct:
- return False
-
- if ty.GetNumberOfFields() != 3:
- return False
-
- if ty.GetFieldAtIndex(0).GetName() != "ptr":
- return False
-
- if ty.GetFieldAtIndex(1).GetName() != "len":
- return False
-
- if ty.GetFieldAtIndex(2).GetName() != "cap":
- return False
-
- return ty.GetName().startswith("collections::vec::Vec<")
-
-
def print_array_of_values(array_name, data_ptr_val, length, internal_dict):
'''Prints a contigous memory range, interpreting it as values of the
pointee-type of data_ptr_val.'''
- data_ptr_type = data_ptr_val.GetType()
- assert data_ptr_type.IsPointerType()
+ data_ptr_type = data_ptr_val.type
+ assert data_ptr_type.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_PTR
- element_type = data_ptr_type.GetPointeeType()
+ element_type = data_ptr_type.get_wrapped_value().GetPointeeType()
element_type_size = element_type.GetByteSize()
- start_address = data_ptr_val.GetValueAsUnsigned()
+ start_address = data_ptr_val.as_integer()
+ raw_value = data_ptr_val.get_wrapped_value()
def render_element(i):
address = start_address + i * element_type_size
- element_val = data_ptr_val.CreateValueFromAddress(array_name + ("[%s]" % i),
- address,
- element_type)
+ element_val = raw_value.CreateValueFromAddress(array_name + ("[%s]" % i),
+ address,
+ element_type)
return print_val(element_val, internal_dict)
return ', '.join([render_element(i) for i in range(length)])
+
+
+def read_utf8_string(ptr_val, byte_count):
+ error = lldb.SBError()
+ process = ptr_val.get_wrapped_value().GetProcess()
+ data = process.ReadMemory(ptr_val.as_integer(), byte_count, error)
+ if error.Success():
+ return '"%s"' % data.decode(encoding='UTF-8')
+ else:
+ return '<error: %s>' % error.GetCString()
--- /dev/null
+# Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+import sys
+
+input_file = sys.argv[1]
+output_file = sys.argv[2]
+name = sys.argv[3]
+
+with open(input_file, 'r') as f:
+ with open(output_file, 'w') as g:
+ print >> g, 'LIBRARY ' + name
+ print >> g, 'EXPORTS'
+ for x in f:
+ x = str(x)
+ if not x.startswith(' pub fn LLVM'): continue
+ name = x[11:x.find('(')]
+ print >> g, ' ' + name
assert('stdlib=libc++' not in out)
f.write("#[link(name = \"stdc++\", kind = \"static\")]\n")
else:
+ # Note that we use `cfg_attr` here because on MSVC the C++ standard library
+ # is not c++ or stdc++, but rather the linker takes care of linking the
+ # right standard library.
if 'stdlib=libc++' in out:
- f.write("#[link(name = \"c++\")]\n")
+ f.write("#[cfg_attr(not(target_env = \"msvc\"), link(name = \"c++\"))]\n")
else:
- f.write("#[link(name = \"stdc++\")]\n")
+ f.write("#[cfg_attr(not(target_env = \"msvc\"), link(name = \"stdc++\"))]\n")
# Attach everything to an extern block
f.write("extern {}\n")
check_linelength = True
if len(sys.argv) < 2:
- print "usage: tidy.py <src-dir>"
+ print("usage: tidy.py <src-dir>")
sys.exit(1)
src_dir = sys.argv[1]
print
for ext in sorted(file_counts, key=file_counts.get, reverse=True):
- print "* linted {} {} files".format(file_counts[ext], ext)
-print "* linted {} other files".format(count_other_linted_files)
-print "* total lines of code: {}".format(count_lines)
-print "* total non-blank lines of code: {}".format(count_non_blank_lines)
-print
+ print("* linted {} {} files".format(file_counts[ext], ext))
+print("* linted {} other files".format(count_other_linted_files))
+print("* total lines of code: {}".format(count_lines))
+print("* total non-blank lines of code: {}".format(count_non_blank_lines))
+print()
sys.exit(err)
def load_unicode_data(f):
fetch(f)
gencats = {}
- upperlower = {}
- lowerupper = {}
+ to_lower = {}
+ to_upper = {}
+ to_title = {}
combines = {}
canon_decomp = {}
compat_decomp = {}
# generate char to char direct common and simple conversions
# uppercase to lowercase
- if gencat == "Lu" and lowcase != "" and code_org != lowcase:
- upperlower[code] = int(lowcase, 16)
+ if lowcase != "" and code_org != lowcase:
+ to_lower[code] = (int(lowcase, 16), 0, 0)
# lowercase to uppercase
- if gencat == "Ll" and upcase != "" and code_org != upcase:
- lowerupper[code] = int(upcase, 16)
+ if upcase != "" and code_org != upcase:
+ to_upper[code] = (int(upcase, 16), 0, 0)
+
+ # title case
+ if titlecase.strip() != "" and code_org != titlecase:
+ to_title[code] = (int(titlecase, 16), 0, 0)
# store decomposition, if given
if decomp != "":
gencats = group_cats(gencats)
combines = to_combines(group_cats(combines))
- return (canon_decomp, compat_decomp, gencats, combines, lowerupper, upperlower)
+ return (canon_decomp, compat_decomp, gencats, combines, to_upper, to_lower, to_title)
+
+def load_special_casing(f, to_upper, to_lower, to_title):
+ fetch(f)
+ for line in fileinput.input(f):
+ data = line.split('#')[0].split(';')
+ if len(data) == 5:
+ code, lower, title, upper, _comment = data
+ elif len(data) == 6:
+ code, lower, title, upper, condition, _comment = data
+ if condition.strip(): # Only keep unconditional mappins
+ continue
+ else:
+ continue
+ code = code.strip()
+ lower = lower.strip()
+ title = title.strip()
+ upper = upper.strip()
+ key = int(code, 16)
+ for (map_, values) in [(to_lower, lower), (to_upper, upper), (to_title, title)]:
+ if values != code:
+ values = [int(i, 16) for i in values.split()]
+ for _ in range(len(values), 3):
+ values.append(0)
+ assert len(values) == 3
+ map_[key] = values
def group_cats(cats):
cats_out = {}
return widths
def escape_char(c):
- return "'\\u{%x}'" % c
+ return "'\\u{%x}'" % c if c != 0 else "'\\0'"
def emit_bsearch_range_table(f):
f.write("""
f.write(" }\n\n")
f.write("}\n\n")
-def emit_conversions_module(f, lowerupper, upperlower):
+def emit_conversions_module(f, to_upper, to_lower, to_title):
f.write("pub mod conversions {")
f.write("""
use core::cmp::Ordering::{Equal, Less, Greater};
use core::option::Option::{Some, None};
use core::result::Result::{Ok, Err};
- pub fn to_lower(c: char) -> char {
- match bsearch_case_table(c, LuLl_table) {
- None => c,
- Some(index) => LuLl_table[index].1
+ pub fn to_lower(c: char) -> [char; 3] {
+ match bsearch_case_table(c, to_lowercase_table) {
+ None => [c, '\\0', '\\0'],
+ Some(index) => to_lowercase_table[index].1
+ }
+ }
+
+ pub fn to_upper(c: char) -> [char; 3] {
+ match bsearch_case_table(c, to_uppercase_table) {
+ None => [c, '\\0', '\\0'],
+ Some(index) => to_uppercase_table[index].1
}
}
- pub fn to_upper(c: char) -> char {
- match bsearch_case_table(c, LlLu_table) {
- None => c,
- Some(index) => LlLu_table[index].1
+ pub fn to_title(c: char) -> [char; 3] {
+ match bsearch_case_table(c, to_titlecase_table) {
+ None => [c, '\\0', '\\0'],
+ Some(index) => to_titlecase_table[index].1
}
}
- fn bsearch_case_table(c: char, table: &'static [(char, char)]) -> Option<usize> {
+ fn bsearch_case_table(c: char, table: &'static [(char, [char; 3])]) -> Option<usize> {
match table.binary_search_by(|&(key, _)| {
if c == key { Equal }
else if key < c { Less }
}
""")
- emit_table(f, "LuLl_table",
- sorted(upperlower.iteritems(), key=operator.itemgetter(0)), is_pub=False)
- emit_table(f, "LlLu_table",
- sorted(lowerupper.iteritems(), key=operator.itemgetter(0)), is_pub=False)
+ t_type = "&'static [(char, [char; 3])]"
+ pfun = lambda x: "(%s,[%s,%s,%s])" % (
+ escape_char(x[0]), escape_char(x[1][0]), escape_char(x[1][1]), escape_char(x[1][2]))
+ emit_table(f, "to_lowercase_table",
+ sorted(to_lower.iteritems(), key=operator.itemgetter(0)),
+ is_pub=False, t_type = t_type, pfun=pfun)
+ emit_table(f, "to_uppercase_table",
+ sorted(to_upper.iteritems(), key=operator.itemgetter(0)),
+ is_pub=False, t_type = t_type, pfun=pfun)
+ emit_table(f, "to_titlecase_table",
+ sorted(to_title.iteritems(), key=operator.itemgetter(0)),
+ is_pub=False, t_type = t_type, pfun=pfun)
f.write("}\n\n")
def emit_grapheme_module(f, grapheme_table, grapheme_cats):
pub const UNICODE_VERSION: (u64, u64, u64) = (%s, %s, %s);
""" % unicode_version)
(canon_decomp, compat_decomp, gencats, combines,
- lowerupper, upperlower) = load_unicode_data("UnicodeData.txt")
- want_derived = ["XID_Start", "XID_Continue", "Alphabetic", "Lowercase", "Uppercase"]
+ to_upper, to_lower, to_title) = load_unicode_data("UnicodeData.txt")
+ load_special_casing("SpecialCasing.txt", to_upper, to_lower, to_title)
+ want_derived = ["XID_Start", "XID_Continue", "Alphabetic", "Lowercase", "Uppercase",
+ "Cased", "Case_Ignorable"]
derived = load_properties("DerivedCoreProperties.txt", want_derived)
scripts = load_properties("Scripts.txt", [])
props = load_properties("PropList.txt",
# normalizations and conversions module
emit_norm_module(rf, canon_decomp, compat_decomp, combines, norm_props)
- emit_conversions_module(rf, lowerupper, upperlower)
+ emit_conversions_module(rf, to_upper, to_lower, to_title)
### character width module
width_table = []
-0.12.0-9659-g35ceea3997c79a3b7562e89b462ab76af5b86b22
+0.12.0-10860-g082e4763615bdbe7b4dd3dfd6fc2210b7773edf5
use core::atomic::Ordering::{Relaxed, Release, Acquire, SeqCst};
use core::fmt;
use core::cmp::Ordering;
-use core::mem::{min_align_of, size_of};
+use core::mem::{align_of_val, size_of_val};
+use core::intrinsics::drop_in_place;
use core::mem;
use core::nonzero::NonZero;
-use core::ops::Deref;
-use core::ptr;
+use core::ops::{Deref, CoerceUnsized};
+use core::marker::Unsize;
use core::hash::{Hash, Hasher};
use heap::deallocate;
/// increase the reference counter.
///
/// ```
-/// # #![feature(alloc, core)]
/// use std::sync::Arc;
/// use std::thread;
///
/// ```
#[unsafe_no_drop_flag]
#[stable(feature = "rust1", since = "1.0.0")]
-pub struct Arc<T> {
+pub struct Arc<T: ?Sized> {
// FIXME #12808: strange name to try to avoid interfering with
// field accesses of the contained type via Deref
_ptr: NonZero<*mut ArcInner<T>>,
}
-unsafe impl<T: Sync + Send> Send for Arc<T> { }
-unsafe impl<T: Sync + Send> Sync for Arc<T> { }
+unsafe impl<T: ?Sized + Sync + Send> Send for Arc<T> { }
+unsafe impl<T: ?Sized + Sync + Send> Sync for Arc<T> { }
+impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Arc<U>> for Arc<T> {}
/// A weak pointer to an `Arc`.
///
/// Weak pointers will not keep the data inside of the `Arc` alive, and can be
/// used to break cycles between `Arc` pointers.
#[unsafe_no_drop_flag]
-#[unstable(feature = "alloc",
+#[unstable(feature = "arc_weak",
reason = "Weak pointers may not belong in this module.")]
-pub struct Weak<T> {
+pub struct Weak<T: ?Sized> {
// FIXME #12808: strange name to try to avoid interfering with
// field accesses of the contained type via Deref
_ptr: NonZero<*mut ArcInner<T>>,
}
-unsafe impl<T: Sync + Send> Send for Weak<T> { }
-unsafe impl<T: Sync + Send> Sync for Weak<T> { }
+unsafe impl<T: ?Sized + Sync + Send> Send for Weak<T> { }
+unsafe impl<T: ?Sized + Sync + Send> Sync for Weak<T> { }
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: fmt::Debug> fmt::Debug for Weak<T> {
+impl<T: ?Sized + fmt::Debug> fmt::Debug for Weak<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "(Weak)")
}
}
-struct ArcInner<T> {
+struct ArcInner<T: ?Sized> {
strong: atomic::AtomicUsize,
weak: atomic::AtomicUsize,
data: T,
}
-unsafe impl<T: Sync + Send> Send for ArcInner<T> {}
-unsafe impl<T: Sync + Send> Sync for ArcInner<T> {}
+unsafe impl<T: ?Sized + Sync + Send> Send for ArcInner<T> {}
+unsafe impl<T: ?Sized + Sync + Send> Sync for ArcInner<T> {}
impl<T> Arc<T> {
/// Constructs a new `Arc<T>`.
};
Arc { _ptr: unsafe { NonZero::new(mem::transmute(x)) } }
}
+}
+impl<T: ?Sized> Arc<T> {
/// Downgrades the `Arc<T>` to a `Weak<T>` reference.
///
/// # Examples
///
/// ```
- /// # #![feature(alloc)]
+ /// # #![feature(arc_weak)]
/// use std::sync::Arc;
///
/// let five = Arc::new(5);
///
/// let weak_five = five.downgrade();
/// ```
- #[unstable(feature = "alloc",
+ #[unstable(feature = "arc_weak",
reason = "Weak pointers may not belong in this module.")]
pub fn downgrade(&self) -> Weak<T> {
// See the clone() impl for why this is relaxed
self.inner().weak.fetch_add(1, Relaxed);
Weak { _ptr: self._ptr }
}
-}
-impl<T> Arc<T> {
+ /// Get the number of weak references to this value.
+ #[inline]
+ #[unstable(feature = "arc_counts")]
+ pub fn weak_count(this: &Arc<T>) -> usize {
+ this.inner().weak.load(SeqCst) - 1
+ }
+
+ /// Get the number of strong references to this value.
+ #[inline]
+ #[unstable(feature = "arc_counts")]
+ pub fn strong_count(this: &Arc<T>) -> usize {
+ this.inner().strong.load(SeqCst)
+ }
+
#[inline]
fn inner(&self) -> &ArcInner<T> {
// This unsafety is ok because while this arc is alive we're guaranteed
// Destroy the data at this time, even though we may not free the box
// allocation itself (there may still be weak pointers lying around).
- drop(ptr::read(&self.inner().data));
+ drop_in_place(&mut (*ptr).data);
if self.inner().weak.fetch_sub(1, Release) == 1 {
atomic::fence(Acquire);
- deallocate(ptr as *mut u8, size_of::<ArcInner<T>>(), min_align_of::<ArcInner<T>>())
+ deallocate(ptr as *mut u8, size_of_val(&*ptr), align_of_val(&*ptr))
}
}
}
/// Get the number of weak references to this value.
#[inline]
-#[unstable(feature = "alloc")]
-pub fn weak_count<T>(this: &Arc<T>) -> usize { this.inner().weak.load(SeqCst) - 1 }
+#[unstable(feature = "arc_counts")]
+#[deprecated(since = "1.2.0", reason = "renamed to Arc::weak_count")]
+pub fn weak_count<T: ?Sized>(this: &Arc<T>) -> usize { Arc::weak_count(this) }
/// Get the number of strong references to this value.
#[inline]
-#[unstable(feature = "alloc")]
-pub fn strong_count<T>(this: &Arc<T>) -> usize { this.inner().strong.load(SeqCst) }
+#[unstable(feature = "arc_counts")]
+#[deprecated(since = "1.2.0", reason = "renamed to Arc::strong_count")]
+pub fn strong_count<T: ?Sized>(this: &Arc<T>) -> usize { Arc::strong_count(this) }
/// Returns a mutable reference to the contained value if the `Arc<T>` is unique.
///
/// Returns `None` if the `Arc<T>` is not unique.
///
+/// This function is marked **unsafe** because it is racy if weak pointers
+/// are active.
+///
/// # Examples
///
/// ```
-/// # #![feature(alloc)]
+/// # #![feature(arc_unique, alloc)]
/// extern crate alloc;
/// # fn main() {
/// use alloc::arc::{Arc, get_mut};
///
+/// # unsafe {
/// let mut x = Arc::new(3);
/// *get_mut(&mut x).unwrap() = 4;
/// assert_eq!(*x, 4);
/// let _y = x.clone();
/// assert!(get_mut(&mut x).is_none());
/// # }
+/// # }
/// ```
#[inline]
-#[unstable(feature = "alloc")]
-pub fn get_mut<T>(this: &mut Arc<T>) -> Option<&mut T> {
- if strong_count(this) == 1 && weak_count(this) == 0 {
+#[unstable(feature = "arc_unique")]
+#[deprecated(since = "1.2.0",
+ reason = "this function is unsafe with weak pointers")]
+pub unsafe fn get_mut<T: ?Sized>(this: &mut Arc<T>) -> Option<&mut T> {
+ // FIXME(#24880) potential race with upgraded weak pointers here
+ if Arc::strong_count(this) == 1 && Arc::weak_count(this) == 0 {
// This unsafety is ok because we're guaranteed that the pointer
// returned is the *only* pointer that will ever be returned to T. Our
// reference count is guaranteed to be 1 at this point, and we required
// the Arc itself to be `mut`, so we're returning the only possible
// reference to the inner data.
- let inner = unsafe { &mut **this._ptr };
+ let inner = &mut **this._ptr;
Some(&mut inner.data)
} else {
None
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Clone for Arc<T> {
+impl<T: ?Sized> Clone for Arc<T> {
/// Makes a clone of the `Arc<T>`.
///
/// This increases the strong reference count.
/// # Examples
///
/// ```
- /// # #![feature(alloc)]
/// use std::sync::Arc;
///
/// let five = Arc::new(5);
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Deref for Arc<T> {
+impl<T: ?Sized> Deref for Arc<T> {
type Target = T;
#[inline]
/// This is also referred to as a copy-on-write operation because the inner
/// data is cloned if the reference count is greater than one.
///
+ /// This method is marked **unsafe** because it is racy if weak pointers
+ /// are active.
+ ///
/// # Examples
///
/// ```
- /// # #![feature(alloc)]
+ /// # #![feature(arc_unique)]
/// use std::sync::Arc;
///
+ /// # unsafe {
/// let mut five = Arc::new(5);
///
/// let mut_five = five.make_unique();
+ /// # }
/// ```
#[inline]
- #[unstable(feature = "alloc")]
- pub fn make_unique(&mut self) -> &mut T {
+ #[unstable(feature = "arc_unique")]
+ #[deprecated(since = "1.2.0",
+ reason = "this function is unsafe with weak pointers")]
+ pub unsafe fn make_unique(&mut self) -> &mut T {
+ // FIXME(#24880) potential race with upgraded weak pointers here
+ //
// Note that we hold a strong reference, which also counts as a weak
// reference, so we only clone if there is an additional reference of
// either kind.
}
// As with `get_mut()`, the unsafety is ok because our reference was
// either unique to begin with, or became one upon cloning the contents.
- let inner = unsafe { &mut **self._ptr };
+ let inner = &mut **self._ptr;
&mut inner.data
}
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Drop for Arc<T> {
+impl<T: ?Sized> Drop for Arc<T> {
/// Drops the `Arc<T>`.
///
/// This will decrement the strong reference count. If the strong reference
/// # Examples
///
/// ```
- /// # #![feature(alloc)]
/// use std::sync::Arc;
///
/// {
// it's run more than once)
let ptr = *self._ptr;
// if ptr.is_null() { return }
- if ptr.is_null() || ptr as usize == mem::POST_DROP_USIZE { return }
+ if ptr as *mut u8 as usize == 0 || ptr as *mut u8 as usize == mem::POST_DROP_USIZE {
+ return
+ }
// Because `fetch_sub` is already atomic, we do not need to synchronize
// with other threads unless we are going to delete the object. This
}
}
-#[unstable(feature = "alloc",
+#[unstable(feature = "arc_weak",
reason = "Weak pointers may not belong in this module.")]
-impl<T> Weak<T> {
+impl<T: ?Sized> Weak<T> {
/// Upgrades a weak reference to a strong reference.
///
/// Upgrades the `Weak<T>` reference to an `Arc<T>`, if possible.
/// # Examples
///
/// ```
- /// # #![feature(alloc)]
+ /// # #![feature(arc_weak)]
/// use std::sync::Arc;
///
/// let five = Arc::new(5);
}
}
-#[unstable(feature = "alloc",
+#[unstable(feature = "arc_weak",
reason = "Weak pointers may not belong in this module.")]
-impl<T> Clone for Weak<T> {
+impl<T: ?Sized> Clone for Weak<T> {
/// Makes a clone of the `Weak<T>`.
///
/// This increases the weak reference count.
/// # Examples
///
/// ```
- /// # #![feature(alloc)]
+ /// # #![feature(arc_weak)]
/// use std::sync::Arc;
///
/// let weak_five = Arc::new(5).downgrade();
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Drop for Weak<T> {
+impl<T: ?Sized> Drop for Weak<T> {
/// Drops the `Weak<T>`.
///
/// This will decrement the weak reference count.
/// # Examples
///
/// ```
- /// # #![feature(alloc)]
+ /// # #![feature(arc_weak)]
/// use std::sync::Arc;
///
/// {
let ptr = *self._ptr;
// see comments above for why this check is here
- if ptr.is_null() || ptr as usize == mem::POST_DROP_USIZE { return }
+ if ptr as *mut u8 as usize == 0 || ptr as *mut u8 as usize == mem::POST_DROP_USIZE {
+ return
+ }
// If we find out that we were the last weak pointer, then its time to
// deallocate the data entirely. See the discussion in Arc::drop() about
// the memory orderings
if self.inner().weak.fetch_sub(1, Release) == 1 {
atomic::fence(Acquire);
- unsafe { deallocate(ptr as *mut u8, size_of::<ArcInner<T>>(),
- min_align_of::<ArcInner<T>>()) }
+ unsafe { deallocate(ptr as *mut u8,
+ size_of_val(&*ptr),
+ align_of_val(&*ptr)) }
}
}
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: PartialEq> PartialEq for Arc<T> {
+impl<T: ?Sized + PartialEq> PartialEq for Arc<T> {
/// Equality for two `Arc<T>`s.
///
/// Two `Arc<T>`s are equal if their inner value are equal.
fn ne(&self, other: &Arc<T>) -> bool { *(*self) != *(*other) }
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: PartialOrd> PartialOrd for Arc<T> {
+impl<T: ?Sized + PartialOrd> PartialOrd for Arc<T> {
/// Partial comparison for two `Arc<T>`s.
///
/// The two are compared by calling `partial_cmp()` on their inner values.
fn ge(&self, other: &Arc<T>) -> bool { *(*self) >= *(*other) }
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Ord> Ord for Arc<T> {
+impl<T: ?Sized + Ord> Ord for Arc<T> {
fn cmp(&self, other: &Arc<T>) -> Ordering { (**self).cmp(&**other) }
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Eq> Eq for Arc<T> {}
+impl<T: ?Sized + Eq> Eq for Arc<T> {}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: fmt::Display> fmt::Display for Arc<T> {
+impl<T: ?Sized + fmt::Display> fmt::Display for Arc<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&**self, f)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: fmt::Debug> fmt::Debug for Arc<T> {
+impl<T: ?Sized + fmt::Debug> fmt::Debug for Arc<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Hash> Hash for Arc<T> {
+impl<T: ?Sized + Hash> Hash for Arc<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
(**self).hash(state)
}
#[test]
fn test_arc_get_mut() {
- let mut x = Arc::new(3);
- *get_mut(&mut x).unwrap() = 4;
- assert_eq!(*x, 4);
- let y = x.clone();
- assert!(get_mut(&mut x).is_none());
- drop(y);
- assert!(get_mut(&mut x).is_some());
- let _w = x.downgrade();
- assert!(get_mut(&mut x).is_none());
+ unsafe {
+ let mut x = Arc::new(3);
+ *get_mut(&mut x).unwrap() = 4;
+ assert_eq!(*x, 4);
+ let y = x.clone();
+ assert!(get_mut(&mut x).is_none());
+ drop(y);
+ assert!(get_mut(&mut x).is_some());
+ let _w = x.downgrade();
+ assert!(get_mut(&mut x).is_none());
+ }
}
#[test]
fn test_cowarc_clone_make_unique() {
- let mut cow0 = Arc::new(75);
- let mut cow1 = cow0.clone();
- let mut cow2 = cow1.clone();
-
- assert!(75 == *cow0.make_unique());
- assert!(75 == *cow1.make_unique());
- assert!(75 == *cow2.make_unique());
-
- *cow0.make_unique() += 1;
- *cow1.make_unique() += 2;
- *cow2.make_unique() += 3;
-
- assert!(76 == *cow0);
- assert!(77 == *cow1);
- assert!(78 == *cow2);
-
- // none should point to the same backing memory
- assert!(*cow0 != *cow1);
- assert!(*cow0 != *cow2);
- assert!(*cow1 != *cow2);
+ unsafe {
+ let mut cow0 = Arc::new(75);
+ let mut cow1 = cow0.clone();
+ let mut cow2 = cow1.clone();
+
+ assert!(75 == *cow0.make_unique());
+ assert!(75 == *cow1.make_unique());
+ assert!(75 == *cow2.make_unique());
+
+ *cow0.make_unique() += 1;
+ *cow1.make_unique() += 2;
+ *cow2.make_unique() += 3;
+
+ assert!(76 == *cow0);
+ assert!(77 == *cow1);
+ assert!(78 == *cow2);
+
+ // none should point to the same backing memory
+ assert!(*cow0 != *cow1);
+ assert!(*cow0 != *cow2);
+ assert!(*cow1 != *cow2);
+ }
}
#[test]
assert!(75 == *cow1);
assert!(75 == *cow2);
- *cow0.make_unique() += 1;
+ unsafe {
+ *cow0.make_unique() += 1;
+ }
assert!(76 == *cow0);
assert!(75 == *cow1);
assert!(75 == *cow0);
assert!(75 == *cow1_weak.upgrade().unwrap());
- *cow0.make_unique() += 1;
+ unsafe {
+ *cow0.make_unique() += 1;
+ }
assert!(76 == *cow0);
assert!(cow1_weak.upgrade().is_none());
// Make sure deriving works with Arc<T>
#[derive(Eq, Ord, PartialEq, PartialOrd, Clone, Debug, Default)]
struct Foo { inner: Arc<i32> }
+
+ #[test]
+ fn test_unsized() {
+ let x: Arc<[i32]> = Arc::new([1, 2, 3]);
+ assert_eq!(format!("{:?}", x), "[1, 2, 3]");
+ let y = x.clone().downgrade();
+ drop(x);
+ assert!(y.upgrade().is_none());
+ }
}
//! A pointer type for heap allocation.
//!
-//! `Box<T>`, casually referred to as a 'box', provides the simplest form of heap allocation in
-//! Rust. Boxes provide ownership for this allocation, and drop their contents when they go out of
-//! scope.
+//! `Box<T>`, casually referred to as a 'box', provides the simplest form of
+//! heap allocation in Rust. Boxes provide ownership for this allocation, and
+//! drop their contents when they go out of scope.
//!
//! # Examples
//!
//!
//! This will print `Cons(1, Cons(2, Nil))`.
//!
-//! Recursive structures must be boxed, because if the definition of `Cons` looked like this:
+//! Recursive structures must be boxed, because if the definition of `Cons`
+//! looked like this:
//!
//! ```rust,ignore
//! Cons(T, List<T>),
//! ```
//!
-//! It wouldn't work. This is because the size of a `List` depends on how many elements are in the
-//! list, and so we don't know how much memory to allocate for a `Cons`. By introducing a `Box`,
-//! which has a defined size, we know how big `Cons` needs to be.
+//! It wouldn't work. This is because the size of a `List` depends on how many
+//! elements are in the list, and so we don't know how much memory to allocate
+//! for a `Cons`. By introducing a `Box`, which has a defined size, we know how
+//! big `Cons` needs to be.
#![stable(feature = "rust1", since = "1.0.0")]
use core::cmp::Ordering;
use core::fmt;
use core::hash::{self, Hash};
+use core::marker::Unsize;
use core::mem;
-use core::ops::{Deref, DerefMut};
+use core::ops::{CoerceUnsized, Deref, DerefMut};
use core::ptr::{Unique};
use core::raw::{TraitObject};
-#[cfg(not(stage0))]
-use core::marker::Unsize;
-#[cfg(not(stage0))]
-use core::ops::CoerceUnsized;
-
/// A value that represents the heap. This is the default place that the `box`
/// keyword allocates into when no place is supplied.
///
/// The following two examples are equivalent:
///
/// ```
-/// # #![feature(alloc)]
+/// # #![feature(box_heap)]
/// #![feature(box_syntax)]
/// use std::boxed::HEAP;
///
/// }
/// ```
#[lang = "exchange_heap"]
-#[unstable(feature = "alloc",
+#[unstable(feature = "box_heap",
reason = "may be renamed; uncertain about custom allocator design")]
-pub static HEAP: () = ();
+pub const HEAP: () = ();
/// A pointer type for heap allocation.
///
/// Function is unsafe, because improper use of this function may
/// lead to memory problems like double-free, for example if the
/// function is called twice on the same raw pointer.
- #[unstable(feature = "alloc",
+ #[unstable(feature = "box_raw",
reason = "may be renamed or moved out of Box scope")]
#[inline]
+ // NB: may want to be called from_ptr, see comments on CStr::from_ptr
pub unsafe fn from_raw(raw: *mut T) -> Self {
mem::transmute(raw)
}
+
+ /// Consumes the `Box`, returning the wrapped raw pointer.
+ ///
+ /// After call to this function, caller is responsible for the memory
+ /// previously managed by `Box`, in particular caller should properly
+ /// destroy `T` and release memory. The proper way to do it is to
+ /// convert pointer back to `Box` with `Box::from_raw` function, because
+ /// `Box` does not specify, how memory is allocated.
+ ///
+ /// # Examples
+ /// ```
+ /// # #![feature(box_raw)]
+ /// use std::boxed;
+ ///
+ /// let seventeen = Box::new(17u32);
+ /// let raw = boxed::into_raw(seventeen);
+ /// let boxed_again = unsafe { Box::from_raw(raw) };
+ /// ```
+ #[unstable(feature = "box_raw", reason = "may be renamed")]
+ #[inline]
+ // NB: may want to be called into_ptr, see comments on CStr::from_ptr
+ pub fn into_raw(b: Box<T>) -> *mut T {
+ unsafe { mem::transmute(b) }
+ }
}
/// Consumes the `Box`, returning the wrapped raw pointer.
/// convert pointer back to `Box` with `Box::from_raw` function, because
/// `Box` does not specify, how memory is allocated.
///
-/// Function is unsafe, because result of this function is no longer
-/// automatically managed that may lead to memory or other resource
-/// leak.
-///
/// # Examples
/// ```
-/// # #![feature(alloc)]
+/// # #![feature(box_raw)]
/// use std::boxed;
///
/// let seventeen = Box::new(17u32);
-/// let raw = unsafe { boxed::into_raw(seventeen) };
+/// let raw = boxed::into_raw(seventeen);
/// let boxed_again = unsafe { Box::from_raw(raw) };
/// ```
-#[unstable(feature = "alloc",
- reason = "may be renamed")]
+#[unstable(feature = "box_raw", reason = "may be renamed")]
+#[deprecated(since = "1.2.0", reason = "renamed to Box::into_raw")]
#[inline]
-pub unsafe fn into_raw<T : ?Sized>(b: Box<T>) -> *mut T {
- mem::transmute(b)
+pub fn into_raw<T : ?Sized>(b: Box<T>) -> *mut T {
+ Box::into_raw(b)
}
#[stable(feature = "rust1", since = "1.0.0")]
/// # Examples
///
/// ```
- /// # #![feature(alloc, core)]
+ /// # #![feature(box_raw)]
/// let x = Box::new(5);
/// let mut y = Box::new(10);
///
if self.is::<T>() {
unsafe {
// Get the raw representation of the trait object
- let raw = into_raw(self);
+ let raw = Box::into_raw(self);
let to: TraitObject =
mem::transmute::<*mut Any, TraitObject>(raw);
/// -> i32>`.
///
/// ```
-/// #![feature(core)]
+/// #![feature(fnbox)]
///
/// use std::boxed::FnBox;
/// use std::collections::HashMap;
/// }
/// ```
#[rustc_paren_sugar]
-#[unstable(feature = "core", reason = "Newly introduced")]
+#[unstable(feature = "fnbox", reason = "Newly introduced")]
pub trait FnBox<A> {
type Output;
}
}
-#[cfg(not(stage0))]
impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<Box<U>> for Box<T> {}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![unstable(feature = "heap_api",
+ reason = "the precise API and guarantees it provides may be tweaked \
+ slightly, especially to possibly take into account the \
+ types being stored to make room for a future \
+ tracing garbage collector")]
+
use core::{isize, usize};
#[inline(always)]
///
/// These statistics may be inconsistent if other threads use the allocator
/// during the call.
-#[unstable(feature = "alloc")]
pub fn stats_print() {
imp::stats_print();
}
not(jemalloc),
windows))]
mod imp {
- use libc::{c_void, size_t};
- use libc;
+ use core::mem::size_of;
+ use libc::{BOOL, DWORD, HANDLE, LPVOID, SIZE_T, INVALID_HANDLE_VALUE};
+ use libc::{WriteFile};
use super::MIN_ALIGN;
- extern {
- fn _aligned_malloc(size: size_t, align: size_t) -> *mut c_void;
- fn _aligned_realloc(block: *mut c_void, size: size_t,
- align: size_t) -> *mut c_void;
- fn _aligned_free(ptr: *mut c_void);
+ extern "system" {
+ fn GetProcessHeap() -> HANDLE;
+ fn GetStdHandle(nStdHandle: DWORD) -> HANDLE;
+ fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID;
+ fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID;
+ fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL;
+ fn HeapSummary(hHeap: HANDLE, dwFlags: DWORD, lpSummary: LPHEAP_SUMMARY) -> BOOL;
+ }
+
+ #[repr(C)] #[allow(non_snake_case)]
+ struct HEAP_SUMMARY {
+ cb: DWORD,
+ cbAllocated: SIZE_T,
+ cbCommitted: SIZE_T,
+ cbReserved: SIZE_T,
+ cbMaxReserve: SIZE_T,
+ }
+ #[allow(non_camel_case_types)]
+ type LPHEAP_SUMMARY = *mut HEAP_SUMMARY;
+
+ #[repr(C)]
+ struct Header(*mut u8);
+
+ const HEAP_REALLOC_IN_PLACE_ONLY: DWORD = 0x00000010;
+ const STD_OUTPUT_HANDLE: DWORD = -11i32 as u32;
+
+ #[inline]
+ unsafe fn get_header<'a>(ptr: *mut u8) -> &'a mut Header {
+ &mut *(ptr as *mut Header).offset(-1)
+ }
+
+ #[inline]
+ unsafe fn align_ptr(ptr: *mut u8, align: usize) -> *mut u8 {
+ let aligned = ptr.offset((align - (ptr as usize & (align - 1))) as isize);
+ *get_header(aligned) = Header(ptr);
+ aligned
}
#[inline]
pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
if align <= MIN_ALIGN {
- libc::malloc(size as size_t) as *mut u8
+ HeapAlloc(GetProcessHeap(), 0, size as SIZE_T) as *mut u8
} else {
- _aligned_malloc(size as size_t, align as size_t) as *mut u8
+ let ptr = HeapAlloc(GetProcessHeap(), 0, (size + align) as SIZE_T) as *mut u8;
+ if ptr.is_null() { return ptr }
+ align_ptr(ptr, align)
}
}
#[inline]
pub unsafe fn reallocate(ptr: *mut u8, _old_size: usize, size: usize, align: usize) -> *mut u8 {
if align <= MIN_ALIGN {
- libc::realloc(ptr as *mut c_void, size as size_t) as *mut u8
+ HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, size as SIZE_T) as *mut u8
} else {
- _aligned_realloc(ptr as *mut c_void, size as size_t, align as size_t) as *mut u8
+ let header = get_header(ptr);
+ let new = HeapReAlloc(GetProcessHeap(), 0, header.0 as LPVOID,
+ (size + align) as SIZE_T) as *mut u8;
+ if new.is_null() { return new }
+ align_ptr(new, align)
}
}
#[inline]
- pub unsafe fn reallocate_inplace(_ptr: *mut u8, old_size: usize, _size: usize,
- _align: usize) -> usize {
- old_size
+ pub unsafe fn reallocate_inplace(ptr: *mut u8, old_size: usize, size: usize,
+ align: usize) -> usize {
+ if align <= MIN_ALIGN {
+ let new = HeapReAlloc(GetProcessHeap(), HEAP_REALLOC_IN_PLACE_ONLY, ptr as LPVOID,
+ size as SIZE_T) as *mut u8;
+ if new.is_null() { old_size } else { size }
+ } else {
+ old_size
+ }
}
#[inline]
pub unsafe fn deallocate(ptr: *mut u8, _old_size: usize, align: usize) {
if align <= MIN_ALIGN {
- libc::free(ptr as *mut libc::c_void)
+ let err = HeapFree(GetProcessHeap(), 0, ptr as LPVOID);
+ debug_assert!(err != 0);
} else {
- _aligned_free(ptr as *mut c_void)
+ let header = get_header(ptr);
+ let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID);
+ debug_assert!(err != 0);
}
}
size
}
- pub fn stats_print() {}
+ pub fn stats_print() {
+ use core::fmt::{Error, Result, Write};
+ use core::ptr::null_mut;
+ use core::raw::Repr;
+ use core::result::Result::{Ok, Err};
+ struct Console(HANDLE);
+ impl Write for Console {
+ fn write_str(&mut self, s: &str) -> Result {
+ let repr = s.repr();
+ let mut written = 0;
+ let err = unsafe { WriteFile(self.0, repr.data as LPVOID, repr.len as DWORD,
+ &mut written, null_mut()) };
+ if written as usize != repr.len { return Err(Error) }
+ if err == 0 { return Err(Error) }
+ Ok(())
+ }
+ }
+ let mut hs = HEAP_SUMMARY {
+ cb: size_of::<HEAP_SUMMARY>() as DWORD,
+ cbAllocated: 0,
+ cbCommitted: 0,
+ cbReserved: 0,
+ cbMaxReserve: 0,
+ };
+ let err = unsafe { HeapSummary(GetProcessHeap(), 0, &mut hs) };
+ assert!(err != 0);
+ let handle = unsafe { GetStdHandle(STD_OUTPUT_HANDLE) };
+ if handle.is_null() || handle == INVALID_HANDLE_VALUE { panic!("Failed to open stdout") }
+ let mut out = Console(handle);
+ writeln!(&mut out, "Allocated: {}", hs.cbAllocated).unwrap();
+ writeln!(&mut out, "Committed: {}", hs.cbCommitted).unwrap();
+ writeln!(&mut out, "Reserved: {}", hs.cbReserved).unwrap();
+ writeln!(&mut out, "MaxReserve: {}", hs.cbMaxReserve).unwrap();
+ }
+
+ #[test]
+ fn alignment_header_size() {
+ assert!(size_of::<Header>() <= MIN_ALIGN);
+ }
}
#[cfg(test)]
//!
//! ## Boxed values
//!
-//! The [`Box`](boxed/index.html) type is the core owned pointer type in Rust.
-//! There can only be one owner of a `Box`, and the owner can decide to mutate
-//! the contents, which live on the heap.
+//! The [`Box`](boxed/index.html) type is a smart pointer type. There can
+//! only be one owner of a `Box`, and the owner can decide to mutate the
+//! contents, which live on the heap.
//!
//! This type can be sent among threads efficiently as the size of a `Box` value
//! is the same as that of a pointer. Tree-like data structures are often built
// Do not remove on snapshot creation. Needed for bootstrap. (Issue #22364)
#![cfg_attr(stage0, feature(custom_attribute))]
#![crate_name = "alloc"]
-#![unstable(feature = "alloc")]
-#![feature(staged_api)]
-#![staged_api]
#![crate_type = "rlib"]
+#![staged_api]
+#![unstable(feature = "alloc",
+ reason = "this library is unlikely to be stabilized in its current \
+ form or name")]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
- html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/nightly/")]
-#![doc(test(no_crate_inject))]
-
-#![feature(no_std)]
+ html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
+ html_root_url = "http://doc.rust-lang.org/nightly/",
+ test(no_crate_inject))]
#![no_std]
+
#![feature(allocator)]
+#![feature(box_syntax)]
+#![feature(coerce_unsized)]
+#![feature(core)]
+#![feature(core_intrinsics)]
+#![feature(core_prelude)]
#![feature(custom_attribute)]
#![feature(fundamental)]
#![feature(lang_items)]
-#![feature(box_syntax)]
+#![feature(no_std)]
+#![feature(nonzero)]
#![feature(optin_builtin_traits)]
+#![feature(raw)]
+#![feature(staged_api)]
#![feature(unboxed_closures)]
-#![feature(unsafe_no_drop_flag, filling_drop)]
-#![feature(core)]
#![feature(unique)]
-#![cfg_attr(test, feature(test, alloc, rustc_private))]
+#![feature(unsafe_no_drop_flag, filling_drop)]
+#![feature(unsize)]
+
+#![cfg_attr(test, feature(test, alloc, rustc_private, box_raw))]
#![cfg_attr(all(not(feature = "external_funcs"), not(feature = "external_crate")),
feature(libc))]
-
#[macro_use]
extern crate core;
/// Common out-of-memory routine
#[cold]
#[inline(never)]
+#[unstable(feature = "oom", reason = "not a scrutinized interface")]
pub fn oom() -> ! {
// FIXME(#14674): This really needs to do something other than just abort
// here, but any printing done must be *guaranteed* to not
// to get linked in to libstd successfully (the linker won't
// optimize it out).
#[doc(hidden)]
+#[unstable(feature = "issue_14344_fixme")]
pub fn fixme_14344_be_sure_to_link_to_collections() {}
//! and have the `Owner` remain allocated as long as any `Gadget` points at it.
//!
//! ```rust
-//! # #![feature(alloc, collections)]
//! use std::rc::Rc;
//!
//! struct Owner {
//! fn main() {
//! // Create a reference counted Owner.
//! let gadget_owner : Rc<Owner> = Rc::new(
-//! Owner { name: String::from_str("Gadget Man") }
+//! Owner { name: String::from("Gadget Man") }
//! );
//!
//! // Create Gadgets belonging to gadget_owner. To increment the reference
//! documentation for more details on interior mutability.
//!
//! ```rust
-//! # #![feature(alloc)]
+//! # #![feature(rc_weak)]
//! use std::rc::Rc;
//! use std::rc::Weak;
//! use std::cell::RefCell;
//! // At the end of the method, gadget_owner, gadget1 and gadget2 get
//! // destroyed. There are now no strong (`Rc<T>`) references to the gadgets.
//! // Once they get destroyed, the Gadgets get destroyed. This zeroes the
-//! // reference count on Gadget Man, so he gets destroyed as well.
+//! // reference count on Gadget Man, they get destroyed as well.
//! }
//! ```
#![stable(feature = "rust1", since = "1.0.0")]
+
+use core::prelude::*;
+
#[cfg(not(test))]
-use boxed;
+use boxed::Box;
#[cfg(test)]
-use std::boxed;
+use std::boxed::Box;
+
use core::cell::Cell;
-use core::clone::Clone;
-use core::cmp::{PartialEq, PartialOrd, Eq, Ord, Ordering};
-use core::default::Default;
+use core::cmp::Ordering;
use core::fmt;
use core::hash::{Hasher, Hash};
-use core::marker::{self, Sized};
-use core::mem::{self, min_align_of, size_of, forget};
+use core::intrinsics::{assume, drop_in_place};
+use core::marker::{self, Unsize};
+use core::mem::{self, align_of, size_of, align_of_val, size_of_val, forget};
use core::nonzero::NonZero;
-use core::ops::{Deref, Drop};
-use core::option::Option;
-use core::option::Option::{Some, None};
+use core::ops::{CoerceUnsized, Deref};
use core::ptr;
-use core::result::Result;
-use core::result::Result::{Ok, Err};
-use core::intrinsics::assume;
-
-#[cfg(not(stage0))]
-use core::intrinsics::drop_in_place;
-#[cfg(not(stage0))]
-use core::marker::Unsize;
-#[cfg(not(stage0))]
-use core::mem::{min_align_of_val, size_of_val};
-#[cfg(not(stage0))]
-use core::ops::CoerceUnsized;
use heap::deallocate;
-#[cfg(stage0)]
-struct RcBox<T> {
- strong: Cell<usize>,
- weak: Cell<usize>,
- value: T,
-}
-
-#[cfg(not(stage0))]
struct RcBox<T: ?Sized> {
strong: Cell<usize>,
weak: Cell<usize>,
/// A reference-counted pointer type over an immutable value.
///
/// See the [module level documentation](./index.html) for more details.
-#[cfg(stage0)]
-#[unsafe_no_drop_flag]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct Rc<T> {
- // FIXME #12808: strange names to try to avoid interfering with field
- // accesses of the contained type via Deref
- _ptr: NonZero<*mut RcBox<T>>,
-}
-#[cfg(not(stage0))]
#[unsafe_no_drop_flag]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Rc<T: ?Sized> {
_ptr: NonZero<*mut RcBox<T>>,
}
-#[cfg(stage0)]
-impl<T> !marker::Send for Rc<T> {}
-
-#[cfg(not(stage0))]
impl<T: ?Sized> !marker::Send for Rc<T> {}
-
-#[cfg(stage0)]
-impl<T> !marker::Sync for Rc<T> {}
-
-#[cfg(not(stage0))]
impl<T: ?Sized> !marker::Sync for Rc<T> {}
-#[cfg(not(stage0))]
impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<Rc<U>> for Rc<T> {}
impl<T> Rc<T> {
// pointers, which ensures that the weak destructor never frees
// the allocation while the strong destructor is running, even
// if the weak pointer is stored inside the strong one.
- _ptr: NonZero::new(boxed::into_raw(box RcBox {
+ _ptr: NonZero::new(Box::into_raw(box RcBox {
strong: Cell::new(1),
weak: Cell::new(1),
value: value
}
}
}
+
+ /// Unwraps the contained value if the `Rc<T>` is unique.
+ ///
+ /// If the `Rc<T>` is not unique, an `Err` is returned with the same
+ /// `Rc<T>`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # #![feature(rc_unique)]
+ /// use std::rc::Rc;
+ ///
+ /// let x = Rc::new(3);
+ /// assert_eq!(Rc::try_unwrap(x), Ok(3));
+ ///
+ /// let x = Rc::new(4);
+ /// let _y = x.clone();
+ /// assert_eq!(Rc::try_unwrap(x), Err(Rc::new(4)));
+ /// ```
+ #[inline]
+ #[unstable(feature = "rc_unique")]
+ pub fn try_unwrap(rc: Rc<T>) -> Result<T, Rc<T>> {
+ if Rc::is_unique(&rc) {
+ unsafe {
+ let val = ptr::read(&*rc); // copy the contained object
+ // destruct the box and skip our Drop
+ // we can ignore the refcounts because we know we're unique
+ deallocate(*rc._ptr as *mut u8, size_of::<RcBox<T>>(),
+ align_of::<RcBox<T>>());
+ forget(rc);
+ Ok(val)
+ }
+ } else {
+ Err(rc)
+ }
+ }
}
-#[cfg(not(stage0))]
impl<T: ?Sized> Rc<T> {
/// Downgrades the `Rc<T>` to a `Weak<T>` reference.
///
/// # Examples
///
/// ```
- /// # #![feature(alloc)]
+ /// # #![feature(rc_weak)]
/// use std::rc::Rc;
///
/// let five = Rc::new(5);
///
/// let weak_five = five.downgrade();
/// ```
- #[unstable(feature = "alloc",
+ #[unstable(feature = "rc_weak",
reason = "Weak pointers may not belong in this module")]
pub fn downgrade(&self) -> Weak<T> {
self.inc_weak();
Weak { _ptr: self._ptr }
}
-}
-#[cfg(stage0)]
-impl<T> Rc<T> {
- /// Downgrades the `Rc<T>` to a `Weak<T>` reference.
+ /// Get the number of weak references to this value.
+ #[inline]
+ #[unstable(feature = "rc_counts")]
+ pub fn weak_count(this: &Rc<T>) -> usize { this.weak() - 1 }
+
+ /// Get the number of strong references to this value.
+ #[inline]
+ #[unstable(feature = "rc_counts")]
+ pub fn strong_count(this: &Rc<T>) -> usize { this.strong() }
+
+ /// Returns true if there are no other `Rc` or `Weak<T>` values that share
+ /// the same inner value.
///
/// # Examples
///
/// ```
- /// # #![feature(alloc)]
+ /// # #![feature(rc_unique)]
/// use std::rc::Rc;
///
/// let five = Rc::new(5);
///
- /// let weak_five = five.downgrade();
+ /// assert!(Rc::is_unique(&five));
/// ```
- #[unstable(feature = "alloc",
- reason = "Weak pointers may not belong in this module")]
- pub fn downgrade(&self) -> Weak<T> {
- self.inc_weak();
- Weak { _ptr: self._ptr }
+ #[inline]
+ #[unstable(feature = "rc_unique")]
+ pub fn is_unique(rc: &Rc<T>) -> bool {
+ Rc::weak_count(rc) == 0 && Rc::strong_count(rc) == 1
+ }
+
+ /// Returns a mutable reference to the contained value if the `Rc<T>` is
+ /// unique.
+ ///
+ /// Returns `None` if the `Rc<T>` is not unique.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # #![feature(rc_unique)]
+ /// use std::rc::Rc;
+ ///
+ /// let mut x = Rc::new(3);
+ /// *Rc::get_mut(&mut x).unwrap() = 4;
+ /// assert_eq!(*x, 4);
+ ///
+ /// let _y = x.clone();
+ /// assert!(Rc::get_mut(&mut x).is_none());
+ /// ```
+ #[inline]
+ #[unstable(feature = "rc_unique")]
+ pub fn get_mut(rc: &mut Rc<T>) -> Option<&mut T> {
+ if Rc::is_unique(rc) {
+ let inner = unsafe { &mut **rc._ptr };
+ Some(&mut inner.value)
+ } else {
+ None
+ }
}
}
/// Get the number of weak references to this value.
-#[cfg(stage0)]
-#[inline]
-#[unstable(feature = "alloc")]
-pub fn weak_count<T>(this: &Rc<T>) -> usize { this.weak() - 1 }
-#[cfg(not(stage0))]
#[inline]
-#[unstable(feature = "alloc")]
-pub fn weak_count<T: ?Sized>(this: &Rc<T>) -> usize { this.weak() - 1 }
+#[unstable(feature = "rc_counts")]
+#[deprecated(since = "1.2.0", reason = "renamed to Rc::weak_count")]
+pub fn weak_count<T: ?Sized>(this: &Rc<T>) -> usize { Rc::weak_count(this) }
/// Get the number of strong references to this value.
-#[cfg(stage0)]
#[inline]
-#[unstable(feature = "alloc")]
-pub fn strong_count<T>(this: &Rc<T>) -> usize { this.strong() }
-#[cfg(not(stage0))]
-#[inline]
-#[unstable(feature = "alloc")]
-pub fn strong_count<T: ?Sized>(this: &Rc<T>) -> usize { this.strong() }
+#[unstable(feature = "rc_counts")]
+#[deprecated(since = "1.2.0", reason = "renamed to Rc::strong_count")]
+pub fn strong_count<T: ?Sized>(this: &Rc<T>) -> usize { Rc::strong_count(this) }
/// Returns true if there are no other `Rc` or `Weak<T>` values that share the
/// same inner value.
/// # Examples
///
/// ```
-/// # #![feature(alloc)]
+/// # #![feature(rc_unique)]
/// use std::rc;
/// use std::rc::Rc;
///
/// rc::is_unique(&five);
/// ```
#[inline]
-#[unstable(feature = "alloc")]
-pub fn is_unique<T>(rc: &Rc<T>) -> bool {
- weak_count(rc) == 0 && strong_count(rc) == 1
-}
+#[unstable(feature = "rc_unique")]
+#[deprecated(since = "1.2.0", reason = "renamed to Rc::is_unique")]
+pub fn is_unique<T>(rc: &Rc<T>) -> bool { Rc::is_unique(rc) }
/// Unwraps the contained value if the `Rc<T>` is unique.
///
/// # Examples
///
/// ```
-/// # #![feature(alloc)]
+/// # #![feature(rc_unique)]
/// use std::rc::{self, Rc};
///
/// let x = Rc::new(3);
/// assert_eq!(rc::try_unwrap(x), Err(Rc::new(4)));
/// ```
#[inline]
-#[unstable(feature = "alloc")]
-pub fn try_unwrap<T>(rc: Rc<T>) -> Result<T, Rc<T>> {
- if is_unique(&rc) {
- unsafe {
- let val = ptr::read(&*rc); // copy the contained object
- // destruct the box and skip our Drop
- // we can ignore the refcounts because we know we're unique
- deallocate(*rc._ptr as *mut u8, size_of::<RcBox<T>>(),
- min_align_of::<RcBox<T>>());
- forget(rc);
- Ok(val)
- }
- } else {
- Err(rc)
- }
-}
+#[unstable(feature = "rc_unique")]
+#[deprecated(since = "1.2.0", reason = "renamed to Rc::try_unwrap")]
+pub fn try_unwrap<T>(rc: Rc<T>) -> Result<T, Rc<T>> { Rc::try_unwrap(rc) }
/// Returns a mutable reference to the contained value if the `Rc<T>` is unique.
///
/// # Examples
///
/// ```
-/// # #![feature(alloc)]
+/// # #![feature(rc_unique)]
/// use std::rc::{self, Rc};
///
/// let mut x = Rc::new(3);
/// assert!(rc::get_mut(&mut x).is_none());
/// ```
#[inline]
-#[unstable(feature = "alloc")]
-pub fn get_mut<T>(rc: &mut Rc<T>) -> Option<&mut T> {
- if is_unique(rc) {
- let inner = unsafe { &mut **rc._ptr };
- Some(&mut inner.value)
- } else {
- None
- }
-}
+#[unstable(feature = "rc_unique")]
+#[deprecated(since = "1.2.0", reason = "renamed to Rc::get_mut")]
+pub fn get_mut<T>(rc: &mut Rc<T>) -> Option<&mut T> { Rc::get_mut(rc) }
impl<T: Clone> Rc<T> {
/// Make a mutable reference from the given `Rc<T>`.
/// # Examples
///
/// ```
- /// # #![feature(alloc)]
+ /// # #![feature(rc_unique)]
/// use std::rc::Rc;
///
/// let mut five = Rc::new(5);
/// let mut_five = five.make_unique();
/// ```
#[inline]
- #[unstable(feature = "alloc")]
+ #[unstable(feature = "rc_unique")]
pub fn make_unique(&mut self) -> &mut T {
- if !is_unique(self) {
+ if !Rc::is_unique(self) {
*self = Rc::new((**self).clone())
}
// This unsafety is ok because we're guaranteed that the pointer
}
}
-#[cfg(stage0)]
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Deref for Rc<T> {
- type Target = T;
-
- #[inline(always)]
- fn deref(&self) -> &T {
- &self.inner().value
- }
-}
-#[cfg(not(stage0))]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Deref for Rc<T> {
type Target = T;
}
}
-#[cfg(stage0)]
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Drop for Rc<T> {
- /// Drops the `Rc<T>`.
- ///
- /// This will decrement the strong reference count. If the strong reference
- /// count becomes zero and the only other references are `Weak<T>` ones,
- /// `drop`s the inner value.
- ///
- /// # Examples
- ///
- /// ```
- /// # #![feature(alloc)]
- /// use std::rc::Rc;
- ///
- /// {
- /// let five = Rc::new(5);
- ///
- /// // stuff
- ///
- /// drop(five); // explicit drop
- /// }
- /// {
- /// let five = Rc::new(5);
- ///
- /// // stuff
- ///
- /// } // implicit drop
- /// ```
- fn drop(&mut self) {
- unsafe {
- let ptr = *self._ptr;
- if !ptr.is_null() && ptr as usize != mem::POST_DROP_USIZE {
- self.dec_strong();
- if self.strong() == 0 {
- ptr::read(&**self); // destroy the contained object
-
- // remove the implicit "strong weak" pointer now that we've
- // destroyed the contents.
- self.dec_weak();
-
- if self.weak() == 0 {
- deallocate(ptr as *mut u8, size_of::<RcBox<T>>(),
- min_align_of::<RcBox<T>>())
- }
- }
- }
- }
- }
-}
-
-#[cfg(not(stage0))]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Drop for Rc<T> {
/// Drops the `Rc<T>`.
/// # Examples
///
/// ```
- /// # #![feature(alloc)]
/// use std::rc::Rc;
///
/// {
unsafe {
let ptr = *self._ptr;
if !(*(&ptr as *const _ as *const *const ())).is_null() &&
- ptr as usize != mem::POST_DROP_USIZE {
+ ptr as *const () as usize != mem::POST_DROP_USIZE {
self.dec_strong();
if self.strong() == 0 {
// destroy the contained object
if self.weak() == 0 {
deallocate(ptr as *mut u8,
size_of_val(&*ptr),
- min_align_of_val(&*ptr))
+ align_of_val(&*ptr))
}
}
}
}
}
-#[cfg(stage0)]
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Clone for Rc<T> {
-
- /// Makes a clone of the `Rc<T>`.
- ///
- /// When you clone an `Rc<T>`, it will create another pointer to the data and
- /// increase the strong reference counter.
- ///
- /// # Examples
- ///
- /// ```
- /// # #![feature(alloc)]
- /// use std::rc::Rc;
- ///
- /// let five = Rc::new(5);
- ///
- /// five.clone();
- /// ```
- #[inline]
- fn clone(&self) -> Rc<T> {
- self.inc_strong();
- Rc { _ptr: self._ptr }
- }
-}
-#[cfg(not(stage0))]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Clone for Rc<T> {
/// # Examples
///
/// ```
- /// # #![feature(alloc)]
/// use std::rc::Rc;
///
/// let five = Rc::new(5);
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: PartialEq> PartialEq for Rc<T> {
+impl<T: ?Sized + PartialEq> PartialEq for Rc<T> {
/// Equality for two `Rc<T>`s.
///
/// Two `Rc<T>`s are equal if their inner value are equal.
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Eq> Eq for Rc<T> {}
+impl<T: ?Sized + Eq> Eq for Rc<T> {}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: PartialOrd> PartialOrd for Rc<T> {
+impl<T: ?Sized + PartialOrd> PartialOrd for Rc<T> {
/// Partial comparison for two `Rc<T>`s.
///
/// The two are compared by calling `partial_cmp()` on their inner values.
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Ord> Ord for Rc<T> {
+impl<T: ?Sized + Ord> Ord for Rc<T> {
/// Comparison for two `Rc<T>`s.
///
/// The two are compared by calling `cmp()` on their inner values.
fn cmp(&self, other: &Rc<T>) -> Ordering { (**self).cmp(&**other) }
}
-#[cfg(stage0)]
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Hash> Hash for Rc<T> {
- fn hash<H: Hasher>(&self, state: &mut H) {
- (**self).hash(state);
- }
-}
-#[cfg(not(stage0))]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized+Hash> Hash for Rc<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
}
}
-#[cfg(stage0)]
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: fmt::Display> fmt::Display for Rc<T> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Display::fmt(&**self, f)
- }
-}
-#[cfg(not(stage0))]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized+fmt::Display> fmt::Display for Rc<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
}
}
-#[cfg(stage0)]
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: fmt::Debug> fmt::Debug for Rc<T> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Debug::fmt(&**self, f)
- }
-}
-#[cfg(not(stage0))]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized+fmt::Debug> fmt::Debug for Rc<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
/// dropped.
///
/// See the [module level documentation](./index.html) for more.
-#[cfg(stage0)]
-#[unsafe_no_drop_flag]
-#[unstable(feature = "alloc",
- reason = "Weak pointers may not belong in this module.")]
-pub struct Weak<T> {
- // FIXME #12808: strange names to try to avoid interfering with
- // field accesses of the contained type via Deref
- _ptr: NonZero<*mut RcBox<T>>,
-}
-#[cfg(not(stage0))]
#[unsafe_no_drop_flag]
-#[unstable(feature = "alloc",
+#[unstable(feature = "rc_weak",
reason = "Weak pointers may not belong in this module.")]
pub struct Weak<T: ?Sized> {
// FIXME #12808: strange names to try to avoid interfering with
_ptr: NonZero<*mut RcBox<T>>,
}
-#[cfg(stage0)]
-impl<T> !marker::Send for Weak<T> {}
-#[cfg(not(stage0))]
impl<T: ?Sized> !marker::Send for Weak<T> {}
-
-#[cfg(stage0)]
-impl<T> !marker::Sync for Weak<T> {}
-#[cfg(not(stage0))]
impl<T: ?Sized> !marker::Sync for Weak<T> {}
-
-#[cfg(stage0)]
-#[unstable(feature = "alloc",
- reason = "Weak pointers may not belong in this module.")]
-impl<T> Weak<T> {
-
- /// Upgrades a weak reference to a strong reference.
- ///
- /// Upgrades the `Weak<T>` reference to an `Rc<T>`, if possible.
- ///
- /// Returns `None` if there were no strong references and the data was
- /// destroyed.
- ///
- /// # Examples
- ///
- /// ```
- /// # #![feature(alloc)]
- /// use std::rc::Rc;
- ///
- /// let five = Rc::new(5);
- ///
- /// let weak_five = five.downgrade();
- ///
- /// let strong_five: Option<Rc<_>> = weak_five.upgrade();
- /// ```
- pub fn upgrade(&self) -> Option<Rc<T>> {
- if self.strong() == 0 {
- None
- } else {
- self.inc_strong();
- Some(Rc { _ptr: self._ptr })
- }
- }
-}
-#[cfg(not(stage0))]
-#[unstable(feature = "alloc",
+#[unstable(feature = "rc_weak",
reason = "Weak pointers may not belong in this module.")]
impl<T: ?Sized> Weak<T> {
/// # Examples
///
/// ```
- /// # #![feature(alloc)]
+ /// # #![feature(rc_weak)]
/// use std::rc::Rc;
///
/// let five = Rc::new(5);
}
}
-#[cfg(stage0)]
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Drop for Weak<T> {
- /// Drops the `Weak<T>`.
- ///
- /// This will decrement the weak reference count.
- ///
- /// # Examples
- ///
- /// ```
- /// # #![feature(alloc)]
- /// use std::rc::Rc;
- ///
- /// {
- /// let five = Rc::new(5);
- /// let weak_five = five.downgrade();
- ///
- /// // stuff
- ///
- /// drop(weak_five); // explicit drop
- /// }
- /// {
- /// let five = Rc::new(5);
- /// let weak_five = five.downgrade();
- ///
- /// // stuff
- ///
- /// } // implicit drop
- /// ```
- fn drop(&mut self) {
- unsafe {
- let ptr = *self._ptr;
- if !ptr.is_null() && ptr as usize != mem::POST_DROP_USIZE {
- self.dec_weak();
- // the weak count starts at 1, and will only go to zero if all
- // the strong pointers have disappeared.
- if self.weak() == 0 {
- deallocate(ptr as *mut u8, size_of::<RcBox<T>>(),
- min_align_of::<RcBox<T>>())
- }
- }
- }
- }
-}
-
-#[cfg(not(stage0))]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Drop for Weak<T> {
/// Drops the `Weak<T>`.
/// # Examples
///
/// ```
- /// # #![feature(alloc)]
+ /// # #![feature(rc_weak)]
/// use std::rc::Rc;
///
/// {
unsafe {
let ptr = *self._ptr;
if !(*(&ptr as *const _ as *const *const ())).is_null() &&
- ptr as usize != mem::POST_DROP_USIZE {
+ ptr as *const () as usize != mem::POST_DROP_USIZE {
self.dec_weak();
// the weak count starts at 1, and will only go to zero if all
// the strong pointers have disappeared.
if self.weak() == 0 {
deallocate(ptr as *mut u8, size_of_val(&*ptr),
- min_align_of_val(&*ptr))
+ align_of_val(&*ptr))
}
}
}
}
}
-#[cfg(stage0)]
-#[unstable(feature = "alloc",
- reason = "Weak pointers may not belong in this module.")]
-impl<T> Clone for Weak<T> {
-
- /// Makes a clone of the `Weak<T>`.
- ///
- /// This increases the weak reference count.
- ///
- /// # Examples
- ///
- /// ```
- /// # #![feature(alloc)]
- /// use std::rc::Rc;
- ///
- /// let weak_five = Rc::new(5).downgrade();
- ///
- /// weak_five.clone();
- /// ```
- #[inline]
- fn clone(&self) -> Weak<T> {
- self.inc_weak();
- Weak { _ptr: self._ptr }
- }
-}
-#[cfg(not(stage0))]
-#[unstable(feature = "alloc",
+#[unstable(feature = "rc_weak",
reason = "Weak pointers may not belong in this module.")]
impl<T: ?Sized> Clone for Weak<T> {
/// # Examples
///
/// ```
- /// # #![feature(alloc)]
+ /// # #![feature(rc_weak)]
/// use std::rc::Rc;
///
/// let weak_five = Rc::new(5).downgrade();
}
}
-#[cfg(stage0)]
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: fmt::Debug> fmt::Debug for Weak<T> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "(Weak)")
- }
-}
-#[cfg(not(stage0))]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized+fmt::Debug> fmt::Debug for Weak<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
}
}
-#[cfg(stage0)]
-#[doc(hidden)]
-trait RcBoxPtr<T> {
- fn inner(&self) -> &RcBox<T>;
-
- #[inline]
- fn strong(&self) -> usize { self.inner().strong.get() }
-
- #[inline]
- fn inc_strong(&self) { self.inner().strong.set(self.strong() + 1); }
-
- #[inline]
- fn dec_strong(&self) { self.inner().strong.set(self.strong() - 1); }
-
- #[inline]
- fn weak(&self) -> usize { self.inner().weak.get() }
-
- #[inline]
- fn inc_weak(&self) { self.inner().weak.set(self.weak() + 1); }
-
- #[inline]
- fn dec_weak(&self) { self.inner().weak.set(self.weak() - 1); }
-}
-#[cfg(not(stage0))]
#[doc(hidden)]
trait RcBoxPtr<T: ?Sized> {
fn inner(&self) -> &RcBox<T>;
fn dec_weak(&self) { self.inner().weak.set(self.weak() - 1); }
}
-#[cfg(stage0)]
-impl<T> RcBoxPtr<T> for Rc<T> {
- #[inline(always)]
- fn inner(&self) -> &RcBox<T> {
- unsafe {
- // Safe to assume this here, as if it weren't true, we'd be breaking
- // the contract anyway.
- // This allows the null check to be elided in the destructor if we
- // manipulated the reference count in the same function.
- assume(!(*(&self._ptr as *const _ as *const *const ())).is_null());
- &(**self._ptr)
- }
- }
-}
-#[cfg(not(stage0))]
impl<T: ?Sized> RcBoxPtr<T> for Rc<T> {
#[inline(always)]
fn inner(&self) -> &RcBox<T> {
}
}
-#[cfg(stage0)]
-impl<T> RcBoxPtr<T> for Weak<T> {
- #[inline(always)]
- fn inner(&self) -> &RcBox<T> {
- unsafe {
- // Safe to assume this here, as if it weren't true, we'd be breaking
- // the contract anyway.
- // This allows the null check to be elided in the destructor if we
- // manipulated the reference count in the same function.
- assume(!(*(&self._ptr as *const _ as *const *const ())).is_null());
- &(**self._ptr)
- }
- }
-}
-#[cfg(not(stage0))]
impl<T: ?Sized> RcBoxPtr<T> for Weak<T> {
#[inline(always)]
fn inner(&self) -> &RcBox<T> {
assert_eq!(format!("{:?}", foo), "75");
}
+ #[test]
+ fn test_unsized() {
+ let foo: Rc<[i32]> = Rc::new([1, 2, 3]);
+ assert_eq!(foo, foo.clone());
+ }
}
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
- html_favicon_url = "http://www.rust-lang.org/favicon.ico",
+ html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/")]
#![feature(alloc)]
#![feature(box_syntax)]
-#![feature(core)]
+#![feature(core_intrinsics)]
+#![feature(heap_api)]
+#![feature(oom)]
+#![feature(ptr_as_ref)]
+#![feature(raw)]
#![feature(staged_api)]
-#![feature(unboxed_closures)]
#![cfg_attr(test, feature(test))]
extern crate alloc;
fn drop(&mut self) {
unsafe {
destroy_chunk(&*self.head.borrow());
- for chunk in &*self.chunks.borrow() {
+ for chunk in self.chunks.borrow().iter() {
if !chunk.is_copy.get() {
destroy_chunk(chunk);
}
fn alloc_copy<T, F>(&self, op: F) -> &mut T where F: FnOnce() -> T {
unsafe {
let ptr = self.alloc_copy_inner(mem::size_of::<T>(),
- mem::min_align_of::<T>());
+ mem::align_of::<T>());
let ptr = ptr as *mut T;
ptr::write(&mut (*ptr), op());
return &mut *ptr;
let tydesc = get_tydesc::<T>();
let (ty_ptr, ptr) =
self.alloc_noncopy_inner(mem::size_of::<T>(),
- mem::min_align_of::<T>());
+ mem::align_of::<T>());
let ty_ptr = ty_ptr as *mut usize;
let ptr = ptr as *mut T;
// Write in our tydesc along with a bit indicating that it
fn calculate_size<T>(capacity: usize) -> usize {
let mut size = mem::size_of::<TypedArenaChunk<T>>();
- size = round_up(size, mem::min_align_of::<T>());
+ size = round_up(size, mem::align_of::<T>());
let elem_size = mem::size_of::<T>();
let elems_size = elem_size.checked_mul(capacity).unwrap();
size = size.checked_add(elems_size).unwrap();
unsafe fn new(next: *mut TypedArenaChunk<T>, capacity: usize)
-> *mut TypedArenaChunk<T> {
let size = calculate_size::<T>(capacity);
- let chunk = allocate(size, mem::min_align_of::<TypedArenaChunk<T>>())
+ let chunk = allocate(size, mem::align_of::<TypedArenaChunk<T>>())
as *mut TypedArenaChunk<T>;
if chunk.is_null() { alloc::oom() }
(*chunk).next = next;
let size = calculate_size::<T>(self.capacity);
let self_ptr: *mut TypedArenaChunk<T> = self;
deallocate(self_ptr as *mut u8, size,
- mem::min_align_of::<TypedArenaChunk<T>>());
+ mem::align_of::<TypedArenaChunk<T>>());
if !next.is_null() {
let capacity = (*next).capacity;
(*next).destroy(capacity);
let this: *const TypedArenaChunk<T> = self;
unsafe {
mem::transmute(round_up(this.offset(1) as usize,
- mem::min_align_of::<T>()))
+ mem::align_of::<T>()))
}
}
//! A priority queue implemented with a binary heap.
//!
-//! Insertion and popping the largest element have `O(log n)` time complexity. Checking the largest
-//! element is `O(1)`. Converting a vector to a binary heap can be done in-place, and has `O(n)`
-//! complexity. A binary heap can also be converted to a sorted vector in-place, allowing it to
-//! be used for an `O(n log n)` in-place heapsort.
+//! Insertion and popping the largest element have `O(log n)` time complexity.
+//! Checking the largest element is `O(1)`. Converting a vector to a binary heap
+//! can be done in-place, and has `O(n)` complexity. A binary heap can also be
+//! converted to a sorted vector in-place, allowing it to be used for an `O(n
+//! log n)` in-place heapsort.
//!
//! # Examples
//!
//!
//! // For each node we can reach, see if we can find a way with
//! // a lower cost going through this node
-//! for edge in adj_list[position].iter() {
+//! for edge in &adj_list[position] {
//! let next = State { cost: cost + edge.cost, position: edge.node };
//!
//! // If so, add it to the frontier and continue
/// let vec = heap.into_vec();
///
/// // Will print in some order
- /// for x in vec.iter() {
+ /// for x in vec {
/// println!("{}", x);
/// }
/// ```
///
/// The elements are removed in arbitrary order.
#[inline]
- #[unstable(feature = "collections",
- reason = "matches collection reform specification, waiting for dust to settle")]
+ #[unstable(feature = "drain",
+ reason = "matches collection reform specification, \
+ waiting for dust to settle")]
pub fn drain(&mut self) -> Drain<T> {
Drain { iter: self.data.drain(..) }
}
impl<T> ExactSizeIterator for IntoIter<T> {}
/// An iterator that drains a `BinaryHeap`.
-#[unstable(feature = "collections", reason = "recent addition")]
+#[unstable(feature = "drain", reason = "recent addition")]
pub struct Drain<'a, T: 'a> {
iter: vec::Drain<'a, T>,
}
}
}
}
+
+#[stable(feature = "extend_ref", since = "1.2.0")]
+impl<'a, T: 'a + Ord + Copy> Extend<&'a T> for BinaryHeap<T> {
+ fn extend<I: IntoIterator<Item=&'a T>>(&mut self, iter: I) {
+ self.extend(iter.into_iter().cloned());
+ }
+}
//! [sieve]: http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
//!
//! ```
-//! # #![feature(collections, core, step_by)]
+//! # #![feature(bitset, bitvec, range_inclusive, step_by)]
//! use std::collections::{BitSet, BitVec};
//! use std::iter;
//!
use core::cmp;
use core::fmt;
use core::hash;
+#[allow(deprecated)]
use core::iter::RandomAccessIterator;
use core::iter::{Chain, Enumerate, Repeat, Skip, Take, repeat, Cloned};
use core::iter::{self, FromIterator};
}
}
-static TRUE: bool = true;
-static FALSE: bool = false;
+const TRUE: &'static bool = &true;
+const FALSE: &'static bool = &false;
/// The bitvector type.
///
/// # Examples
///
/// ```
-/// # #![feature(collections)]
+/// # #![feature(bitvec)]
/// use std::collections::BitVec;
///
/// let mut bv = BitVec::from_elem(10, false);
/// println!("{:?}", bv);
/// println!("total bits set to true: {}", bv.iter().filter(|x| *x).count());
/// ```
-#[unstable(feature = "collections",
- reason = "RFC 509")]
+#[unstable(feature = "bitvec", reason = "RFC 509")]
pub struct BitVec {
/// Internal representation of the bit vector
storage: Vec<u32>,
#[inline]
fn index(&self, i: usize) -> &bool {
if self.get(i).expect("index out of bounds") {
- &TRUE
+ TRUE
} else {
- &FALSE
+ FALSE
}
}
}
/// Computes how many blocks are needed to store that many bits
fn blocks_for_bits(bits: usize) -> usize {
- // If we want 17 bits, dividing by 32 will produce 0. So we add 1 to make sure we
- // reserve enough. But if we want exactly a multiple of 32, this will actually allocate
- // one too many. So we need to check if that's the case. We can do that by computing if
- // bitwise AND by `32 - 1` is 0. But LLVM should be able to optimize the semantically
- // superior modulo operator on a power of two to this.
+ // If we want 17 bits, dividing by 32 will produce 0. So we add 1 to make
+ // sure we reserve enough. But if we want exactly a multiple of 32, this
+ // will actually allocate one too many. So we need to check if that's the
+ // case. We can do that by computing if bitwise AND by `32 - 1` is 0. But
+ // LLVM should be able to optimize the semantically superior modulo operator
+ // on a power of two to this.
//
// Note that we can technically avoid this branch with the expression
- // `(nbits + u32::BITS - 1) / 32::BITS`, but if nbits is almost usize::MAX this will overflow.
+ // `(nbits + u32::BITS - 1) / 32::BITS`, but if nbits is almost usize::MAX
+ // this will overflow.
if bits % u32::BITS == 0 {
bits / u32::BITS
} else {
!0 >> (u32::BITS - bits % u32::BITS) % u32::BITS
}
+#[unstable(feature = "bitvec", reason = "RFC 509")]
impl BitVec {
/// Applies the given operation to the blocks of self and other, and sets
/// self to be the result. This relies on the caller not to corrupt the
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(bitvec)]
/// use std::collections::BitVec;
/// let mut bv = BitVec::new();
/// ```
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(bitvec)]
/// use std::collections::BitVec;
///
- /// let mut bv = BitVec::from_elem(10, false);
+ /// let bv = BitVec::from_elem(10, false);
/// assert_eq!(bv.len(), 10);
- /// for x in bv.iter() {
+ /// for x in &bv {
/// assert_eq!(x, false);
/// }
/// ```
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(bitvec)]
/// use std::collections::BitVec;
///
/// let bv = BitVec::from_bytes(&[0b10100000, 0b00010010]);
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(bitvec)]
/// use std::collections::BitVec;
///
/// let bv = BitVec::from_fn(5, |i| { i % 2 == 0 });
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(bitvec)]
/// use std::collections::BitVec;
///
/// let bv = BitVec::from_bytes(&[0b01100000]);
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(bitvec)]
/// use std::collections::BitVec;
///
/// let mut bv = BitVec::from_elem(5, false);
/// assert_eq!(bv[3], true);
/// ```
#[inline]
- #[unstable(feature = "collections",
- reason = "panic semantics are likely to change in the future")]
pub fn set(&mut self, i: usize, x: bool) {
assert!(i < self.nbits);
let w = i / u32::BITS;
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(bitvec)]
/// use std::collections::BitVec;
///
/// let before = 0b01100000;
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(bitvec)]
/// use std::collections::BitVec;
///
/// let before = 0b01100000;
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(bitvec)]
/// use std::collections::BitVec;
///
/// let a = 0b01100100;
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(bitvec)]
/// use std::collections::BitVec;
///
/// let a = 0b01100100;
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(bitvec)]
/// use std::collections::BitVec;
///
/// let a = 0b01100100;
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(bitvec)]
/// use std::collections::BitVec;
///
/// let mut bv = BitVec::from_elem(5, true);
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(bitvec)]
/// use std::collections::BitVec;
///
/// let bv = BitVec::from_bytes(&[0b01110100, 0b10010010]);
/// # Examples
///
/// ```
- /// # #![feature(collections, bit_vec_append_split_off)]
+ /// # #![feature(bitvec, append)]
/// use std::collections::BitVec;
///
/// let mut a = BitVec::from_bytes(&[0b10000000]);
/// assert!(a.eq_vec(&[true, false, false, false, false, false, false, false,
/// false, true, true, false, false, false, false, true]));
/// ```
- #[unstable(feature = "bit_vec_append_split_off",
+ #[unstable(feature = "append",
reason = "recently added as part of collections reform 2")]
pub fn append(&mut self, other: &mut Self) {
let b = self.len() % u32::BITS;
/// # Examples
///
/// ```
- /// # #![feature(collections, bit_vec_append_split_off)]
+ /// # #![feature(bitvec, split_off)]
/// use std::collections::BitVec;
/// let mut a = BitVec::new();
/// a.push(true);
/// assert!(a.eq_vec(&[true, false]));
/// assert!(b.eq_vec(&[false, true]));
/// ```
- #[unstable(feature = "bit_vec_append_split_off",
+ #[unstable(feature = "split_off",
reason = "recently added as part of collections reform 2")]
pub fn split_off(&mut self, at: usize) -> Self {
assert!(at <= self.len(), "`at` out of bounds");
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(bitvec)]
/// use std::collections::BitVec;
///
/// let mut bv = BitVec::from_elem(10, false);
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(bitvec)]
/// use std::collections::BitVec;
///
/// let mut bv = BitVec::from_elem(10, false);
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(bitvec)]
/// use std::collections::BitVec;
///
/// let mut bv = BitVec::from_elem(3, true);
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(bitvec)]
/// use std::collections::BitVec;
///
/// let bv = BitVec::from_bytes(&[0b10100000]);
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(bitvec)]
/// use std::collections::BitVec;
///
/// let mut bv = BitVec::from_bytes(&[0b01001011]);
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(bitvec)]
/// use std::collections::BitVec;
///
/// let mut bv = BitVec::from_elem(3, false);
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(bitvec)]
/// use std::collections::BitVec;
///
/// let mut bv = BitVec::from_elem(3, false);
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(bitvec)]
/// use std::collections::BitVec;
///
/// let mut bv = BitVec::new();
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(bitvec)]
/// use std::collections::BitVec;
///
/// let mut bv = BitVec::from_bytes(&[0b01001011]);
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(bitvec)]
/// use std::collections::BitVec;
///
/// let mut bv = BitVec::from_bytes(&[0b01001001]);
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(bitvec)]
/// use std::collections::BitVec;
///
/// let mut bv = BitVec::new();
}
}
+#[stable(feature = "extend_ref", since = "1.2.0")]
+impl<'a> Extend<&'a bool> for BitVec {
+ fn extend<I: IntoIterator<Item=&'a bool>>(&mut self, iter: I) {
+ self.extend(iter.into_iter().cloned());
+ }
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl Clone for BitVec {
#[inline]
impl<'a> ExactSizeIterator for Iter<'a> {}
#[stable(feature = "rust1", since = "1.0.0")]
+#[allow(deprecated)]
impl<'a> RandomAccessIterator for Iter<'a> {
#[inline]
fn indexable(&self) -> usize {
/// # Examples
///
/// ```
-/// # #![feature(collections)]
+/// # #![feature(bitvec, bitset)]
/// use std::collections::{BitSet, BitVec};
///
/// // It's a regular set
/// s.union_with(&other);
///
/// // Print 0, 1, 3 in some order
-/// for x in s.iter() {
+/// for x in &s {
/// println!("{}", x);
/// }
///
/// assert!(bv[3]);
/// ```
#[derive(Clone)]
-#[unstable(feature = "collections",
- reason = "RFC 509")]
+#[unstable(feature = "bitset", reason = "RFC 509")]
pub struct BitSet {
bit_vec: BitVec,
}
}
}
+#[stable(feature = "extend_ref", since = "1.2.0")]
+impl<'a> Extend<&'a usize> for BitSet {
+ fn extend<I: IntoIterator<Item=&'a usize>>(&mut self, iter: I) {
+ self.extend(iter.into_iter().cloned());
+ }
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl PartialOrd for BitSet {
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
impl cmp::Eq for BitSet {}
+#[unstable(feature = "bitset", reason = "RFC 509")]
impl BitSet {
/// Creates a new empty `BitSet`.
///
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(bitset)]
/// use std::collections::BitSet;
///
/// let mut s = BitSet::new();
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(bitset)]
/// use std::collections::BitSet;
///
/// let mut s = BitSet::with_capacity(100);
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(bitset, bitvec)]
/// use std::collections::{BitVec, BitSet};
///
/// let bv = BitVec::from_bytes(&[0b01100000]);
/// let s = BitSet::from_bit_vec(bv);
///
/// // Print 1, 2 in arbitrary order
- /// for x in s.iter() {
+ /// for x in &s {
/// println!("{}", x);
/// }
/// ```
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(bitset)]
/// use std::collections::BitSet;
///
/// let mut s = BitSet::with_capacity(100);
self.bit_vec.capacity()
}
- /// Reserves capacity for the given `BitSet` to contain `len` distinct elements. In the case
- /// of `BitSet` this means reallocations will not occur as long as all inserted elements
- /// are less than `len`.
+ /// Reserves capacity for the given `BitSet` to contain `len` distinct
+ /// elements. In the case of `BitSet` this means reallocations will not
+ /// occur as long as all inserted elements are less than `len`.
///
/// The collection may reserve more space to avoid frequent reallocations.
///
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(bitset)]
/// use std::collections::BitSet;
///
/// let mut s = BitSet::new();
}
}
- /// Reserves the minimum capacity for the given `BitSet` to contain `len` distinct elements.
- /// In the case of `BitSet` this means reallocations will not occur as long as all inserted
- /// elements are less than `len`.
+ /// Reserves the minimum capacity for the given `BitSet` to contain `len`
+ /// distinct elements. In the case of `BitSet` this means reallocations
+ /// will not occur as long as all inserted elements are less than `len`.
///
- /// Note that the allocator may give the collection more space than it requests. Therefore
- /// capacity can not be relied upon to be precisely minimal. Prefer `reserve_len` if future
- /// insertions are expected.
+ /// Note that the allocator may give the collection more space than it
+ /// requests. Therefore capacity can not be relied upon to be precisely
+ /// minimal. Prefer `reserve_len` if future insertions are expected.
///
///
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(bitset)]
/// use std::collections::BitSet;
///
/// let mut s = BitSet::new();
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(bitset)]
/// use std::collections::BitSet;
///
/// let mut s = BitSet::new();
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(bitset)]
/// use std::collections::BitSet;
///
/// let mut s = BitSet::new();
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(bitset)]
/// use std::collections::BitSet;
///
/// let mut s = BitSet::new();
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(bitset, bitvec)]
/// use std::collections::{BitVec, BitSet};
///
/// let s = BitSet::from_bit_vec(BitVec::from_bytes(&[0b01001010]));
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn iter(&self) -> bit_set::Iter {
- SetIter {set: self, next_idx: 0}
+ SetIter(BlockIter::from_blocks(self.bit_vec.blocks()))
}
/// Iterator over each usize stored in `self` union `other`.
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(bitset, bitvec)]
/// use std::collections::{BitVec, BitSet};
///
/// let a = BitSet::from_bit_vec(BitVec::from_bytes(&[0b01101000]));
pub fn union<'a>(&'a self, other: &'a BitSet) -> Union<'a> {
fn or(w1: u32, w2: u32) -> u32 { w1 | w2 }
- Union(TwoBitPositions {
- set: self,
- other: other,
+ Union(BlockIter::from_blocks(TwoBitPositions {
+ set: self.bit_vec.blocks(),
+ other: other.bit_vec.blocks(),
merge: or,
- current_word: 0,
- next_idx: 0
- })
+ }))
}
/// Iterator over each usize stored in `self` intersect `other`.
- /// See [intersect_with](#method.intersect_with) for an efficient in-place version.
+ /// See [intersect_with](#method.intersect_with) for an efficient in-place
+ /// version.
///
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(bitset, bitvec)]
/// use std::collections::{BitVec, BitSet};
///
/// let a = BitSet::from_bit_vec(BitVec::from_bytes(&[0b01101000]));
pub fn intersection<'a>(&'a self, other: &'a BitSet) -> Intersection<'a> {
fn bitand(w1: u32, w2: u32) -> u32 { w1 & w2 }
let min = cmp::min(self.bit_vec.len(), other.bit_vec.len());
- Intersection(TwoBitPositions {
- set: self,
- other: other,
+
+ Intersection(BlockIter::from_blocks(TwoBitPositions {
+ set: self.bit_vec.blocks(),
+ other: other.bit_vec.blocks(),
merge: bitand,
- current_word: 0,
- next_idx: 0
- }.take(min))
+ }).take(min))
}
/// Iterator over each usize stored in the `self` setminus `other`.
- /// See [difference_with](#method.difference_with) for an efficient in-place version.
+ /// See [difference_with](#method.difference_with) for an efficient in-place
+ /// version.
///
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(bitset, bitvec)]
/// use std::collections::{BitSet, BitVec};
///
/// let a = BitSet::from_bit_vec(BitVec::from_bytes(&[0b01101000]));
pub fn difference<'a>(&'a self, other: &'a BitSet) -> Difference<'a> {
fn diff(w1: u32, w2: u32) -> u32 { w1 & !w2 }
- Difference(TwoBitPositions {
- set: self,
- other: other,
+ Difference(BlockIter::from_blocks(TwoBitPositions {
+ set: self.bit_vec.blocks(),
+ other: other.bit_vec.blocks(),
merge: diff,
- current_word: 0,
- next_idx: 0
- })
+ }))
}
- /// Iterator over each usize stored in the symmetric difference of `self` and `other`.
- /// See [symmetric_difference_with](#method.symmetric_difference_with) for
- /// an efficient in-place version.
+ /// Iterator over each usize stored in the symmetric difference of `self`
+ /// and `other`. See
+ /// [symmetric_difference_with](#method.symmetric_difference_with) for an
+ /// efficient in-place version.
///
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(bitset, bitvec)]
/// use std::collections::{BitSet, BitVec};
///
/// let a = BitSet::from_bit_vec(BitVec::from_bytes(&[0b01101000]));
pub fn symmetric_difference<'a>(&'a self, other: &'a BitSet) -> SymmetricDifference<'a> {
fn bitxor(w1: u32, w2: u32) -> u32 { w1 ^ w2 }
- SymmetricDifference(TwoBitPositions {
- set: self,
- other: other,
+ SymmetricDifference(BlockIter::from_blocks(TwoBitPositions {
+ set: self.bit_vec.blocks(),
+ other: other.bit_vec.blocks(),
merge: bitxor,
- current_word: 0,
- next_idx: 0
- })
+ }))
}
/// Unions in-place with the specified other bit vector.
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(bitset, bitvec)]
/// use std::collections::{BitSet, BitVec};
///
/// let a = 0b01101000;
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(bitset, bitvec)]
/// use std::collections::{BitSet, BitVec};
///
/// let a = 0b01101000;
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(bitset, bitvec)]
/// use std::collections::{BitSet, BitVec};
///
/// let a = 0b01101000;
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(bitset, bitvec)]
/// use std::collections::{BitSet, BitVec};
///
/// let a = 0b01101000;
/// # Examples
///
/// ```
- /// # #![feature(collections, bit_set_append_split_off)]
+ /// # #![feature(bitset, bitvec, append)]
/// use std::collections::{BitVec, BitSet};
///
/// let mut a = BitSet::new();
/// assert_eq!(b.len(), 0);
/// assert_eq!(a, BitSet::from_bit_vec(BitVec::from_bytes(&[0b01110010])));
/// ```
- #[unstable(feature = "bit_set_append_split_off",
+ #[unstable(feature = "append",
reason = "recently added as part of collections reform 2")]
pub fn append(&mut self, other: &mut Self) {
self.union_with(other);
/// # Examples
///
/// ```
- /// # #![feature(collections, bit_set_append_split_off)]
+ /// # #![feature(bitset, bitvec, split_off)]
/// use std::collections::{BitSet, BitVec};
/// let mut a = BitSet::new();
/// a.insert(2);
/// assert_eq!(a, BitSet::from_bit_vec(BitVec::from_bytes(&[0b01100000])));
/// assert_eq!(b, BitSet::from_bit_vec(BitVec::from_bytes(&[0b00010010])));
/// ```
- #[unstable(feature = "bit_set_append_split_off",
+ #[unstable(feature = "split_off",
reason = "recently added as part of collections reform 2")]
pub fn split_off(&mut self, at: usize) -> Self {
let mut other = BitSet::new();
}
}
-/// An iterator for `BitSet`.
#[derive(Clone)]
#[stable(feature = "rust1", since = "1.0.0")]
-pub struct SetIter<'a> {
- set: &'a BitSet,
- next_idx: usize
+struct BlockIter<T> where T: Iterator<Item=u32> {
+ head: u32,
+ head_offset: usize,
+ tail: T,
+}
+
+impl<'a, T> BlockIter<T> where T: Iterator<Item=u32> {
+ fn from_blocks(mut blocks: T) -> BlockIter<T> {
+ let h = blocks.next().unwrap_or(0);
+ BlockIter {tail: blocks, head: h, head_offset: 0}
+ }
}
/// An iterator combining two `BitSet` iterators.
#[derive(Clone)]
struct TwoBitPositions<'a> {
- set: &'a BitSet,
- other: &'a BitSet,
+ set: Blocks<'a>,
+ other: Blocks<'a>,
merge: fn(u32, u32) -> u32,
- current_word: u32,
- next_idx: usize
}
+/// An iterator for `BitSet`.
#[derive(Clone)]
#[stable(feature = "rust1", since = "1.0.0")]
-pub struct Union<'a>(TwoBitPositions<'a>);
+pub struct SetIter<'a>(BlockIter<Blocks<'a>>);
#[derive(Clone)]
#[stable(feature = "rust1", since = "1.0.0")]
-pub struct Intersection<'a>(Take<TwoBitPositions<'a>>);
+pub struct Union<'a>(BlockIter<TwoBitPositions<'a>>);
#[derive(Clone)]
#[stable(feature = "rust1", since = "1.0.0")]
-pub struct Difference<'a>(TwoBitPositions<'a>);
+pub struct Intersection<'a>(Take<BlockIter<TwoBitPositions<'a>>>);
#[derive(Clone)]
#[stable(feature = "rust1", since = "1.0.0")]
-pub struct SymmetricDifference<'a>(TwoBitPositions<'a>);
+pub struct Difference<'a>(BlockIter<TwoBitPositions<'a>>);
+#[derive(Clone)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct SymmetricDifference<'a>(BlockIter<TwoBitPositions<'a>>);
#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a> Iterator for SetIter<'a> {
+impl<'a, T> Iterator for BlockIter<T> where T: Iterator<Item=u32> {
type Item = usize;
fn next(&mut self) -> Option<usize> {
- while self.next_idx < self.set.bit_vec.len() {
- let idx = self.next_idx;
- self.next_idx += 1;
-
- if self.set.contains(&idx) {
- return Some(idx);
+ while self.head == 0 {
+ match self.tail.next() {
+ Some(w) => self.head = w,
+ None => return None
}
+ self.head_offset += u32::BITS;
}
- return None;
+ // from the current block, isolate the
+ // LSB and subtract 1, producing k:
+ // a block with a number of set bits
+ // equal to the index of the LSB
+ let k = (self.head & (!self.head + 1)) - 1;
+ // update block, removing the LSB
+ self.head &= self.head - 1;
+ // return offset + (index of LSB)
+ Some(self.head_offset + (u32::count_ones(k) as usize))
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
- (0, Some(self.set.bit_vec.len() - self.next_idx))
+ match self.tail.size_hint() {
+ (_, Some(h)) => (0, Some(1 + h * (u32::BITS as usize))),
+ _ => (0, None)
+ }
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> Iterator for TwoBitPositions<'a> {
- type Item = usize;
-
- fn next(&mut self) -> Option<usize> {
- while self.next_idx < self.set.bit_vec.len() ||
- self.next_idx < self.other.bit_vec.len() {
- let bit_idx = self.next_idx % u32::BITS;
- if bit_idx == 0 {
- let s_bit_vec = &self.set.bit_vec;
- let o_bit_vec = &self.other.bit_vec;
- // Merging the two words is a bit of an awkward dance since
- // one BitVec might be longer than the other
- let word_idx = self.next_idx / u32::BITS;
- let w1 = if word_idx < s_bit_vec.storage.len() {
- s_bit_vec.storage[word_idx]
- } else { 0 };
- let w2 = if word_idx < o_bit_vec.storage.len() {
- o_bit_vec.storage[word_idx]
- } else { 0 };
- self.current_word = (self.merge)(w1, w2);
- }
-
- self.next_idx += 1;
- if self.current_word & (1 << bit_idx) != 0 {
- return Some(self.next_idx - 1);
- }
+ type Item = u32;
+
+ fn next(&mut self) -> Option<u32> {
+ match (self.set.next(), self.other.next()) {
+ (Some(a), Some(b)) => Some((self.merge)(a, b)),
+ (Some(a), None) => Some((self.merge)(a, 0)),
+ (None, Some(b)) => Some((self.merge)(0, b)),
+ _ => return None
}
- return None;
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
- let cap = cmp::max(self.set.bit_vec.len(), self.other.bit_vec.len());
- (0, Some(cap - self.next_idx))
+ let (a, au) = self.set.size_hint();
+ let (b, bu) = self.other.size_hint();
+
+ let upper = match (au, bu) {
+ (Some(au), Some(bu)) => Some(cmp::max(au, bu)),
+ _ => None
+ };
+
+ (cmp::max(a, b), upper)
}
}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> Iterator for SetIter<'a> {
+ type Item = usize;
+
+ #[inline] fn next(&mut self) -> Option<usize> { self.0.next() }
+ #[inline] fn size_hint(&self) -> (usize, Option<usize>) { self.0.size_hint() }
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> Iterator for Union<'a> {
type Item = usize;
fn borrow_mut(&mut self) -> &mut T { &mut **self }
}
-impl<T> Borrow<T> for rc::Rc<T> {
+impl<T: ?Sized> Borrow<T> for rc::Rc<T> {
fn borrow(&self) -> &T { &**self }
}
-impl<T> Borrow<T> for arc::Arc<T> {
+impl<T: ?Sized> Borrow<T> for arc::Arc<T> {
fn borrow(&self) -> &T { &**self }
}
/// tied to the original tree.
pub fn into_top(mut self) -> &'a mut V {
unsafe {
- mem::copy_mut_lifetime(
- self.map,
- self.top.from_raw_mut().val_mut()
- )
+ &mut *(self.top.from_raw_mut().val_mut() as *mut V)
}
}
}
}
}
+#[stable(feature = "extend_ref", since = "1.2.0")]
+impl<'a, K: Ord + Copy, V: Copy> Extend<(&'a K, &'a V)> for BTreeMap<K, V> {
+ fn extend<I: IntoIterator<Item=(&'a K, &'a V)>>(&mut self, iter: I) {
+ self.extend(iter.into_iter().map(|(&key, &value)| (key, value)));
+ }
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<K: Hash, V: Hash> Hash for BTreeMap<K, V> {
fn hash<H: Hasher>(&self, state: &mut H) {
impl<K: PartialEq, V: PartialEq> PartialEq for BTreeMap<K, V> {
fn eq(&self, other: &BTreeMap<K, V>) -> bool {
self.len() == other.len() &&
- self.iter().zip(other.iter()).all(|(a, b)| a == b)
+ self.iter().zip(other).all(|(a, b)| a == b)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<K: Debug, V: Debug> Debug for BTreeMap<K, V> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- self.iter().fold(f.debug_map(), |b, (k, v)| b.entry(k, v)).finish()
+ f.debug_map().entries(self.iter()).finish()
}
}
}
impl<'a, K: Ord, V> Entry<'a, K, V> {
- #[unstable(feature = "std_misc",
+ #[unstable(feature = "entry",
reason = "will soon be replaced by or_insert")]
#[deprecated(since = "1.0",
reason = "replaced with more ergonomic `or_insert` and `or_insert_with`")]
/// # Examples
///
/// ```
- /// # #![feature(core)]
/// use std::collections::BTreeMap;
///
/// let mut a = BTreeMap::new();
/// a.insert(1, "a");
/// a.insert(2, "b");
///
- /// let keys: Vec<usize> = a.keys().cloned().collect();
+ /// let keys: Vec<_> = a.keys().cloned().collect();
/// assert_eq!(keys, [1, 2]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
/// # Examples
///
/// ```
- /// # #![feature(core)]
/// use std::collections::BTreeMap;
///
/// let mut a = BTreeMap::new();
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(btree_range, collections_bound)]
/// use std::collections::BTreeMap;
/// use std::collections::Bound::{Included, Unbounded};
///
/// }
/// assert_eq!(Some((&5, &"b")), map.range(Included(&4), Unbounded).next());
/// ```
- #[unstable(feature = "collections",
+ #[unstable(feature = "btree_range",
reason = "matches collection reform specification, waiting for dust to settle")]
pub fn range<'a>(&'a self, min: Bound<&K>, max: Bound<&K>) -> Range<'a, K, V> {
range_impl!(&self.root, min, max, as_slices_internal, iter, Range, edges, [])
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(btree_range, collections_bound)]
/// use std::collections::BTreeMap;
/// use std::collections::Bound::{Included, Excluded};
///
/// for (_, balance) in map.range_mut(Included(&"B"), Excluded(&"Cheryl")) {
/// *balance += 100;
/// }
- /// for (name, balance) in map.iter() {
+ /// for (name, balance) in &map {
/// println!("{} => {}", name, balance);
/// }
/// ```
- #[unstable(feature = "collections",
+ #[unstable(feature = "btree_range",
reason = "matches collection reform specification, waiting for dust to settle")]
pub fn range_mut<'a>(&'a mut self, min: Bound<&K>, max: Bound<&K>) -> RangeMut<'a, K, V> {
range_impl!(&mut self.root, min, max, as_slices_internal_mut, iter_mut, RangeMut,
/// # Examples
///
/// ```
- /// # #![feature(collections)]
/// use std::collections::BTreeMap;
///
/// let mut count: BTreeMap<&str, usize> = BTreeMap::new();
use core::prelude::*;
use core::cmp::Ordering::{Greater, Less, Equal};
+use core::intrinsics::arith_offset;
use core::iter::Zip;
use core::marker::PhantomData;
use core::ops::{Deref, DerefMut, Index, IndexMut};
}
fn calculate_allocation_generic<K, V>(capacity: usize, is_leaf: bool) -> (usize, usize) {
- let (keys_size, keys_align) = (capacity * mem::size_of::<K>(), mem::min_align_of::<K>());
- let (vals_size, vals_align) = (capacity * mem::size_of::<V>(), mem::min_align_of::<V>());
+ let (keys_size, keys_align) = (capacity * mem::size_of::<K>(), mem::align_of::<K>());
+ let (vals_size, vals_align) = (capacity * mem::size_of::<V>(), mem::align_of::<V>());
let (edges_size, edges_align) = if is_leaf {
(0, 1)
} else {
- ((capacity + 1) * mem::size_of::<Node<K, V>>(), mem::min_align_of::<Node<K, V>>())
+ ((capacity + 1) * mem::size_of::<Node<K, V>>(), mem::align_of::<Node<K, V>>())
};
calculate_allocation(
fn calculate_offsets_generic<K, V>(capacity: usize, is_leaf: bool) -> (usize, usize) {
let keys_size = capacity * mem::size_of::<K>();
let vals_size = capacity * mem::size_of::<V>();
- let vals_align = mem::min_align_of::<V>();
+ let vals_align = mem::align_of::<V>();
let edges_align = if is_leaf {
1
} else {
- mem::min_align_of::<Node<K, V>>()
+ mem::align_of::<Node<K, V>>()
};
calculate_offsets(
if mem::size_of::<T>() == 0 {
RawItems {
head: ptr,
- tail: (ptr as usize + len) as *const T,
+ tail: arith_offset(ptr as *const i8, len as isize) as *const T,
}
} else {
RawItems {
ptr::write(self.tail as *mut T, val);
if mem::size_of::<T>() == 0 {
- self.tail = (self.tail as usize + 1) as *const T;
+ self.tail = arith_offset(self.tail as *const i8, 1) as *const T;
} else {
self.tail = self.tail.offset(1);
}
let ret = Some(ptr::read(self.head));
if mem::size_of::<T>() == 0 {
- self.head = (self.head as usize + 1) as *const T;
+ self.head = arith_offset(self.head as *const i8, 1) as *const T;
} else {
self.head = self.head.offset(1);
}
} else {
unsafe {
if mem::size_of::<T>() == 0 {
- self.tail = (self.tail as usize - 1) as *const T;
+ self.tail = arith_offset(self.tail as *const i8, -1) as *const T;
} else {
self.tail = self.tail.offset(-1);
}
/// Makes a new BTreeSet with the given B.
///
/// B cannot be less than 2.
- #[unstable(feature = "collections",
+ #[unstable(feature = "btree_b",
reason = "probably want this to be on the type, eventually")]
pub fn with_b(b: usize) -> BTreeSet<T> {
BTreeSet { map: BTreeMap::with_b(b) }
/// # Examples
///
/// ```
- /// # #![feature(core)]
/// use std::collections::BTreeSet;
///
/// let set: BTreeSet<usize> = [1, 2, 3, 4].iter().cloned().collect();
/// println!("{}", x);
/// }
///
- /// let v: Vec<usize> = set.iter().cloned().collect();
+ /// let v: Vec<_> = set.iter().cloned().collect();
/// assert_eq!(v, [1, 2, 3, 4]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(btree_range, collections_bound)]
/// use std::collections::BTreeSet;
/// use std::collections::Bound::{Included, Unbounded};
///
/// }
/// assert_eq!(Some(&5), set.range(Included(&4), Unbounded).next());
/// ```
- #[unstable(feature = "collections",
+ #[unstable(feature = "btree_range",
reason = "matches collection reform specification, waiting for dust to settle")]
pub fn range<'a>(&'a self, min: Bound<&T>, max: Bound<&T>) -> Range<'a, T> {
fn first<A, B>((a, _): (A, B)) -> A { a }
/// # Examples
///
/// ```
- /// # #![feature(core)]
/// use std::collections::BTreeSet;
///
/// let mut a = BTreeSet::new();
/// b.insert(2);
/// b.insert(3);
///
- /// let diff: Vec<usize> = a.difference(&b).cloned().collect();
+ /// let diff: Vec<_> = a.difference(&b).cloned().collect();
/// assert_eq!(diff, [1]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
/// # Examples
///
/// ```
- /// # #![feature(core)]
/// use std::collections::BTreeSet;
///
/// let mut a = BTreeSet::new();
/// b.insert(2);
/// b.insert(3);
///
- /// let sym_diff: Vec<usize> = a.symmetric_difference(&b).cloned().collect();
+ /// let sym_diff: Vec<_> = a.symmetric_difference(&b).cloned().collect();
/// assert_eq!(sym_diff, [1, 3]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
/// # Examples
///
/// ```
- /// # #![feature(core)]
/// use std::collections::BTreeSet;
///
/// let mut a = BTreeSet::new();
/// b.insert(2);
/// b.insert(3);
///
- /// let intersection: Vec<usize> = a.intersection(&b).cloned().collect();
+ /// let intersection: Vec<_> = a.intersection(&b).cloned().collect();
/// assert_eq!(intersection, [2]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
/// # Examples
///
/// ```
- /// # #![feature(core)]
/// use std::collections::BTreeSet;
///
/// let mut a = BTreeSet::new();
/// let mut b = BTreeSet::new();
/// b.insert(2);
///
- /// let union: Vec<usize> = a.union(&b).cloned().collect();
+ /// let union: Vec<_> = a.union(&b).cloned().collect();
/// assert_eq!(union, [1, 2]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
/// # Examples
///
/// ```
- /// # #![feature(core)]
/// use std::collections::BTreeSet;
///
/// let set: BTreeSet<_> = [1, 2, 3].iter().cloned().collect();
/// # Examples
///
/// ```
- /// # #![feature(core)]
/// use std::collections::BTreeSet;
///
/// let a: BTreeSet<_> = [1, 2, 3].iter().cloned().collect();
/// # Examples
///
/// ```
- /// # #![feature(core)]
/// use std::collections::BTreeSet;
///
/// let sup: BTreeSet<_> = [1, 2, 3].iter().cloned().collect();
/// # Examples
///
/// ```
- /// # #![feature(core)]
/// use std::collections::BTreeSet;
///
/// let sub: BTreeSet<_> = [1, 2].iter().cloned().collect();
/// # Examples
///
/// ```
- /// # #![feature(core)]
/// use std::collections::BTreeSet;
///
/// let set: BTreeSet<usize> = [1, 2, 3, 4].iter().cloned().collect();
///
- /// let v: Vec<usize> = set.into_iter().collect();
+ /// let v: Vec<_> = set.into_iter().collect();
/// assert_eq!(v, [1, 2, 3, 4]);
/// ```
fn into_iter(self) -> IntoIter<T> {
}
}
+#[stable(feature = "extend_ref", since = "1.2.0")]
+impl<'a, T: 'a + Ord + Copy> Extend<&'a T> for BTreeSet<T> {
+ fn extend<I: IntoIterator<Item=&'a T>>(&mut self, iter: I) {
+ self.extend(iter.into_iter().cloned());
+ }
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Ord> Default for BTreeSet<T> {
#[stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Debug> Debug for BTreeSet<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- self.iter().fold(f.debug_set(), |b, e| b.entry(e)).finish()
+ f.debug_set().entries(self.iter()).finish()
}
}
//! This module defines a container which uses an efficient bit mask
//! representation to hold C-like enum variants.
+#![unstable(feature = "enumset",
+ reason = "matches collection reform specification, \
+ waiting for dust to settle")]
+
use core::prelude::*;
use core::marker;
use core::fmt;
use core::iter::{FromIterator};
use core::ops::{Sub, BitOr, BitAnd, BitXor};
-// FIXME(contentions): implement union family of methods? (general design may be wrong here)
+// FIXME(contentions): implement union family of methods? (general design may be
+// wrong here)
-#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
/// A specialized set implementation to use enum types.
///
-/// It is a logic error for an item to be modified in such a way that the transformation of the
-/// item to or from a `usize`, as determined by the `CLike` trait, changes while the item is in the
-/// set. This is normally only possible through `Cell`, `RefCell`, global state, I/O, or unsafe
-/// code.
+/// It is a logic error for an item to be modified in such a way that the
+/// transformation of the item to or from a `usize`, as determined by the
+/// `CLike` trait, changes while the item is in the set. This is normally only
+/// possible through `Cell`, `RefCell`, global state, I/O, or unsafe code.
+#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct EnumSet<E> {
// We must maintain the invariant that no bits are set
// for which no variant exists
impl<E:CLike> EnumSet<E> {
/// Returns an empty `EnumSet`.
- #[unstable(feature = "collections",
- reason = "matches collection reform specification, waiting for dust to settle")]
pub fn new() -> EnumSet<E> {
EnumSet {bits: 0, marker: marker::PhantomData}
}
/// Returns the number of elements in the given `EnumSet`.
- #[unstable(feature = "collections",
- reason = "matches collection reform specification, waiting for dust to settle")]
pub fn len(&self) -> usize {
self.bits.count_ones() as usize
}
/// Returns true if the `EnumSet` is empty.
- #[unstable(feature = "collections",
- reason = "matches collection reform specification, waiting for dust to settle")]
pub fn is_empty(&self) -> bool {
self.bits == 0
}
}
/// Returns `false` if the `EnumSet` contains any enum of the given `EnumSet`.
- #[unstable(feature = "collections",
- reason = "matches collection reform specification, waiting for dust to settle")]
pub fn is_disjoint(&self, other: &EnumSet<E>) -> bool {
(self.bits & other.bits) == 0
}
/// Returns `true` if a given `EnumSet` is included in this `EnumSet`.
- #[unstable(feature = "collections",
- reason = "matches collection reform specification, waiting for dust to settle")]
pub fn is_superset(&self, other: &EnumSet<E>) -> bool {
(self.bits & other.bits) == other.bits
}
/// Returns `true` if this `EnumSet` is included in the given `EnumSet`.
- #[unstable(feature = "collections",
- reason = "matches collection reform specification, waiting for dust to settle")]
pub fn is_subset(&self, other: &EnumSet<E>) -> bool {
other.is_superset(self)
}
}
/// Adds an enum to the `EnumSet`, and returns `true` if it wasn't there before
- #[unstable(feature = "collections",
- reason = "matches collection reform specification, waiting for dust to settle")]
pub fn insert(&mut self, e: E) -> bool {
let result = !self.contains(&e);
self.bits |= bit(&e);
}
/// Removes an enum from the EnumSet
- #[unstable(feature = "collections",
- reason = "matches collection reform specification, waiting for dust to settle")]
pub fn remove(&mut self, e: &E) -> bool {
let result = self.contains(e);
self.bits &= !bit(e);
}
/// Returns `true` if an `EnumSet` contains a given enum.
- #[unstable(feature = "collections",
- reason = "matches collection reform specification, waiting for dust to settle")]
pub fn contains(&self, e: &E) -> bool {
(self.bits & bit(e)) != 0
}
/// Returns an iterator over an `EnumSet`.
- #[unstable(feature = "collections",
- reason = "matches collection reform specification, waiting for dust to settle")]
pub fn iter(&self) -> Iter<E> {
Iter::new(self.bits)
}
}
}
}
+
+#[stable(feature = "extend_ref", since = "1.2.0")]
+impl<'a, E: 'a + CLike + Copy> Extend<&'a E> for EnumSet<E> {
+ fn extend<I: IntoIterator<Item=&'a E>>(&mut self, iter: I) {
+ self.extend(iter.into_iter().cloned());
+ }
+}
//! provides some helper methods.
//!
//! Additionally, the return value of this function is `fmt::Result` which is a
-//! typedef to `Result<(), IoError>` (also known as `IoResult<()>`). Formatting
-//! implementations should ensure that they return errors from `write!`
+//! typedef to `Result<(), std::io::Error>` (also known as `std::io::Result<()>`).
+//! Formatting implementations should ensure that they return errors from `write!`
//! correctly (propagating errors upward).
//!
//! An example of implementing the formatting traits would look
//! like:
//!
//! ```
-//! # #![feature(core, std_misc)]
+//! # #![feature(fmt_flags)]
//! use std::fmt;
-//! use std::f64;
//!
//! #[derive(Debug)]
//! struct Vector2D {
//! * `^` - the argument is center-aligned in `width` columns
//! * `>` - the argument is right-aligned in `width` columns
//!
+//! Note that alignment may not be implemented by some types. A good way
+//! to ensure padding is applied is to format your input, then use this
+//! resulting string to pad your output.
+//!
//! ## Sign/#/0
//!
//! These can all be interpreted as flags for a particular formatter.
//! Collection types.
//!
-//! See [std::collections](../std/collections) for a detailed discussion of collections in Rust.
+//! See [std::collections](../std/collections) for a detailed discussion of
+//! collections in Rust.
// Do not remove on snapshot creation. Needed for bootstrap. (Issue #22364)
#![cfg_attr(stage0, feature(custom_attribute))]
#![crate_name = "collections"]
-#![unstable(feature = "collections")]
#![staged_api]
#![crate_type = "rlib"]
+#![unstable(feature = "collections",
+ reason = "library is unlikely to be stabilized with the current \
+ layout and name, use std::collections instead")]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
- html_favicon_url = "http://www.rust-lang.org/favicon.ico",
+ html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/",
- html_playground_url = "http://play.rust-lang.org/")]
-#![doc(test(no_crate_inject))]
+ html_playground_url = "http://play.rust-lang.org/",
+ test(no_crate_inject))]
#![allow(trivial_casts)]
+#![cfg_attr(test, allow(deprecated))] // rand
+
#![feature(alloc)]
-#![feature(box_syntax)]
#![feature(box_patterns)]
+#![feature(box_raw)]
+#![feature(box_syntax)]
#![feature(core)]
+#![feature(core_intrinsics)]
+#![feature(core_prelude)]
+#![feature(core_slice_ext)]
+#![feature(core_str_ext)]
+#![feature(heap_api)]
+#![feature(iter_cmp)]
+#![feature(iter_idx)]
+#![feature(iter_order)]
+#![feature(iter_arith)]
+#![feature(iter_arith)]
#![feature(lang_items)]
+#![feature(num_bits_bytes)]
+#![feature(oom)]
+#![feature(pattern)]
+#![feature(ptr_as_ref)]
+#![feature(raw)]
+#![feature(slice_patterns)]
#![feature(staged_api)]
+#![feature(step_by)]
+#![feature(str_char)]
+#![feature(str_match_indices)]
#![feature(unboxed_closures)]
#![feature(unicode)]
#![feature(unique)]
#![feature(unsafe_no_drop_flag, filling_drop)]
-#![feature(step_by)]
-#![feature(str_char)]
-#![feature(str_words)]
-#![feature(slice_patterns)]
-#![feature(debug_builders)]
#![feature(utf8_error)]
-#![cfg_attr(test, feature(rand, rustc_private, test, hash, collections,
- collections_drain, collections_range))]
-#![cfg_attr(test, allow(deprecated))] // rand
+#![cfg_attr(test, feature(rand, test))]
+#![cfg_attr(not(test), feature(str_words))]
#![feature(no_std)]
#![no_std]
pub mod vec_deque;
pub mod vec_map;
-#[unstable(feature = "collections",
- reason = "RFC 509")]
+#[unstable(feature = "bitvec", reason = "RFC 509")]
pub mod bit_vec {
pub use bit::{BitVec, Iter};
}
-#[unstable(feature = "collections",
- reason = "RFC 509")]
+#[unstable(feature = "bitset", reason = "RFC 509")]
pub mod bit_set {
pub use bit::{BitSet, Union, Intersection, Difference, SymmetricDifference};
pub use bit::SetIter as Iter;
// FIXME(#14344) this shouldn't be necessary
#[doc(hidden)]
+#[unstable(feature = "issue_14344_fixme")]
pub fn fixme_14344_be_sure_to_link_to_collections() {}
#[cfg(not(test))]
}
/// An endpoint of a range of keys.
+#[unstable(feature = "collections_bound")]
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
pub enum Bound<T> {
/// An inclusive bound.
}
/// Convert the `Rawlink` into an Option value
- fn resolve_immut<'a>(&self) -> Option<&'a T> {
- unsafe {
- mem::transmute(self.p.as_ref())
- }
+ ///
+ /// **unsafe** because:
+ ///
+ /// - Dereference of raw pointer.
+ /// - Returns reference of arbitrary lifetime.
+ unsafe fn resolve<'a>(&self) -> Option<&'a T> {
+ self.p.as_ref()
}
/// Convert the `Rawlink` into an Option value
- fn resolve<'a>(&mut self) -> Option<&'a mut T> {
- if self.p.is_null() {
- None
- } else {
- Some(unsafe { mem::transmute(self.p) })
- }
+ ///
+ /// **unsafe** because:
+ ///
+ /// - Dereference of raw pointer.
+ /// - Returns reference of arbitrary lifetime.
+ unsafe fn resolve_mut<'a>(&mut self) -> Option<&'a mut T> {
+ self.p.as_mut()
}
/// Return the `Rawlink` and replace with `Rawlink::none()`
}
}
+impl<'a, T> From<&'a mut Link<T>> for Rawlink<Node<T>> {
+ fn from(node: &'a mut Link<T>) -> Self {
+ match node.as_mut() {
+ None => Rawlink::none(),
+ Some(ptr) => Rawlink::some(ptr),
+ }
+ }
+}
+
impl<T> Clone for Rawlink<T> {
#[inline]
fn clone(&self) -> Rawlink<T> {
fn new(v: T) -> Node<T> {
Node{value: v, next: None, prev: Rawlink::none()}
}
+
+ /// Update the `prev` link on `next`, then set self's next pointer.
+ ///
+ /// `self.next` should be `None` when you call this
+ /// (otherwise a Node is probably being dropped by mistake).
+ fn set_next(&mut self, mut next: Box<Node<T>>) {
+ debug_assert!(self.next.is_none());
+ next.prev = Rawlink::some(self);
+ self.next = Some(next);
+ }
}
-/// Set the .prev field on `next`, then return `Some(next)`
-fn link_with_prev<T>(mut next: Box<Node<T>>, prev: Rawlink<Node<T>>)
- -> Link<T> {
- next.prev = prev;
+/// Clear the .prev field on `next`, then return `Some(next)`
+fn link_no_prev<T>(mut next: Box<Node<T>>) -> Link<T> {
+ next.prev = Rawlink::none();
Some(next)
}
fn push_front_node(&mut self, mut new_head: Box<Node<T>>) {
match self.list_head {
None => {
- self.list_tail = Rawlink::some(&mut *new_head);
- self.list_head = link_with_prev(new_head, Rawlink::none());
+ self.list_head = link_no_prev(new_head);
+ self.list_tail = Rawlink::from(&mut self.list_head);
}
Some(ref mut head) => {
new_head.prev = Rawlink::none();
self.list_head.take().map(|mut front_node| {
self.length -= 1;
match front_node.next.take() {
- Some(node) => self.list_head = link_with_prev(node, Rawlink::none()),
+ Some(node) => self.list_head = link_no_prev(node),
None => self.list_tail = Rawlink::none()
}
front_node
/// Add a Node last in the list
#[inline]
- fn push_back_node(&mut self, mut new_tail: Box<Node<T>>) {
- match self.list_tail.resolve() {
+ fn push_back_node(&mut self, new_tail: Box<Node<T>>) {
+ match unsafe { self.list_tail.resolve_mut() } {
None => return self.push_front_node(new_tail),
Some(tail) => {
- self.list_tail = Rawlink::some(&mut *new_tail);
- tail.next = link_with_prev(new_tail, Rawlink::some(tail));
+ tail.set_next(new_tail);
+ self.list_tail = Rawlink::from(&mut tail.next);
}
}
self.length += 1;
/// Remove the last Node and return it, or None if the list is empty
#[inline]
fn pop_back_node(&mut self) -> Option<Box<Node<T>>> {
- self.list_tail.resolve().map_or(None, |tail| {
- self.length -= 1;
- self.list_tail = tail.prev;
- match tail.prev.resolve() {
- None => self.list_head.take(),
- Some(tail_prev) => tail_prev.next.take()
- }
- })
+ unsafe {
+ self.list_tail.resolve_mut().and_then(|tail| {
+ self.length -= 1;
+ self.list_tail = tail.prev;
+ match tail.prev.resolve_mut() {
+ None => self.list_head.take(),
+ Some(tail_prev) => tail_prev.next.take()
+ }
+ })
+ }
}
}
/// # Examples
///
/// ```
- /// # #![feature(collections)]
/// use std::collections::LinkedList;
///
/// let mut a = LinkedList::new();
///
/// a.append(&mut b);
///
- /// for e in a.iter() {
+ /// for e in &a {
/// println!("{}", e); // prints 1, then 2, then 3, then 4
/// }
/// println!("{}", b.len()); // prints 0
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn append(&mut self, other: &mut LinkedList<T>) {
- match self.list_tail.resolve() {
+ match unsafe { self.list_tail.resolve_mut() } {
None => {
self.length = other.length;
self.list_head = other.list_head.take();
match other.list_head.take() {
None => return,
Some(node) => {
- tail.next = link_with_prev(node, self.list_tail);
+ tail.set_next(node);
self.list_tail = o_tail;
self.length += o_length;
}
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn iter_mut(&mut self) -> IterMut<T> {
- let head_raw = match self.list_head {
- Some(ref mut h) => Rawlink::some(&mut **h),
- None => Rawlink::none(),
- };
- IterMut{
+ IterMut {
nelem: self.len(),
- head: head_raw,
+ head: Rawlink::from(&mut self.list_head),
tail: self.list_tail,
list: self
}
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn back(&self) -> Option<&T> {
- self.list_tail.resolve_immut().as_ref().map(|tail| &tail.value)
+ unsafe {
+ self.list_tail.resolve().map(|tail| &tail.value)
+ }
}
/// Provides a mutable reference to the back element, or `None` if the list
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn back_mut(&mut self) -> Option<&mut T> {
- self.list_tail.resolve().map(|tail| &mut tail.value)
+ unsafe {
+ self.list_tail.resolve_mut().map(|tail| &mut tail.value)
+ }
}
/// Adds an element first in the list.
/// # Examples
///
/// ```
- /// # #![feature(collections)]
/// use std::collections::LinkedList;
///
/// let mut dl = LinkedList::new();
/// # Examples
///
/// ```
- /// # #![feature(collections)]
/// use std::collections::LinkedList;
///
/// let mut d = LinkedList::new();
/// # Examples
///
/// ```
- /// # #![feature(collections)]
/// use std::collections::LinkedList;
///
/// let mut d = LinkedList::new();
/// # Examples
///
/// ```
- /// # #![feature(collections)]
/// use std::collections::LinkedList;
///
/// let mut d = LinkedList::new();
iter.tail
};
- let mut splitted_list = LinkedList {
- list_head: None,
+ // The split node is the new tail node of the first part and owns
+ // the head of the second part.
+ let mut second_part_head;
+
+ unsafe {
+ second_part_head = split_node.resolve_mut().unwrap().next.take();
+ match second_part_head {
+ None => {}
+ Some(ref mut head) => head.prev = Rawlink::none(),
+ }
+ }
+
+ let second_part = LinkedList {
+ list_head: second_part_head,
list_tail: self.list_tail,
length: len - at
};
- // Swap split_node.next with list_head (which is None), nulling out split_node.next,
- // as it is the new tail.
- mem::swap(&mut split_node.resolve().unwrap().next, &mut splitted_list.list_head);
- // Null out list_head.prev. Note this `unwrap` won't fail because if at == len
- // we already branched out at the top of the fn to return the empty list.
- splitted_list.list_head.as_mut().unwrap().prev = Rawlink::none();
- // Fix the tail ptr
+ // Fix the tail ptr of the first part
self.list_tail = split_node;
self.length = at;
- splitted_list
+ second_part
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Drop for LinkedList<T> {
fn drop(&mut self) {
- // Dissolve the linked_list in backwards direction
+ // Dissolve the linked_list in a loop.
// Just dropping the list_head can lead to stack exhaustion
// when length is >> 1_000_000
- let mut tail = self.list_tail;
- loop {
- match tail.resolve() {
- None => break,
- Some(prev) => {
- prev.next.take(); // release Box<Node<T>>
- tail = prev.prev;
- }
- }
+ while let Some(mut head_) = self.list_head.take() {
+ self.list_head = head_.next.take();
}
self.length = 0;
- self.list_head = None;
self.list_tail = Rawlink::none();
}
}
if self.nelem == 0 {
return None;
}
- self.tail.resolve_immut().as_ref().map(|prev| {
- self.nelem -= 1;
- self.tail = prev.prev;
- &prev.value
- })
+ unsafe {
+ self.tail.resolve().map(|prev| {
+ self.nelem -= 1;
+ self.tail = prev.prev;
+ &prev.value
+ })
+ }
}
}
if self.nelem == 0 {
return None;
}
- self.head.resolve().map(|next| {
- self.nelem -= 1;
- self.head = match next.next {
- Some(ref mut node) => Rawlink::some(&mut **node),
- None => Rawlink::none(),
- };
- &mut next.value
- })
+ unsafe {
+ self.head.resolve_mut().map(|next| {
+ self.nelem -= 1;
+ self.head = Rawlink::from(&mut next.next);
+ &mut next.value
+ })
+ }
}
#[inline]
if self.nelem == 0 {
return None;
}
- self.tail.resolve().map(|prev| {
- self.nelem -= 1;
- self.tail = prev.prev;
- &mut prev.value
- })
+ unsafe {
+ self.tail.resolve_mut().map(|prev| {
+ self.nelem -= 1;
+ self.tail = prev.prev;
+ &mut prev.value
+ })
+ }
}
}
// previously yielded element and self.head.
//
// The inserted node will not appear in further iteration.
- match self.head.resolve() {
+ match unsafe { self.head.resolve_mut() } {
None => { self.list.push_back_node(ins_node); }
Some(node) => {
- let prev_node = match node.prev.resolve() {
+ let prev_node = match unsafe { node.prev.resolve_mut() } {
None => return self.list.push_front_node(ins_node),
Some(prev) => prev,
};
let node_own = prev_node.next.take().unwrap();
- ins_node.next = link_with_prev(node_own, Rawlink::some(&mut *ins_node));
- prev_node.next = link_with_prev(ins_node, Rawlink::some(prev_node));
+ ins_node.set_next(node_own);
+ prev_node.set_next(ins_node);
self.list.length += 1;
}
}
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(linked_list_extras)]
/// use std::collections::LinkedList;
///
/// let mut list: LinkedList<_> = vec![1, 3, 4].into_iter().collect();
/// }
/// ```
#[inline]
- #[unstable(feature = "collections",
+ #[unstable(feature = "linked_list_extras",
reason = "this is probably better handled by a cursor type -- we'll see")]
pub fn insert_next(&mut self, elt: A) {
self.insert_next_node(box Node::new(elt))
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(linked_list_extras)]
/// use std::collections::LinkedList;
///
/// let mut list: LinkedList<_> = vec![1, 2, 3].into_iter().collect();
/// assert_eq!(it.next().unwrap(), &2);
/// ```
#[inline]
- #[unstable(feature = "collections",
+ #[unstable(feature = "linked_list_extras",
reason = "this is probably better handled by a cursor type -- we'll see")]
pub fn peek_next(&mut self) -> Option<&mut A> {
if self.nelem == 0 {
return None
}
- self.head.resolve().map(|head| &mut head.value)
+ unsafe {
+ self.head.resolve_mut().map(|head| &mut head.value)
+ }
}
}
}
}
+#[stable(feature = "extend_ref", since = "1.2.0")]
+impl<'a, T: 'a + Copy> Extend<&'a T> for LinkedList<T> {
+ fn extend<I: IntoIterator<Item=&'a T>>(&mut self, iter: I) {
+ self.extend(iter.into_iter().cloned());
+ }
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<A: PartialEq> PartialEq for LinkedList<A> {
fn eq(&self, other: &LinkedList<A>) -> bool {
#[stable(feature = "rust1", since = "1.0.0")]
impl<A: fmt::Debug> fmt::Debug for LinkedList<A> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- self.iter().fold(f.debug_list(), |b, e| b.entry(e)).finish()
+ f.debug_list().entries(self.iter()).finish()
}
}
#[cfg(test)]
mod tests {
use std::clone::Clone;
- use std::iter::{Iterator, IntoIterator};
+ use std::iter::{Iterator, IntoIterator, Extend};
use std::option::Option::{Some, None, self};
use std::__rand::{thread_rng, Rng};
use std::thread;
Some(ref node) => node_ptr = &**node,
}
loop {
- match (last_ptr, node_ptr.prev.resolve_immut()) {
+ match unsafe { (last_ptr, node_ptr.prev.resolve()) } {
(None , None ) => {}
(None , _ ) => panic!("prev link for list_head"),
(Some(p), Some(pptr)) => {
assert_eq!(v1.iter().collect::<Vec<_>>().len(), 3);
}
+ #[test]
+ fn test_split_off() {
+ let mut v1 = LinkedList::new();
+ v1.push_front(1u8);
+ v1.push_front(1u8);
+ v1.push_front(1u8);
+ v1.push_front(1u8);
+
+ // test all splits
+ for ix in 0..1 + v1.len() {
+ let mut a = v1.clone();
+ let b = a.split_off(ix);
+ check_links(&a);
+ check_links(&b);
+ a.extend(b);
+ assert_eq!(v1, a);
+ }
+ }
+
+
#[cfg(test)]
fn fuzz_test(sz: i32) {
let mut m: LinkedList<_> = LinkedList::new();
check_links(&m);
let mut i = 0;
- for (a, &b) in m.into_iter().zip(v.iter()) {
+ for (a, &b) in m.into_iter().zip(&v) {
i += 1;
assert_eq!(a, b);
}
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+
#![unstable(feature = "collections_range", reason = "was just added")]
//! Range syntax.
//! Utilities for slice manipulation
//!
//! The `slice` module contains useful code to help work with slice values.
-//! Slices are a view into a block of memory represented as a pointer and a length.
+//! Slices are a view into a block of memory represented as a pointer and a
+//! length.
//!
//! ```
//! // slicing a Vec
//! }
//! ```
//!
-//! This iterator yields mutable references to the slice's elements, so while the element
-//! type of the slice is `i32`, the element type of the iterator is `&mut i32`.
+//! This iterator yields mutable references to the slice's elements, so while
+//! the element type of the slice is `i32`, the element type of the iterator is
+//! `&mut i32`.
//!
//! * `.iter()` and `.iter_mut()` are the explicit methods to return the default
//! iterators.
#![doc(primitive = "slice")]
#![stable(feature = "rust1", since = "1.0.0")]
+// Many of the usings in this module are only used in the test configuration.
+// It's cleaner to just turn off the unused_imports warning than to fix them.
+#![allow(unused_imports)]
+
use alloc::boxed::Box;
use core::clone::Clone;
use core::cmp::Ordering::{self, Greater, Less};
}
}
+ #[allow(deprecated)]
pub fn permutations<T>(s: &[T]) -> Permutations<T> where T: Clone {
Permutations{
swaps: ElementSwaps::new(s.len()),
#[cfg(not(test))]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> [T] {
- /// Sorts the slice, in place, using `compare` to compare
- /// elements.
- ///
- /// This sort is `O(n log n)` worst-case and stable, but allocates
- /// approximately `2 * n`, where `n` is the length of `self`.
- ///
- /// # Examples
+ /// Returns the number of elements in the slice.
///
- /// ```rust
- /// let mut v = [5, 4, 1, 3, 2];
- /// v.sort_by(|a, b| a.cmp(b));
- /// assert!(v == [1, 2, 3, 4, 5]);
+ /// # Example
///
- /// // reverse sorting
- /// v.sort_by(|a, b| b.cmp(a));
- /// assert!(v == [5, 4, 3, 2, 1]);
+ /// ```
+ /// let a = [1, 2, 3];
+ /// assert_eq!(a.len(), 3);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn sort_by<F>(&mut self, compare: F) where F: FnMut(&T, &T) -> Ordering {
- merge_sort(self, compare)
+ pub fn len(&self) -> usize {
+ core_slice::SliceExt::len(self)
}
- /// Consumes `src` and moves as many elements as it can into `self`
- /// from the range [start,end).
- ///
- /// Returns the number of elements copied (the shorter of `self.len()`
- /// and `end - start`).
- ///
- /// # Arguments
- ///
- /// * src - A mutable vector of `T`
- /// * start - The index into `src` to start copying from
- /// * end - The index into `src` to stop copying from
+ /// Returns true if the slice has a length of 0
///
- /// # Examples
+ /// # Example
///
- /// ```rust
- /// # #![feature(collections)]
- /// let mut a = [1, 2, 3, 4, 5];
- /// let b = vec![6, 7, 8];
- /// let num_moved = a.move_from(b, 0, 3);
- /// assert_eq!(num_moved, 3);
- /// assert!(a == [6, 7, 8, 4, 5]);
/// ```
- #[unstable(feature = "collections",
- reason = "uncertain about this API approach")]
+ /// let a = [1, 2, 3];
+ /// assert!(!a.is_empty());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn move_from(&mut self, mut src: Vec<T>, start: usize, end: usize) -> usize {
- for (a, b) in self.iter_mut().zip(src[start .. end].iter_mut()) {
- mem::swap(a, b);
- }
- cmp::min(self.len(), end-start)
+ pub fn is_empty(&self) -> bool {
+ core_slice::SliceExt::is_empty(self)
}
- /// Divides one slice into two at an index.
- ///
- /// The first will contain all indices from `[0, mid)` (excluding
- /// the index `mid` itself) and the second will contain all
- /// indices from `[mid, len)` (excluding the index `len` itself).
- ///
- /// Panics if `mid > len`.
+ /// Returns the first element of a slice, or `None` if it is empty.
///
/// # Examples
///
/// ```
- /// let v = [10, 40, 30, 20, 50];
- /// let (v1, v2) = v.split_at(2);
- /// assert_eq!([10, 40], v1);
- /// assert_eq!([30, 20, 50], v2);
+ /// let v = [10, 40, 30];
+ /// assert_eq!(Some(&10), v.first());
+ ///
+ /// let w: &[i32] = &[];
+ /// assert_eq!(None, w.first());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn split_at(&self, mid: usize) -> (&[T], &[T]) {
- core_slice::SliceExt::split_at(self, mid)
+ pub fn first(&self) -> Option<&T> {
+ core_slice::SliceExt::first(self)
}
- /// Returns an iterator over the slice.
+ /// Returns a mutable pointer to the first element of a slice, or `None` if it is empty
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn iter(&self) -> Iter<T> {
- core_slice::SliceExt::iter(self)
+ pub fn first_mut(&mut self) -> Option<&mut T> {
+ core_slice::SliceExt::first_mut(self)
}
- /// Returns an iterator over subslices separated by elements that match
- /// `pred`. The matched element is not contained in the subslices.
- ///
- /// # Examples
- ///
- /// Print the slice split by numbers divisible by 3 (i.e. `[10, 40]`,
- /// `[20]`, `[50]`):
- ///
- /// ```
- /// let v = [10, 40, 30, 20, 60, 50];
- /// for group in v.split(|num| *num % 3 == 0) {
- /// println!("{:?}", group);
- /// }
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
+ /// Returns all but the first element of a slice.
+ #[unstable(feature = "slice_extras", reason = "likely to be renamed")]
#[inline]
- pub fn split<F>(&self, pred: F) -> Split<T, F> where F: FnMut(&T) -> bool {
- core_slice::SliceExt::split(self, pred)
+ pub fn tail(&self) -> &[T] {
+ core_slice::SliceExt::tail(self)
}
- /// Returns an iterator over subslices separated by elements that match
- /// `pred`, limited to returning at most `n` items. The matched element is
- /// not contained in the subslices.
- ///
- /// The last element returned, if any, will contain the remainder of the
- /// slice.
- ///
- /// # Examples
- ///
- /// Print the slice split once by numbers divisible by 3 (i.e. `[10, 40]`,
- /// `[20, 60, 50]`):
- ///
- /// ```
- /// let v = [10, 40, 30, 20, 60, 50];
- /// for group in v.splitn(2, |num| *num % 3 == 0) {
- /// println!("{:?}", group);
- /// }
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
+ /// Returns all but the first element of a mutable slice
+ #[unstable(feature = "slice_extras",
+ reason = "likely to be renamed or removed")]
#[inline]
- pub fn splitn<F>(&self, n: usize, pred: F) -> SplitN<T, F> where F: FnMut(&T) -> bool {
- core_slice::SliceExt::splitn(self, n, pred)
+ pub fn tail_mut(&mut self) -> &mut [T] {
+ core_slice::SliceExt::tail_mut(self)
}
- /// Returns an iterator over subslices separated by elements that match
- /// `pred` limited to returning at most `n` items. This starts at the end of
- /// the slice and works backwards. The matched element is not contained in
- /// the subslices.
- ///
- /// The last element returned, if any, will contain the remainder of the
- /// slice.
- ///
- /// # Examples
- ///
- /// Print the slice split once, starting from the end, by numbers divisible
- /// by 3 (i.e. `[50]`, `[10, 40, 30, 20]`):
- ///
- /// ```
- /// let v = [10, 40, 30, 20, 60, 50];
- /// for group in v.rsplitn(2, |num| *num % 3 == 0) {
- /// println!("{:?}", group);
- /// }
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
+ /// Returns all but the last element of a slice.
+ #[unstable(feature = "slice_extras", reason = "likely to be renamed")]
#[inline]
- pub fn rsplitn<F>(&self, n: usize, pred: F) -> RSplitN<T, F> where F: FnMut(&T) -> bool {
- core_slice::SliceExt::rsplitn(self, n, pred)
+ pub fn init(&self) -> &[T] {
+ core_slice::SliceExt::init(self)
}
- /// Returns an iterator over all contiguous windows of length
- /// `size`. The windows overlap. If the slice is shorter than
- /// `size`, the iterator returns no values.
- ///
- /// # Panics
- ///
- /// Panics if `size` is 0.
+ /// Returns all but the last element of a mutable slice
+ #[unstable(feature = "slice_extras",
+ reason = "likely to be renamed or removed")]
+ #[inline]
+ pub fn init_mut(&mut self) -> &mut [T] {
+ core_slice::SliceExt::init_mut(self)
+ }
+
+ /// Returns the last element of a slice, or `None` if it is empty.
///
- /// # Example
+ /// # Examples
///
- /// Print the adjacent pairs of a slice (i.e. `[1,2]`, `[2,3]`,
- /// `[3,4]`):
+ /// ```
+ /// let v = [10, 40, 30];
+ /// assert_eq!(Some(&30), v.last());
///
- /// ```rust
- /// let v = &[1, 2, 3, 4];
- /// for win in v.windows(2) {
- /// println!("{:?}", win);
- /// }
+ /// let w: &[i32] = &[];
+ /// assert_eq!(None, w.last());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn windows(&self, size: usize) -> Windows<T> {
- core_slice::SliceExt::windows(self, size)
+ pub fn last(&self) -> Option<&T> {
+ core_slice::SliceExt::last(self)
}
- /// Returns an iterator over `size` elements of the slice at a
- /// time. The chunks do not overlap. If `size` does not divide the
- /// length of the slice, then the last chunk will not have length
- /// `size`.
- ///
- /// # Panics
- ///
- /// Panics if `size` is 0.
- ///
- /// # Example
- ///
- /// Print the slice two elements at a time (i.e. `[1,2]`,
- /// `[3,4]`, `[5]`):
- ///
- /// ```rust
- /// let v = &[1, 2, 3, 4, 5];
- /// for win in v.chunks(2) {
- /// println!("{:?}", win);
- /// }
- /// ```
+ /// Returns a mutable pointer to the last item in the slice.
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn chunks(&self, size: usize) -> Chunks<T> {
- core_slice::SliceExt::chunks(self, size)
+ pub fn last_mut(&mut self) -> Option<&mut T> {
+ core_slice::SliceExt::last_mut(self)
}
/// Returns the element of a slice at the given index, or `None` if the
core_slice::SliceExt::get(self, index)
}
- /// Returns the first element of a slice, or `None` if it is empty.
- ///
- /// # Examples
- ///
- /// ```
- /// let v = [10, 40, 30];
- /// assert_eq!(Some(&10), v.first());
- ///
- /// let w: &[i32] = &[];
- /// assert_eq!(None, w.first());
- /// ```
+ /// Returns a mutable reference to the element at the given index,
+ /// or `None` if the index is out of bounds
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn first(&self) -> Option<&T> {
- core_slice::SliceExt::first(self)
+ pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
+ core_slice::SliceExt::get_mut(self, index)
}
- /// Returns all but the first element of a slice.
- #[unstable(feature = "collections", reason = "likely to be renamed")]
+ /// Returns a pointer to the element at the given index, without doing
+ /// bounds checking.
+ #[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn tail(&self) -> &[T] {
- core_slice::SliceExt::tail(self)
+ pub unsafe fn get_unchecked(&self, index: usize) -> &T {
+ core_slice::SliceExt::get_unchecked(self, index)
}
- /// Returns all but the last element of a slice.
- #[unstable(feature = "collections", reason = "likely to be renamed")]
+ /// Returns an unsafe mutable pointer to the element in index
+ #[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn init(&self) -> &[T] {
- core_slice::SliceExt::init(self)
+ pub unsafe fn get_unchecked_mut(&mut self, index: usize) -> &mut T {
+ core_slice::SliceExt::get_unchecked_mut(self, index)
}
- /// Returns the last element of a slice, or `None` if it is empty.
- ///
- /// # Examples
+ /// Returns an raw pointer to the slice's buffer
///
- /// ```
- /// let v = [10, 40, 30];
- /// assert_eq!(Some(&30), v.last());
+ /// The caller must ensure that the slice outlives the pointer this
+ /// function returns, or else it will end up pointing to garbage.
///
- /// let w: &[i32] = &[];
- /// assert_eq!(None, w.last());
- /// ```
+ /// Modifying the slice may cause its buffer to be reallocated, which
+ /// would also make any pointers to it invalid.
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn last(&self) -> Option<&T> {
- core_slice::SliceExt::last(self)
- }
-
- /// Returns a pointer to the element at the given index, without doing
- /// bounds checking.
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub unsafe fn get_unchecked(&self, index: usize) -> &T {
- core_slice::SliceExt::get_unchecked(self, index)
+ pub fn as_ptr(&self) -> *const T {
+ core_slice::SliceExt::as_ptr(self)
}
- /// Returns an unsafe pointer to the slice's buffer
+ /// Returns an unsafe mutable pointer to the slice's buffer.
///
/// The caller must ensure that the slice outlives the pointer this
/// function returns, or else it will end up pointing to garbage.
/// would also make any pointers to it invalid.
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn as_ptr(&self) -> *const T {
- core_slice::SliceExt::as_ptr(self)
+ pub fn as_mut_ptr(&mut self) -> *mut T {
+ core_slice::SliceExt::as_mut_ptr(self)
}
- /// Binary search a sorted slice with a comparator function.
- ///
- /// The comparator function should implement an order consistent
- /// with the sort order of the underlying slice, returning an
- /// order code that indicates whether its argument is `Less`,
- /// `Equal` or `Greater` the desired target.
- ///
- /// If a matching value is found then returns `Ok`, containing
- /// the index for the matched element; if no match is found then
- /// `Err` is returned, containing the index where a matching
- /// element could be inserted while maintaining sorted order.
+ /// Swaps two elements in a slice.
///
- /// # Example
+ /// # Arguments
///
- /// Looks up a series of four elements. The first is found, with a
- /// uniquely determined position; the second and third are not
- /// found; the fourth could match any position in `[1,4]`.
+ /// * a - The index of the first element
+ /// * b - The index of the second element
///
- /// ```rust
- /// # #![feature(core)]
- /// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
+ /// # Panics
///
- /// let seek = 13;
- /// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Ok(9));
- /// let seek = 4;
- /// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Err(7));
- /// let seek = 100;
- /// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Err(13));
- /// let seek = 1;
- /// let r = s.binary_search_by(|probe| probe.cmp(&seek));
- /// assert!(match r { Ok(1...4) => true, _ => false, });
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn binary_search_by<F>(&self, f: F) -> Result<usize, usize> where F: FnMut(&T) -> Ordering {
- core_slice::SliceExt::binary_search_by(self, f)
- }
-
- /// Returns the number of elements in the slice.
+ /// Panics if `a` or `b` are out of bounds.
///
/// # Example
///
- /// ```
- /// let a = [1, 2, 3];
- /// assert_eq!(a.len(), 3);
+ /// ```rust
+ /// let mut v = ["a", "b", "c", "d"];
+ /// v.swap(1, 3);
+ /// assert!(v == ["a", "d", "c", "b"]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn len(&self) -> usize {
- core_slice::SliceExt::len(self)
+ pub fn swap(&mut self, a: usize, b: usize) {
+ core_slice::SliceExt::swap(self, a, b)
}
- /// Returns true if the slice has a length of 0
+ /// Reverse the order of elements in a slice, in place.
///
/// # Example
///
- /// ```
- /// let a = [1, 2, 3];
- /// assert!(!a.is_empty());
+ /// ```rust
+ /// let mut v = [1, 2, 3];
+ /// v.reverse();
+ /// assert!(v == [3, 2, 1]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn is_empty(&self) -> bool {
- core_slice::SliceExt::is_empty(self)
+ pub fn reverse(&mut self) {
+ core_slice::SliceExt::reverse(self)
}
- /// Returns a mutable reference to the element at the given index,
- /// or `None` if the index is out of bounds
+ /// Returns an iterator over the slice.
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
- core_slice::SliceExt::get_mut(self, index)
+ pub fn iter(&self) -> Iter<T> {
+ core_slice::SliceExt::iter(self)
}
/// Returns an iterator that allows modifying each value
core_slice::SliceExt::iter_mut(self)
}
- /// Returns a mutable pointer to the first element of a slice, or `None` if it is empty
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn first_mut(&mut self) -> Option<&mut T> {
- core_slice::SliceExt::first_mut(self)
- }
-
- /// Returns all but the first element of a mutable slice
- #[unstable(feature = "collections",
- reason = "likely to be renamed or removed")]
- #[inline]
- pub fn tail_mut(&mut self) -> &mut [T] {
- core_slice::SliceExt::tail_mut(self)
- }
-
- /// Returns all but the last element of a mutable slice
- #[unstable(feature = "collections",
- reason = "likely to be renamed or removed")]
- #[inline]
- pub fn init_mut(&mut self) -> &mut [T] {
- core_slice::SliceExt::init_mut(self)
- }
-
- /// Returns a mutable pointer to the last item in the slice.
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn last_mut(&mut self) -> Option<&mut T> {
- core_slice::SliceExt::last_mut(self)
- }
-
- /// Returns an iterator over mutable subslices separated by elements that
- /// match `pred`. The matched element is not contained in the subslices.
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn split_mut<F>(&mut self, pred: F) -> SplitMut<T, F> where F: FnMut(&T) -> bool {
- core_slice::SliceExt::split_mut(self, pred)
- }
-
- /// Returns an iterator over subslices separated by elements that match
- /// `pred`, limited to returning at most `n` items. The matched element is
- /// not contained in the subslices.
+ /// Returns an iterator over all contiguous windows of length
+ /// `size`. The windows overlap. If the slice is shorter than
+ /// `size`, the iterator returns no values.
///
- /// The last element returned, if any, will contain the remainder of the
- /// slice.
+ /// # Panics
+ ///
+ /// Panics if `size` is 0.
+ ///
+ /// # Example
+ ///
+ /// Print the adjacent pairs of a slice (i.e. `[1,2]`, `[2,3]`,
+ /// `[3,4]`):
+ ///
+ /// ```rust
+ /// let v = &[1, 2, 3, 4];
+ /// for win in v.windows(2) {
+ /// println!("{:?}", win);
+ /// }
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn splitn_mut<F>(&mut self, n: usize, pred: F) -> SplitNMut<T, F>
- where F: FnMut(&T) -> bool {
- core_slice::SliceExt::splitn_mut(self, n, pred)
+ pub fn windows(&self, size: usize) -> Windows<T> {
+ core_slice::SliceExt::windows(self, size)
}
- /// Returns an iterator over subslices separated by elements that match
- /// `pred` limited to returning at most `n` items. This starts at the end of
- /// the slice and works backwards. The matched element is not contained in
- /// the subslices.
+ /// Returns an iterator over `size` elements of the slice at a
+ /// time. The chunks do not overlap. If `size` does not divide the
+ /// length of the slice, then the last chunk will not have length
+ /// `size`.
///
- /// The last element returned, if any, will contain the remainder of the
- /// slice.
+ /// # Panics
+ ///
+ /// Panics if `size` is 0.
+ ///
+ /// # Example
+ ///
+ /// Print the slice two elements at a time (i.e. `[1,2]`,
+ /// `[3,4]`, `[5]`):
+ ///
+ /// ```rust
+ /// let v = &[1, 2, 3, 4, 5];
+ /// for win in v.chunks(2) {
+ /// println!("{:?}", win);
+ /// }
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn rsplitn_mut<F>(&mut self, n: usize, pred: F) -> RSplitNMut<T, F>
- where F: FnMut(&T) -> bool {
- core_slice::SliceExt::rsplitn_mut(self, n, pred)
+ pub fn chunks(&self, size: usize) -> Chunks<T> {
+ core_slice::SliceExt::chunks(self, size)
}
/// Returns an iterator over `chunk_size` elements of the slice at a time.
core_slice::SliceExt::chunks_mut(self, chunk_size)
}
- /// Swaps two elements in a slice.
- ///
- /// # Arguments
- ///
- /// * a - The index of the first element
- /// * b - The index of the second element
+ /// Divides one slice into two at an index.
///
- /// # Panics
+ /// The first will contain all indices from `[0, mid)` (excluding
+ /// the index `mid` itself) and the second will contain all
+ /// indices from `[mid, len)` (excluding the index `len` itself).
///
- /// Panics if `a` or `b` are out of bounds.
+ /// Panics if `mid > len`.
///
- /// # Example
+ /// # Examples
///
- /// ```rust
- /// let mut v = ["a", "b", "c", "d"];
- /// v.swap(1, 3);
- /// assert!(v == ["a", "d", "c", "b"]);
+ /// ```
+ /// let v = [10, 40, 30, 20, 50];
+ /// let (v1, v2) = v.split_at(2);
+ /// assert_eq!([10, 40], v1);
+ /// assert_eq!([30, 20, 50], v2);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn swap(&mut self, a: usize, b: usize) {
- core_slice::SliceExt::swap(self, a, b)
+ pub fn split_at(&self, mid: usize) -> (&[T], &[T]) {
+ core_slice::SliceExt::split_at(self, mid)
}
/// Divides one `&mut` into two at an index.
core_slice::SliceExt::split_at_mut(self, mid)
}
- /// Reverse the order of elements in a slice, in place.
+ /// Returns an iterator over subslices separated by elements that match
+ /// `pred`. The matched element is not contained in the subslices.
///
- /// # Example
+ /// # Examples
///
- /// ```rust
- /// let mut v = [1, 2, 3];
- /// v.reverse();
- /// assert!(v == [3, 2, 1]);
+ /// Print the slice split by numbers divisible by 3 (i.e. `[10, 40]`,
+ /// `[20]`, `[50]`):
+ ///
+ /// ```
+ /// let v = [10, 40, 30, 20, 60, 50];
+ /// for group in v.split(|num| *num % 3 == 0) {
+ /// println!("{:?}", group);
+ /// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn reverse(&mut self) {
- core_slice::SliceExt::reverse(self)
+ pub fn split<F>(&self, pred: F) -> Split<T, F> where F: FnMut(&T) -> bool {
+ core_slice::SliceExt::split(self, pred)
}
- /// Returns an unsafe mutable pointer to the element in index
+ /// Returns an iterator over mutable subslices separated by elements that
+ /// match `pred`. The matched element is not contained in the subslices.
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub unsafe fn get_unchecked_mut(&mut self, index: usize) -> &mut T {
- core_slice::SliceExt::get_unchecked_mut(self, index)
+ pub fn split_mut<F>(&mut self, pred: F) -> SplitMut<T, F> where F: FnMut(&T) -> bool {
+ core_slice::SliceExt::split_mut(self, pred)
}
- /// Returns an unsafe mutable pointer to the slice's buffer.
+ /// Returns an iterator over subslices separated by elements that match
+ /// `pred`, limited to returning at most `n` items. The matched element is
+ /// not contained in the subslices.
///
- /// The caller must ensure that the slice outlives the pointer this
- /// function returns, or else it will end up pointing to garbage.
- ///
- /// Modifying the slice may cause its buffer to be reallocated, which
- /// would also make any pointers to it invalid.
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn as_mut_ptr(&mut self) -> *mut T {
- core_slice::SliceExt::as_mut_ptr(self)
- }
-
- /// Copies `self` into a new `Vec`.
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn to_vec(&self) -> Vec<T> where T: Clone {
- // NB see hack module in this file
- hack::to_vec(self)
- }
-
- /// Creates an iterator that yields every possible permutation of the
- /// vector in succession.
+ /// The last element returned, if any, will contain the remainder of the
+ /// slice.
///
/// # Examples
///
- /// ```rust
- /// # #![feature(collections)]
- /// let v = [1, 2, 3];
- /// let mut perms = v.permutations();
+ /// Print the slice split once by numbers divisible by 3 (i.e. `[10, 40]`,
+ /// `[20, 60, 50]`):
///
- /// for p in perms {
- /// println!("{:?}", p);
+ /// ```
+ /// let v = [10, 40, 30, 20, 60, 50];
+ /// for group in v.splitn(2, |num| *num % 3 == 0) {
+ /// println!("{:?}", group);
/// }
/// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn splitn<F>(&self, n: usize, pred: F) -> SplitN<T, F> where F: FnMut(&T) -> bool {
+ core_slice::SliceExt::splitn(self, n, pred)
+ }
+
+ /// Returns an iterator over subslices separated by elements that match
+ /// `pred`, limited to returning at most `n` items. The matched element is
+ /// not contained in the subslices.
///
- /// Iterating through permutations one by one.
+ /// The last element returned, if any, will contain the remainder of the
+ /// slice.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn splitn_mut<F>(&mut self, n: usize, pred: F) -> SplitNMut<T, F>
+ where F: FnMut(&T) -> bool {
+ core_slice::SliceExt::splitn_mut(self, n, pred)
+ }
+
+ /// Returns an iterator over subslices separated by elements that match
+ /// `pred` limited to returning at most `n` items. This starts at the end of
+ /// the slice and works backwards. The matched element is not contained in
+ /// the subslices.
///
- /// ```rust
- /// # #![feature(collections)]
- /// let v = [1, 2, 3];
- /// let mut perms = v.permutations();
+ /// The last element returned, if any, will contain the remainder of the
+ /// slice.
///
- /// assert_eq!(Some(vec![1, 2, 3]), perms.next());
- /// assert_eq!(Some(vec![1, 3, 2]), perms.next());
- /// assert_eq!(Some(vec![3, 1, 2]), perms.next());
+ /// # Examples
+ ///
+ /// Print the slice split once, starting from the end, by numbers divisible
+ /// by 3 (i.e. `[50]`, `[10, 40, 30, 20]`):
+ ///
+ /// ```
+ /// let v = [10, 40, 30, 20, 60, 50];
+ /// for group in v.rsplitn(2, |num| *num % 3 == 0) {
+ /// println!("{:?}", group);
+ /// }
/// ```
- #[unstable(feature = "collections")]
+ #[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn permutations(&self) -> Permutations<T> where T: Clone {
- // NB see hack module in this file
- hack::permutations(self)
+ pub fn rsplitn<F>(&self, n: usize, pred: F) -> RSplitN<T, F> where F: FnMut(&T) -> bool {
+ core_slice::SliceExt::rsplitn(self, n, pred)
}
- /// Copies as many elements from `src` as it can into `self` (the
- /// shorter of `self.len()` and `src.len()`). Returns the number
- /// of elements copied.
- ///
- /// # Example
+ /// Returns an iterator over subslices separated by elements that match
+ /// `pred` limited to returning at most `n` items. This starts at the end of
+ /// the slice and works backwards. The matched element is not contained in
+ /// the subslices.
///
- /// ```rust
- /// # #![feature(collections)]
- /// let mut dst = [0, 0, 0];
- /// let src = [1, 2];
+ /// The last element returned, if any, will contain the remainder of the
+ /// slice.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn rsplitn_mut<F>(&mut self, n: usize, pred: F) -> RSplitNMut<T, F>
+ where F: FnMut(&T) -> bool {
+ core_slice::SliceExt::rsplitn_mut(self, n, pred)
+ }
+
+ /// Returns true if the slice contains an element with the given value.
///
- /// assert!(dst.clone_from_slice(&src) == 2);
- /// assert!(dst == [1, 2, 0]);
+ /// # Examples
///
- /// let src2 = [3, 4, 5, 6];
- /// assert!(dst.clone_from_slice(&src2) == 3);
- /// assert!(dst == [3, 4, 5]);
/// ```
- #[unstable(feature = "collections")]
- pub fn clone_from_slice(&mut self, src: &[T]) -> usize where T: Clone {
- core_slice::SliceExt::clone_from_slice(self, src)
+ /// let v = [10, 40, 30];
+ /// assert!(v.contains(&30));
+ /// assert!(!v.contains(&50));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn contains(&self, x: &T) -> bool where T: PartialEq {
+ core_slice::SliceExt::contains(self, x)
}
- /// Sorts the slice, in place.
- ///
- /// This is equivalent to `self.sort_by(|a, b| a.cmp(b))`.
+ /// Returns true if `needle` is a prefix of the slice.
///
/// # Examples
///
- /// ```rust
- /// let mut v = [-5, 4, 1, -3, 2];
+ /// ```
+ /// let v = [10, 40, 30];
+ /// assert!(v.starts_with(&[10]));
+ /// assert!(v.starts_with(&[10, 40]));
+ /// assert!(!v.starts_with(&[50]));
+ /// assert!(!v.starts_with(&[10, 50]));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn starts_with(&self, needle: &[T]) -> bool where T: PartialEq {
+ core_slice::SliceExt::starts_with(self, needle)
+ }
+
+ /// Returns true if `needle` is a suffix of the slice.
+ ///
+ /// # Examples
///
- /// v.sort();
- /// assert!(v == [-5, -3, 1, 2, 4]);
+ /// ```
+ /// let v = [10, 40, 30];
+ /// assert!(v.ends_with(&[30]));
+ /// assert!(v.ends_with(&[40, 30]));
+ /// assert!(!v.ends_with(&[50]));
+ /// assert!(!v.ends_with(&[50, 30]));
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn sort(&mut self) where T: Ord {
- self.sort_by(|a, b| a.cmp(b))
+ pub fn ends_with(&self, needle: &[T]) -> bool where T: PartialEq {
+ core_slice::SliceExt::ends_with(self, needle)
+ }
+
+ /// Find the first index containing a matching value.
+ #[unstable(feature = "slice_position_elem")]
+ pub fn position_elem(&self, t: &T) -> Option<usize> where T: PartialEq {
+ core_slice::SliceExt::position_elem(self, t)
+ }
+
+ /// Find the last index containing a matching value.
+ #[unstable(feature = "slice_position_elem")]
+ pub fn rposition_elem(&self, t: &T) -> Option<usize> where T: PartialEq {
+ core_slice::SliceExt::rposition_elem(self, t)
}
/// Binary search a sorted slice for a given element.
/// found; the fourth could match any position in `[1,4]`.
///
/// ```rust
- /// # #![feature(core)]
/// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
///
/// assert_eq!(s.binary_search(&13), Ok(9));
core_slice::SliceExt::binary_search(self, x)
}
+ /// Binary search a sorted slice with a comparator function.
+ ///
+ /// The comparator function should implement an order consistent
+ /// with the sort order of the underlying slice, returning an
+ /// order code that indicates whether its argument is `Less`,
+ /// `Equal` or `Greater` the desired target.
+ ///
+ /// If a matching value is found then returns `Ok`, containing
+ /// the index for the matched element; if no match is found then
+ /// `Err` is returned, containing the index where a matching
+ /// element could be inserted while maintaining sorted order.
+ ///
+ /// # Example
+ ///
+ /// Looks up a series of four elements. The first is found, with a
+ /// uniquely determined position; the second and third are not
+ /// found; the fourth could match any position in `[1,4]`.
+ ///
+ /// ```rust
+ /// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
+ ///
+ /// let seek = 13;
+ /// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Ok(9));
+ /// let seek = 4;
+ /// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Err(7));
+ /// let seek = 100;
+ /// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Err(13));
+ /// let seek = 1;
+ /// let r = s.binary_search_by(|probe| probe.cmp(&seek));
+ /// assert!(match r { Ok(1...4) => true, _ => false, });
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn binary_search_by<F>(&self, f: F) -> Result<usize, usize> where F: FnMut(&T) -> Ordering {
+ core_slice::SliceExt::binary_search_by(self, f)
+ }
+
+ /// Sorts the slice, in place.
+ ///
+ /// This is equivalent to `self.sort_by(|a, b| a.cmp(b))`.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// let mut v = [-5, 4, 1, -3, 2];
+ ///
+ /// v.sort();
+ /// assert!(v == [-5, -3, 1, 2, 4]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn sort(&mut self) where T: Ord {
+ self.sort_by(|a, b| a.cmp(b))
+ }
+
+ /// Sorts the slice, in place, using `compare` to compare
+ /// elements.
+ ///
+ /// This sort is `O(n log n)` worst-case and stable, but allocates
+ /// approximately `2 * n`, where `n` is the length of `self`.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// let mut v = [5, 4, 1, 3, 2];
+ /// v.sort_by(|a, b| a.cmp(b));
+ /// assert!(v == [1, 2, 3, 4, 5]);
+ ///
+ /// // reverse sorting
+ /// v.sort_by(|a, b| b.cmp(a));
+ /// assert!(v == [5, 4, 3, 2, 1]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn sort_by<F>(&mut self, compare: F) where F: FnMut(&T, &T) -> Ordering {
+ merge_sort(self, compare)
+ }
+
+ /// Creates an iterator that yields every possible permutation of the
+ /// vector in succession.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # #![feature(permutations)]
+ /// let v = [1, 2, 3];
+ /// let mut perms = v.permutations();
+ ///
+ /// for p in perms {
+ /// println!("{:?}", p);
+ /// }
+ /// ```
+ ///
+ /// Iterating through permutations one by one.
+ ///
+ /// ```rust
+ /// # #![feature(permutations)]
+ /// let v = [1, 2, 3];
+ /// let mut perms = v.permutations();
+ ///
+ /// assert_eq!(Some(vec![1, 2, 3]), perms.next());
+ /// assert_eq!(Some(vec![1, 3, 2]), perms.next());
+ /// assert_eq!(Some(vec![3, 1, 2]), perms.next());
+ /// ```
+ #[allow(deprecated)]
+ #[unstable(feature = "permutations")]
+ #[deprecated(since = "1.2.0", reason = "not clear this should be in the stdlib")]
+ #[inline]
+ pub fn permutations(&self) -> Permutations<T> where T: Clone {
+ // NB see hack module in this file
+ hack::permutations(self)
+ }
+
/// Mutates the slice to the next lexicographic permutation.
///
/// Returns `true` if successful and `false` if the slice is at the
/// # Example
///
/// ```rust
- /// # #![feature(collections)]
+ /// # #![feature(permutations)]
/// let v: &mut [_] = &mut [0, 1, 2];
/// v.next_permutation();
/// let b: &mut [_] = &mut [0, 2, 1];
/// let b: &mut [_] = &mut [1, 0, 2];
/// assert!(v == b);
/// ```
- #[unstable(feature = "collections",
+ #[allow(deprecated)]
+ #[unstable(feature = "permutations",
reason = "uncertain if this merits inclusion in std")]
+ #[deprecated(since = "1.2.0", reason = "not clear this should be in the stdlib")]
pub fn next_permutation(&mut self) -> bool where T: Ord {
core_slice::SliceExt::next_permutation(self)
}
/// # Example
///
/// ```rust
- /// # #![feature(collections)]
+ /// # #![feature(permutations)]
/// let v: &mut [_] = &mut [1, 0, 2];
/// v.prev_permutation();
/// let b: &mut [_] = &mut [0, 2, 1];
/// let b: &mut [_] = &mut [0, 1, 2];
/// assert!(v == b);
/// ```
- #[unstable(feature = "collections",
+ #[allow(deprecated)]
+ #[unstable(feature = "permutations",
reason = "uncertain if this merits inclusion in std")]
+ #[deprecated(since = "1.2.0", reason = "not clear this should be in the stdlib")]
pub fn prev_permutation(&mut self) -> bool where T: Ord {
core_slice::SliceExt::prev_permutation(self)
}
- /// Find the first index containing a matching value.
- #[unstable(feature = "collections")]
- pub fn position_elem(&self, t: &T) -> Option<usize> where T: PartialEq {
- core_slice::SliceExt::position_elem(self, t)
- }
-
- /// Find the last index containing a matching value.
- #[unstable(feature = "collections")]
- pub fn rposition_elem(&self, t: &T) -> Option<usize> where T: PartialEq {
- core_slice::SliceExt::rposition_elem(self, t)
- }
-
- /// Returns true if the slice contains an element with the given value.
+ /// Copies as many elements from `src` as it can into `self` (the
+ /// shorter of `self.len()` and `src.len()`). Returns the number
+ /// of elements copied.
///
- /// # Examples
+ /// # Example
///
- /// ```
- /// let v = [10, 40, 30];
- /// assert!(v.contains(&30));
- /// assert!(!v.contains(&50));
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn contains(&self, x: &T) -> bool where T: PartialEq {
- core_slice::SliceExt::contains(self, x)
- }
-
- /// Returns true if `needle` is a prefix of the slice.
+ /// ```rust
+ /// # #![feature(clone_from_slice)]
+ /// let mut dst = [0, 0, 0];
+ /// let src = [1, 2];
///
- /// # Examples
+ /// assert!(dst.clone_from_slice(&src) == 2);
+ /// assert!(dst == [1, 2, 0]);
///
+ /// let src2 = [3, 4, 5, 6];
+ /// assert!(dst.clone_from_slice(&src2) == 3);
+ /// assert!(dst == [3, 4, 5]);
/// ```
- /// let v = [10, 40, 30];
- /// assert!(v.starts_with(&[10]));
- /// assert!(v.starts_with(&[10, 40]));
- /// assert!(!v.starts_with(&[50]));
- /// assert!(!v.starts_with(&[10, 50]));
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn starts_with(&self, needle: &[T]) -> bool where T: PartialEq {
- core_slice::SliceExt::starts_with(self, needle)
+ #[unstable(feature = "clone_from_slice")]
+ pub fn clone_from_slice(&mut self, src: &[T]) -> usize where T: Clone {
+ core_slice::SliceExt::clone_from_slice(self, src)
}
- /// Returns true if `needle` is a suffix of the slice.
+ /// Consumes `src` and moves as many elements as it can into `self`
+ /// from the range [start,end).
+ ///
+ /// Returns the number of elements copied (the shorter of `self.len()`
+ /// and `end - start`).
+ ///
+ /// # Arguments
+ ///
+ /// * src - A mutable vector of `T`
+ /// * start - The index into `src` to start copying from
+ /// * end - The index into `src` to stop copying from
///
/// # Examples
///
+ /// ```rust
+ /// # #![feature(move_from)]
+ /// let mut a = [1, 2, 3, 4, 5];
+ /// let b = vec![6, 7, 8];
+ /// let num_moved = a.move_from(b, 0, 3);
+ /// assert_eq!(num_moved, 3);
+ /// assert!(a == [6, 7, 8, 4, 5]);
/// ```
- /// let v = [10, 40, 30];
- /// assert!(v.ends_with(&[30]));
- /// assert!(v.ends_with(&[40, 30]));
- /// assert!(!v.ends_with(&[50]));
- /// assert!(!v.ends_with(&[50, 30]));
- /// ```
+ #[unstable(feature = "move_from",
+ reason = "uncertain about this API approach")]
+ #[inline]
+ pub fn move_from(&mut self, mut src: Vec<T>, start: usize, end: usize) -> usize {
+ for (a, b) in self.iter_mut().zip(&mut src[start .. end]) {
+ mem::swap(a, b);
+ }
+ cmp::min(self.len(), end-start)
+ }
+
+ /// Copies `self` into a new `Vec`.
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn ends_with(&self, needle: &[T]) -> bool where T: PartialEq {
- core_slice::SliceExt::ends_with(self, needle)
+ #[inline]
+ pub fn to_vec(&self) -> Vec<T> where T: Clone {
+ // NB see hack module in this file
+ hack::to_vec(self)
}
/// Converts `self` into a vector without clones or allocation.
////////////////////////////////////////////////////////////////////////////////
// Extension traits for slices over specific kinds of data
////////////////////////////////////////////////////////////////////////////////
-#[unstable(feature = "collections", reason = "recently changed")]
+#[unstable(feature = "slice_concat_ext",
+ reason = "trait should not have to exist")]
/// An extension trait for concatenating slices
pub trait SliceConcatExt<T: ?Sized> {
- #[unstable(feature = "collections", reason = "recently changed")]
+ #[unstable(feature = "slice_concat_ext",
+ reason = "trait should not have to exist")]
/// The resulting type after concatenation
type Output;
#[stable(feature = "rust1", since = "1.0.0")]
fn concat(&self) -> Self::Output;
- /// Flattens a slice of `T` into a single value `Self::Output`, placing a given separator
- /// between each.
+ /// Flattens a slice of `T` into a single value `Self::Output`, placing a
+ /// given separator between each.
///
/// # Examples
///
///
/// The last generated swap is always (0, 1), and it returns the
/// sequence to its initial order.
-#[unstable(feature = "collections")]
+#[allow(deprecated)]
+#[unstable(feature = "permutations")]
#[derive(Clone)]
+#[deprecated(since = "1.2.0", reason = "not clear this should be in the stdlib")]
pub struct ElementSwaps {
sdir: Vec<SizeDirection>,
/// If `true`, emit the last swap that returns the sequence to initial
swaps_made : usize,
}
+#[allow(deprecated)]
impl ElementSwaps {
/// Creates an `ElementSwaps` iterator for a sequence of `length` elements.
- #[unstable(feature = "collections")]
+ #[unstable(feature = "permutations")]
+ #[deprecated(since = "1.2.0", reason = "not clear this should be in the stdlib")]
pub fn new(length: usize) -> ElementSwaps {
// Initialize `sdir` with a direction that position should move in
// (all negative at the beginning) and the `size` of the
}
#[stable(feature = "rust1", since = "1.0.0")]
+#[allow(deprecated)]
impl Iterator for ElementSwaps {
type Item = (usize, usize);
/// swap applied.
///
/// Generates even and odd permutations alternately.
-#[unstable(feature = "collections")]
+#[unstable(feature = "permutations")]
+#[deprecated(since = "1.2.0", reason = "not clear this should be in the stdlib")]
+#[allow(deprecated)]
pub struct Permutations<T> {
swaps: ElementSwaps,
v: Vec<T>,
}
-#[unstable(feature = "collections", reason = "trait is unstable")]
+#[unstable(feature = "permutations", reason = "trait is unstable")]
+#[allow(deprecated)]
impl<T: Clone> Iterator for Permutations<T> {
type Item = Vec<T>;
//! You can get a non-`'static` `&str` by taking a slice of a `String`:
//!
//! ```
-//! # let some_string = "Hello, world.".to_string();
+//! let some_string = "Hello, world.".to_string();
//! let s = &some_string;
//! ```
//!
#![doc(primitive = "str")]
#![stable(feature = "rust1", since = "1.0.0")]
+// Many of the usings in this module are only used in the test configuration.
+// It's cleaner to just turn off the unused_imports warning than to fix them.
+#![allow(unused_imports)]
+
use self::RecompositionState::*;
use self::DecompositionType::*;
///
/// For use with the `std::iter` module.
#[derive(Clone)]
-#[unstable(feature = "collections")]
+#[unstable(feature = "str_utf16")]
pub struct Utf16Units<'a> {
encoder: Utf16Encoder<Chars<'a>>
}
#[cfg(not(test))]
#[stable(feature = "rust1", since = "1.0.0")]
impl str {
- /// Escapes each char in `s` with `char::escape_default`.
- #[unstable(feature = "collections",
- reason = "return type may change to be an iterator")]
- pub fn escape_default(&self) -> String {
- self.chars().flat_map(|c| c.escape_default()).collect()
- }
-
- /// Escapes each char in `s` with `char::escape_unicode`.
- #[unstable(feature = "collections",
- reason = "return type may change to be an iterator")]
- pub fn escape_unicode(&self) -> String {
- self.chars().flat_map(|c| c.escape_unicode()).collect()
- }
-
- /// Replaces all occurrences of one string with another.
- ///
- /// `replace` takes two arguments, a sub-`&str` to find in `self`, and a
- /// second `&str` to
- /// replace it with. If the original `&str` isn't found, no change occurs.
+ /// Returns the length of `self` in bytes.
///
/// # Examples
///
/// ```
- /// let s = "this is old";
- ///
- /// assert_eq!(s.replace("old", "new"), "this is new");
- /// ```
- ///
- /// When a `&str` isn't found:
- ///
- /// ```
- /// let s = "this is old";
- /// assert_eq!(s.replace("cookie monster", "little lamb"), s);
+ /// assert_eq!("foo".len(), 3);
+ /// assert_eq!("ƒoo".len(), 4); // fancy f!
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn replace(&self, from: &str, to: &str) -> String {
- let mut result = String::new();
- let mut last_end = 0;
- for (start, end) in self.match_indices(from) {
- result.push_str(unsafe { self.slice_unchecked(last_end, start) });
- result.push_str(to);
- last_end = end;
- }
- result.push_str(unsafe { self.slice_unchecked(last_end, self.len()) });
- result
- }
-
- /// Returns an iterator over the string in Unicode Normalization Form D
- /// (canonical decomposition).
- #[allow(deprecated)]
- #[deprecated(reason = "use the crates.io `unicode-normalization` library instead",
- since = "1.0.0")]
- #[inline]
- #[unstable(feature = "unicode",
- reason = "this functionality may be replaced with a more generic \
- unicode crate on crates.io")]
- pub fn nfd_chars(&self) -> Decompositions {
- Decompositions {
- iter: self[..].chars(),
- buffer: Vec::new(),
- sorted: false,
- kind: Canonical
- }
- }
-
- /// Returns an iterator over the string in Unicode Normalization Form KD
- /// (compatibility decomposition).
- #[allow(deprecated)]
- #[deprecated(reason = "use the crates.io `unicode-normalization` library instead",
- since = "1.0.0")]
#[inline]
- #[unstable(feature = "unicode",
- reason = "this functionality may be replaced with a more generic \
- unicode crate on crates.io")]
- pub fn nfkd_chars(&self) -> Decompositions {
- Decompositions {
- iter: self[..].chars(),
- buffer: Vec::new(),
- sorted: false,
- kind: Compatible
- }
+ pub fn len(&self) -> usize {
+ core_str::StrExt::len(self)
}
- /// An Iterator over the string in Unicode Normalization Form C
- /// (canonical decomposition followed by canonical composition).
- #[allow(deprecated)]
- #[deprecated(reason = "use the crates.io `unicode-normalization` library instead",
- since = "1.0.0")]
+ /// Returns true if this slice has a length of zero bytes.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// assert!("".is_empty());
+ /// ```
#[inline]
- #[unstable(feature = "unicode",
- reason = "this functionality may be replaced with a more generic \
- unicode crate on crates.io")]
- pub fn nfc_chars(&self) -> Recompositions {
- Recompositions {
- iter: self.nfd_chars(),
- state: Composing,
- buffer: VecDeque::new(),
- composee: None,
- last_ccc: None
- }
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn is_empty(&self) -> bool {
+ core_str::StrExt::is_empty(self)
}
- /// An Iterator over the string in Unicode Normalization Form KC
- /// (compatibility decomposition followed by canonical composition).
- #[allow(deprecated)]
- #[deprecated(reason = "use the crates.io `unicode-normalization` library instead",
- since = "1.0.0")]
- #[inline]
+ /// Returns a string's displayed width in columns.
+ ///
+ /// Control characters have zero width.
+ ///
+ /// `is_cjk` determines behavior for characters in the Ambiguous category:
+ /// if `is_cjk` is
+ /// `true`, these are 2 columns wide; otherwise, they are 1.
+ /// In CJK locales, `is_cjk` should be
+ /// `true`, else it should be `false`.
+ /// [Unicode Standard Annex #11](http://www.unicode.org/reports/tr11/)
+ /// recommends that these
+ /// characters be treated as 1 column (i.e., `is_cjk = false`) if the
+ /// locale is unknown.
+ #[deprecated(reason = "use the crates.io `unicode-width` library instead",
+ since = "1.0.0")]
#[unstable(feature = "unicode",
- reason = "this functionality may be replaced with a more generic \
- unicode crate on crates.io")]
- pub fn nfkc_chars(&self) -> Recompositions {
- Recompositions {
- iter: self.nfkd_chars(),
- state: Composing,
- buffer: VecDeque::new(),
- composee: None,
- last_ccc: None
- }
+ reason = "this functionality may only be provided by libunicode")]
+ pub fn width(&self, is_cjk: bool) -> usize {
+ UnicodeStr::width(self, is_cjk)
}
- /// Returns `true` if `self` contains another `&str`.
+ /// Checks that `index`-th byte lies at the start and/or end of a
+ /// UTF-8 code point sequence.
+ ///
+ /// The start and end of the string (when `index == self.len()`) are
+ /// considered to be
+ /// boundaries.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `index` is greater than `self.len()`.
///
/// # Examples
///
/// ```
- /// assert!("bananas".contains("nana"));
+ /// # #![feature(str_char)]
+ /// let s = "Löwe 老虎 Léopard";
+ /// assert!(s.is_char_boundary(0));
+ /// // start of `老`
+ /// assert!(s.is_char_boundary(6));
+ /// assert!(s.is_char_boundary(s.len()));
///
- /// assert!(!"bananas".contains("foobar"));
+ /// // second byte of `ö`
+ /// assert!(!s.is_char_boundary(2));
+ ///
+ /// // third byte of `老`
+ /// assert!(!s.is_char_boundary(8));
/// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn contains<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool {
- core_str::StrExt::contains(&self[..], pat)
+ #[unstable(feature = "str_char",
+ reason = "it is unclear whether this method pulls its weight \
+ with the existence of the char_indices iterator or \
+ this method may want to be replaced with checked \
+ slicing")]
+ pub fn is_char_boundary(&self, index: usize) -> bool {
+ core_str::StrExt::is_char_boundary(self, index)
}
- /// An iterator over the codepoints of `self`.
+ /// Converts `self` to a byte slice.
///
/// # Examples
///
/// ```
- /// let v: Vec<char> = "abc åäö".chars().collect();
- ///
- /// assert_eq!(v, ['a', 'b', 'c', ' ', 'å', 'ä', 'ö']);
+ /// assert_eq!("bors".as_bytes(), b"bors");
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn chars(&self) -> Chars {
- core_str::StrExt::chars(&self[..])
+ #[inline(always)]
+ pub fn as_bytes(&self) -> &[u8] {
+ core_str::StrExt::as_bytes(self)
}
- /// An iterator over the bytes of `self`.
+ /// Returns a raw pointer to the `&str`'s buffer.
+ ///
+ /// The caller must ensure that the string outlives this pointer, and
+ /// that it is not
+ /// reallocated (e.g. by pushing to the string).
///
/// # Examples
///
/// ```
- /// let v: Vec<u8> = "bors".bytes().collect();
- ///
- /// assert_eq!(v, b"bors".to_vec());
+ /// let s = "Hello";
+ /// let p = s.as_ptr();
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn bytes(&self) -> Bytes {
- core_str::StrExt::bytes(&self[..])
+ #[inline]
+ pub fn as_ptr(&self) -> *const u8 {
+ core_str::StrExt::as_ptr(self)
}
- /// An iterator over the characters of `self` and their byte offsets.
+ /// Takes a bytewise slice from a string.
+ ///
+ /// Returns the substring from [`begin`..`end`).
+ ///
+ /// # Unsafety
+ ///
+ /// Caller must check both UTF-8 character boundaries and the boundaries
+ /// of the entire slice as
+ /// well.
///
/// # Examples
///
/// ```
- /// let v: Vec<(usize, char)> = "abc".char_indices().collect();
- /// let b = vec![(0, 'a'), (1, 'b'), (2, 'c')];
+ /// let s = "Löwe 老虎 Léopard";
///
- /// assert_eq!(v, b);
+ /// unsafe {
+ /// assert_eq!(s.slice_unchecked(0, 21), "Löwe 老虎 Léopard");
+ /// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn char_indices(&self) -> CharIndices {
- core_str::StrExt::char_indices(&self[..])
+ pub unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str {
+ core_str::StrExt::slice_unchecked(self, begin, end)
}
- /// An iterator over substrings of `self`, separated by characters
- /// matched by a pattern.
+ /// Returns a slice of the string from the character range [`begin`..`end`).
///
- /// The pattern can be a simple `&str`, `char`, or a closure that
- /// determines the split.
- /// Additional libraries might provide more complex patterns like
- /// regular expressions.
+ /// That is, start at the `begin`-th code point of the string and continue
+ /// to the `end`-th code point. This does not detect or handle edge cases
+ /// such as leaving a combining character as the first code point of the
+ /// string.
///
- /// # Iterator behavior
+ /// Due to the design of UTF-8, this operation is `O(end)`. Use slicing
+ /// syntax if you want to use byte indices rather than codepoint indices.
///
- /// The returned iterator will be double ended if the pattern allows a
- /// reverse search and forward/reverse search yields the same elements.
- /// This is true for, eg, `char` but not
- /// for `&str`.
+ /// # Panics
///
- /// If the pattern allows a reverse search but its results might differ
- /// from a forward search, `rsplit()` can be used.
+ /// Panics if `begin` > `end` or the either `begin` or `end` are beyond the
+ /// last character of the string.
///
/// # Examples
///
- /// Simple patterns:
- ///
/// ```
- /// let v: Vec<&str> = "Mary had a little lamb".split(' ').collect();
- /// assert_eq!(v, ["Mary", "had", "a", "little", "lamb"]);
+ /// # #![feature(slice_chars)]
+ /// let s = "Löwe 老虎 Léopard";
///
- /// let v: Vec<&str> = "".split('X').collect();
- /// assert_eq!(v, [""]);
+ /// assert_eq!(s.slice_chars(0, 4), "Löwe");
+ /// assert_eq!(s.slice_chars(5, 7), "老虎");
+ /// ```
+ #[unstable(feature = "slice_chars",
+ reason = "may have yet to prove its worth")]
+ pub fn slice_chars(&self, begin: usize, end: usize) -> &str {
+ core_str::StrExt::slice_chars(self, begin, end)
+ }
+
+ /// Given a byte position, return the next char and its index.
///
- /// let v: Vec<&str> = "lionXXtigerXleopard".split('X').collect();
- /// assert_eq!(v, ["lion", "", "tiger", "leopard"]);
+ /// This can be used to iterate over the Unicode characters of a string.
///
- /// let v: Vec<&str> = "lion::tiger::leopard".split("::").collect();
- /// assert_eq!(v, ["lion", "tiger", "leopard"]);
- /// ```
+ /// # Panics
///
- /// More complex patterns with closures:
+ /// If `i` is greater than or equal to the length of the string.
+ /// If `i` is not the index of the beginning of a valid UTF-8 character.
///
- /// ```
- /// let v: Vec<&str> = "abc1def2ghi".split(|c: char| c.is_numeric()).collect();
- /// assert_eq!(v, ["abc", "def", "ghi"]);
+ /// # Examples
///
- /// let v: Vec<&str> = "lionXtigerXleopard".split(char::is_uppercase).collect();
- /// assert_eq!(v, ["lion", "tiger", "leopard"]);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P> {
- core_str::StrExt::split(&self[..], pat)
- }
-
- /// An iterator over substrings of `self`, separated by characters
- /// matched by a pattern and yielded in reverse order.
- ///
- /// The pattern can be a simple `&str`, `char`, or a closure that
- /// determines the split.
- /// Additional libraries might provide more complex patterns like
- /// regular expressions.
- ///
- /// # Iterator behavior
- ///
- /// The returned iterator requires that the pattern supports a
- /// reverse search,
- /// and it will be double ended if a forward/reverse search yields
- /// the same elements.
- ///
- /// For iterating from the front, `split()` can be used.
- ///
- /// # Examples
- ///
- /// Simple patterns:
- ///
- /// ```rust
- /// let v: Vec<&str> = "Mary had a little lamb".rsplit(' ').collect();
- /// assert_eq!(v, ["lamb", "little", "a", "had", "Mary"]);
- ///
- /// let v: Vec<&str> = "".rsplit('X').collect();
- /// assert_eq!(v, [""]);
- ///
- /// let v: Vec<&str> = "lionXXtigerXleopard".rsplit('X').collect();
- /// assert_eq!(v, ["leopard", "tiger", "", "lion"]);
+ /// This example manually iterates through the characters of a string;
+ /// this should normally be
+ /// done by `.chars()` or `.char_indices()`.
///
- /// let v: Vec<&str> = "lion::tiger::leopard".rsplit("::").collect();
- /// assert_eq!(v, ["leopard", "tiger", "lion"]);
/// ```
+ /// # #![feature(str_char, core)]
+ /// use std::str::CharRange;
///
- /// More complex patterns with closures:
+ /// let s = "中华Việt Nam";
+ /// let mut i = 0;
+ /// while i < s.len() {
+ /// let CharRange {ch, next} = s.char_range_at(i);
+ /// println!("{}: {}", i, ch);
+ /// i = next;
+ /// }
+ /// ```
///
- /// ```rust
- /// let v: Vec<&str> = "abc1def2ghi".rsplit(|c: char| c.is_numeric()).collect();
- /// assert_eq!(v, ["ghi", "def", "abc"]);
+ /// This outputs:
///
- /// let v: Vec<&str> = "lionXtigerXleopard".rsplit(char::is_uppercase).collect();
- /// assert_eq!(v, ["leopard", "tiger", "lion"]);
+ /// ```text
+ /// 0: 中
+ /// 3: 华
+ /// 6: V
+ /// 7: i
+ /// 8: ệ
+ /// 11: t
+ /// 12:
+ /// 13: N
+ /// 14: a
+ /// 15: m
/// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn rsplit<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplit<'a, P>
- where P::Searcher: ReverseSearcher<'a>
- {
- core_str::StrExt::rsplit(&self[..], pat)
+ #[unstable(feature = "str_char",
+ reason = "often replaced by char_indices, this method may \
+ be removed in favor of just char_at() or eventually \
+ removed altogether")]
+ pub fn char_range_at(&self, start: usize) -> CharRange {
+ core_str::StrExt::char_range_at(self, start)
}
- /// An iterator over substrings of `self`, separated by characters
- /// matched by a pattern.
- ///
- /// The pattern can be a simple `&str`, `char`, or a closure that
- /// determines the split.
- /// Additional libraries might provide more complex patterns
- /// like regular expressions.
- ///
- /// Equivalent to `split`, except that the trailing substring
- /// is skipped if empty.
+ /// Given a byte position, return the previous `char` and its position.
///
- /// This method can be used for string data that is _terminated_,
- /// rather than _separated_ by a pattern.
+ /// This function can be used to iterate over a Unicode string in reverse.
///
- /// # Iterator behavior
+ /// Returns 0 for next index if called on start index 0.
///
- /// The returned iterator will be double ended if the pattern allows a
- /// reverse search
- /// and forward/reverse search yields the same elements. This is true
- /// for, eg, `char` but not for `&str`.
+ /// # Panics
///
- /// If the pattern allows a reverse search but its results might differ
- /// from a forward search, `rsplit_terminator()` can be used.
+ /// If `i` is greater than the length of the string.
+ /// If `i` is not an index following a valid UTF-8 character.
///
/// # Examples
///
- /// Simple patterns:
+ /// This example manually iterates through the characters of a string;
+ /// this should normally be
+ /// done by `.chars().rev()` or `.char_indices()`.
///
/// ```
- /// let v: Vec<&str> = "A.B.".split_terminator('.').collect();
- /// assert_eq!(v, ["A", "B"]);
+ /// # #![feature(str_char, core)]
+ /// use std::str::CharRange;
///
- /// let v: Vec<&str> = "A..B..".split_terminator(".").collect();
- /// assert_eq!(v, ["A", "", "B", ""]);
+ /// let s = "中华Việt Nam";
+ /// let mut i = s.len();
+ /// while i > 0 {
+ /// let CharRange {ch, next} = s.char_range_at_reverse(i);
+ /// println!("{}: {}", i, ch);
+ /// i = next;
+ /// }
/// ```
///
- /// More complex patterns with closures:
+ /// This outputs:
///
+ /// ```text
+ /// 16: m
+ /// 15: a
+ /// 14: N
+ /// 13:
+ /// 12: t
+ /// 11: ệ
+ /// 8: i
+ /// 7: V
+ /// 6: 华
+ /// 3: 中
/// ```
- /// let v: Vec<&str> = "abc1def2ghi3".split_terminator(|c: char| c.is_numeric()).collect();
- /// assert_eq!(v, ["abc", "def", "ghi"]);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P> {
- core_str::StrExt::split_terminator(&self[..], pat)
+ #[unstable(feature = "str_char",
+ reason = "often replaced by char_indices, this method may \
+ be removed in favor of just char_at_reverse() or \
+ eventually removed altogether")]
+ pub fn char_range_at_reverse(&self, start: usize) -> CharRange {
+ core_str::StrExt::char_range_at_reverse(self, start)
}
- /// An iterator over substrings of `self`, separated by characters
- /// matched by a pattern and yielded in reverse order.
- ///
- /// The pattern can be a simple `&str`, `char`, or a closure that
- /// determines the split.
- /// Additional libraries might provide more complex patterns like
- /// regular expressions.
- ///
- /// Equivalent to `split`, except that the trailing substring is
- /// skipped if empty.
- ///
- /// This method can be used for string data that is _terminated_,
- /// rather than _separated_ by a pattern.
- ///
- /// # Iterator behavior
+ /// Given a byte position, return the `char` at that position.
///
- /// The returned iterator requires that the pattern supports a
- /// reverse search, and it will be double ended if a forward/reverse
- /// search yields the same elements.
+ /// # Panics
///
- /// For iterating from the front, `split_terminator()` can be used.
+ /// If `i` is greater than or equal to the length of the string.
+ /// If `i` is not the index of the beginning of a valid UTF-8 character.
///
/// # Examples
///
- /// Simple patterns:
- ///
- /// ```
- /// let v: Vec<&str> = "A.B.".rsplit_terminator('.').collect();
- /// assert_eq!(v, ["B", "A"]);
- ///
- /// let v: Vec<&str> = "A..B..".rsplit_terminator(".").collect();
- /// assert_eq!(v, ["", "B", "", "A"]);
/// ```
- ///
- /// More complex patterns with closures:
- ///
- /// ```
- /// let v: Vec<&str> = "abc1def2ghi3".rsplit_terminator(|c: char| c.is_numeric()).collect();
- /// assert_eq!(v, ["ghi", "def", "abc"]);
+ /// # #![feature(str_char)]
+ /// let s = "abπc";
+ /// assert_eq!(s.char_at(1), 'b');
+ /// assert_eq!(s.char_at(2), 'π');
/// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn rsplit_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplitTerminator<'a, P>
- where P::Searcher: ReverseSearcher<'a>
- {
- core_str::StrExt::rsplit_terminator(&self[..], pat)
+ #[unstable(feature = "str_char",
+ reason = "frequently replaced by the chars() iterator, this \
+ method may be removed or possibly renamed in the \
+ future; it is normally replaced by chars/char_indices \
+ iterators or by getting the first char from a \
+ subslice")]
+ pub fn char_at(&self, i: usize) -> char {
+ core_str::StrExt::char_at(self, i)
}
- /// An iterator over substrings of `self`, separated by a pattern,
- /// restricted to returning
- /// at most `count` items.
- ///
- /// The last element returned, if any, will contain the remainder of the
- /// string.
- /// The pattern can be a simple `&str`, `char`, or a closure that
- /// determines the split.
- /// Additional libraries might provide more complex patterns like
- /// regular expressions.
- ///
- /// # Iterator behavior
+ /// Given a byte position, return the `char` at that position, counting
+ /// from the end.
///
- /// The returned iterator will not be double ended, because it is
- /// not efficient to support.
+ /// # Panics
///
- /// If the pattern allows a reverse search, `rsplitn()` can be used.
+ /// If `i` is greater than the length of the string.
+ /// If `i` is not an index following a valid UTF-8 character.
///
/// # Examples
///
- /// Simple patterns:
- ///
- /// ```
- /// let v: Vec<&str> = "Mary had a little lambda".splitn(3, ' ').collect();
- /// assert_eq!(v, ["Mary", "had", "a little lambda"]);
- ///
- /// let v: Vec<&str> = "lionXXtigerXleopard".splitn(3, "X").collect();
- /// assert_eq!(v, ["lion", "", "tigerXleopard"]);
- ///
- /// let v: Vec<&str> = "abcXdef".splitn(1, 'X').collect();
- /// assert_eq!(v, ["abcXdef"]);
- ///
- /// let v: Vec<&str> = "".splitn(1, 'X').collect();
- /// assert_eq!(v, [""]);
- /// ```
- ///
- /// More complex patterns with closures:
- ///
/// ```
- /// let v: Vec<&str> = "abc1def2ghi".splitn(2, |c: char| c.is_numeric()).collect();
- /// assert_eq!(v, ["abc", "def2ghi"]);
+ /// # #![feature(str_char)]
+ /// let s = "abπc";
+ /// assert_eq!(s.char_at_reverse(1), 'a');
+ /// assert_eq!(s.char_at_reverse(2), 'b');
/// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn splitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> SplitN<'a, P> {
- core_str::StrExt::splitn(&self[..], count, pat)
+ #[unstable(feature = "str_char",
+ reason = "see char_at for more details, but reverse semantics \
+ are also somewhat unclear, especially with which \
+ cases generate panics")]
+ pub fn char_at_reverse(&self, i: usize) -> char {
+ core_str::StrExt::char_at_reverse(self, i)
}
- /// An iterator over substrings of `self`, separated by a pattern,
- /// starting from the end of the string, restricted to returning
- /// at most `count` items.
- ///
- /// The last element returned, if any, will contain the remainder of the
- /// string.
- ///
- /// The pattern can be a simple `&str`, `char`, or a closure that
- /// determines the split.
- /// Additional libraries might provide more complex patterns like
- /// regular expressions.
- ///
- /// # Iterator behavior
+ /// Retrieves the first character from a `&str` and returns it.
///
- /// The returned iterator will not be double ended, because it is not
- /// efficient to support.
+ /// This does not allocate a new string; instead, it returns a slice that
+ /// points one character
+ /// beyond the character that was shifted.
///
- /// `splitn()` can be used for splitting from the front.
+ /// If the slice does not contain any characters, None is returned instead.
///
/// # Examples
///
- /// Simple patterns:
- ///
/// ```
- /// let v: Vec<&str> = "Mary had a little lamb".rsplitn(3, ' ').collect();
- /// assert_eq!(v, ["lamb", "little", "Mary had a"]);
- ///
- /// let v: Vec<&str> = "lionXXtigerXleopard".rsplitn(3, 'X').collect();
- /// assert_eq!(v, ["leopard", "tiger", "lionX"]);
+ /// # #![feature(str_char)]
+ /// let s = "Löwe 老虎 Léopard";
+ /// let (c, s1) = s.slice_shift_char().unwrap();
///
- /// let v: Vec<&str> = "lion::tiger::leopard".rsplitn(2, "::").collect();
- /// assert_eq!(v, ["leopard", "lion::tiger"]);
- /// ```
+ /// assert_eq!(c, 'L');
+ /// assert_eq!(s1, "öwe 老虎 Léopard");
///
- /// More complex patterns with closures:
+ /// let (c, s2) = s1.slice_shift_char().unwrap();
///
+ /// assert_eq!(c, 'ö');
+ /// assert_eq!(s2, "we 老虎 Léopard");
/// ```
- /// let v: Vec<&str> = "abc1def2ghi".rsplitn(2, |c: char| c.is_numeric()).collect();
- /// assert_eq!(v, ["ghi", "abc1def"]);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn rsplitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> RSplitN<'a, P>
- where P::Searcher: ReverseSearcher<'a>
- {
- core_str::StrExt::rsplitn(&self[..], count, pat)
+ #[unstable(feature = "str_char",
+ reason = "awaiting conventions about shifting and slices and \
+ may not be warranted with the existence of the chars \
+ and/or char_indices iterators")]
+ pub fn slice_shift_char(&self) -> Option<(char, &str)> {
+ core_str::StrExt::slice_shift_char(self)
}
- /// An iterator over the matches of a pattern within `self`.
+ /// Divide one string slice into two at an index.
///
- /// The pattern can be a simple `&str`, `char`, or a closure that
- /// determines the split.
- /// Additional libraries might provide more complex patterns like
- /// regular expressions.
+ /// The index `mid` is a byte offset from the start of the string
+ /// that must be on a character boundary.
///
- /// # Iterator behavior
+ /// Return slices `&self[..mid]` and `&self[mid..]`.
///
- /// The returned iterator will be double ended if the pattern allows
- /// a reverse search
- /// and forward/reverse search yields the same elements. This is true
- /// for, eg, `char` but not
- /// for `&str`.
+ /// # Panics
///
- /// If the pattern allows a reverse search but its results might differ
- /// from a forward search, `rmatches()` can be used.
+ /// Panics if `mid` is beyond the last character of the string,
+ /// or if it is not on a character boundary.
///
/// # Examples
- ///
/// ```
/// # #![feature(collections)]
- /// let v: Vec<&str> = "abcXXXabcYYYabc".matches("abc").collect();
- /// assert_eq!(v, ["abc", "abc", "abc"]);
+ /// let s = "Löwe 老虎 Léopard";
+ /// let first_space = s.find(' ').unwrap_or(s.len());
+ /// let (a, b) = s.split_at(first_space);
///
- /// let v: Vec<&str> = "1abc2abc3".matches(|c: char| c.is_numeric()).collect();
- /// assert_eq!(v, ["1", "2", "3"]);
+ /// assert_eq!(a, "Löwe");
+ /// assert_eq!(b, " 老虎 Léopard");
/// ```
- #[unstable(feature = "collections",
- reason = "method got recently added")]
- pub fn matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> Matches<'a, P> {
- core_str::StrExt::matches(&self[..], pat)
+ #[inline]
+ pub fn split_at(&self, mid: usize) -> (&str, &str) {
+ core_str::StrExt::split_at(self, mid)
}
- /// An iterator over the matches of a pattern within `self`, yielded in
- /// reverse order.
- ///
- /// The pattern can be a simple `&str`, `char`, or a closure that
- /// determines the split.
- /// Additional libraries might provide more complex patterns like
- /// regular expressions.
- ///
- /// # Iterator behavior
- ///
- /// The returned iterator requires that the pattern supports a
- /// reverse search,
- /// and it will be double ended if a forward/reverse search yields
- /// the same elements.
- ///
- /// For iterating from the front, `matches()` can be used.
+ /// An iterator over the codepoints of `self`.
///
/// # Examples
///
/// ```
- /// # #![feature(collections)]
- /// let v: Vec<&str> = "abcXXXabcYYYabc".rmatches("abc").collect();
- /// assert_eq!(v, ["abc", "abc", "abc"]);
+ /// let v: Vec<char> = "abc åäö".chars().collect();
///
- /// let v: Vec<&str> = "1abc2abc3".rmatches(|c: char| c.is_numeric()).collect();
- /// assert_eq!(v, ["3", "2", "1"]);
+ /// assert_eq!(v, ['a', 'b', 'c', ' ', 'å', 'ä', 'ö']);
/// ```
- #[unstable(feature = "collections",
- reason = "method got recently added")]
- pub fn rmatches<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatches<'a, P>
- where P::Searcher: ReverseSearcher<'a>
- {
- core_str::StrExt::rmatches(&self[..], pat)
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn chars(&self) -> Chars {
+ core_str::StrExt::chars(self)
}
- /// An iterator over the start and end indices of the disjoint matches
- /// of a pattern within `self`.
- ///
- /// For matches of `pat` within `self` that overlap, only the indices
- /// corresponding to the first
- /// match are returned.
- ///
- /// The pattern can be a simple `&str`, `char`, or a closure that
- /// determines
- /// the split.
- /// Additional libraries might provide more complex patterns like
- /// regular expressions.
- ///
- /// # Iterator behavior
- ///
- /// The returned iterator will be double ended if the pattern allows a
- /// reverse search
- /// and forward/reverse search yields the same elements. This is true for,
- /// eg, `char` but not
- /// for `&str`.
- ///
- /// If the pattern allows a reverse search but its results might differ
- /// from a forward search, `rmatch_indices()` can be used.
+ /// An iterator over the characters of `self` and their byte offsets.
///
/// # Examples
///
/// ```
- /// # #![feature(collections)]
- /// let v: Vec<(usize, usize)> = "abcXXXabcYYYabc".match_indices("abc").collect();
- /// assert_eq!(v, [(0, 3), (6, 9), (12, 15)]);
- ///
- /// let v: Vec<(usize, usize)> = "1abcabc2".match_indices("abc").collect();
- /// assert_eq!(v, [(1, 4), (4, 7)]);
+ /// let v: Vec<(usize, char)> = "abc".char_indices().collect();
+ /// let b = vec![(0, 'a'), (1, 'b'), (2, 'c')];
///
- /// let v: Vec<(usize, usize)> = "ababa".match_indices("aba").collect();
- /// assert_eq!(v, [(0, 3)]); // only the first `aba`
+ /// assert_eq!(v, b);
/// ```
- #[unstable(feature = "collections",
- reason = "might have its iterator type changed")]
- // NB: Right now MatchIndices yields `(usize, usize)`, but it would
- // be more consistent with `matches` and `char_indices` to return `(usize, &str)`
- pub fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P> {
- core_str::StrExt::match_indices(&self[..], pat)
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn char_indices(&self) -> CharIndices {
+ core_str::StrExt::char_indices(self)
}
- /// An iterator over the start and end indices of the disjoint matches of
- /// a pattern within
- /// `self`, yielded in reverse order.
- ///
- /// For matches of `pat` within `self` that overlap, only the indices
- /// corresponding to the last
- /// match are returned.
- ///
- /// The pattern can be a simple `&str`, `char`, or a closure that
- /// determines
- /// the split.
- /// Additional libraries might provide more complex patterns like
- /// regular expressions.
+ /// An iterator over the bytes of `self`.
///
- /// # Iterator behavior
+ /// # Examples
///
- /// The returned iterator requires that the pattern supports a
- /// reverse search,
- /// and it will be double ended if a forward/reverse search yields
- /// the same elements.
+ /// ```
+ /// let v: Vec<u8> = "bors".bytes().collect();
///
- /// For iterating from the front, `match_indices()` can be used.
+ /// assert_eq!(v, b"bors".to_vec());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn bytes(&self) -> Bytes {
+ core_str::StrExt::bytes(self)
+ }
+
+ /// An iterator over the non-empty substrings of `self` which contain no whitespace,
+ /// and which are separated by any amount of whitespace.
///
/// # Examples
///
/// ```
- /// # #![feature(collections)]
- /// let v: Vec<(usize, usize)> = "abcXXXabcYYYabc".rmatch_indices("abc").collect();
- /// assert_eq!(v, [(12, 15), (6, 9), (0, 3)]);
+ /// let some_words = " Mary had\ta little \n\t lamb";
+ /// let v: Vec<&str> = some_words.split_whitespace().collect();
///
- /// let v: Vec<(usize, usize)> = "1abcabc2".rmatch_indices("abc").collect();
- /// assert_eq!(v, [(4, 7), (1, 4)]);
+ /// assert_eq!(v, ["Mary", "had", "a", "little", "lamb"]);
+ /// ```
+ #[stable(feature = "split_whitespace", since = "1.1.0")]
+ pub fn split_whitespace(&self) -> SplitWhitespace {
+ UnicodeStr::split_whitespace(self)
+ }
+
+ /// An iterator over the non-empty substrings of `self` which contain no whitespace,
+ /// and which are separated by any amount of whitespace.
+ ///
+ /// # Examples
///
- /// let v: Vec<(usize, usize)> = "ababa".rmatch_indices("aba").collect();
- /// assert_eq!(v, [(2, 5)]); // only the last `aba`
/// ```
- #[unstable(feature = "collections",
- reason = "might have its iterator type changed")]
- // NB: Right now RMatchIndices yields `(usize, usize)`, but it would
- // be more consistent with `rmatches` and `char_indices` to return `(usize, &str)`
- pub fn rmatch_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatchIndices<'a, P>
- where P::Searcher: ReverseSearcher<'a>
- {
- core_str::StrExt::rmatch_indices(&self[..], pat)
+ /// # #![feature(str_words)]
+ /// # #![allow(deprecated)]
+ /// let some_words = " Mary had\ta little \n\t lamb";
+ /// let v: Vec<&str> = some_words.words().collect();
+ ///
+ /// assert_eq!(v, ["Mary", "had", "a", "little", "lamb"]);
+ /// ```
+ #[deprecated(reason = "words() will be removed. Use split_whitespace() instead",
+ since = "1.1.0")]
+ #[unstable(feature = "str_words",
+ reason = "the precise algorithm to use is unclear")]
+ #[allow(deprecated)]
+ pub fn words(&self) -> Words {
+ UnicodeStr::words(self)
}
/// An iterator over the lines of a string, separated by `\n`.
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn lines(&self) -> Lines {
- core_str::StrExt::lines(&self[..])
+ core_str::StrExt::lines(self)
}
/// An iterator over the lines of a string, separated by either
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn lines_any(&self) -> LinesAny {
- core_str::StrExt::lines_any(&self[..])
+ core_str::StrExt::lines_any(self)
}
- /// Returns a slice of the string from the character range [`begin`..`end`).
- ///
- /// That is, start at the `begin`-th code point of the string and continue
- /// to the `end`-th code point. This does not detect or handle edge cases
- /// such as leaving a combining character as the first code point of the
- /// string.
- ///
- /// Due to the design of UTF-8, this operation is `O(end)`. See `slice`,
- /// `slice_to` and `slice_from` for `O(1)` variants that use byte indices
- /// rather than code point indices.
+
+ /// Returns an iterator over the string in Unicode Normalization Form D
+ /// (canonical decomposition).
+ #[allow(deprecated)]
+ #[deprecated(reason = "use the crates.io `unicode-normalization` library instead",
+ since = "1.0.0")]
+ #[inline]
+ #[unstable(feature = "unicode",
+ reason = "this functionality may be replaced with a more generic \
+ unicode crate on crates.io")]
+ pub fn nfd_chars(&self) -> Decompositions {
+ Decompositions {
+ iter: self[..].chars(),
+ buffer: Vec::new(),
+ sorted: false,
+ kind: Canonical
+ }
+ }
+
+ /// Returns an iterator over the string in Unicode Normalization Form KD
+ /// (compatibility decomposition).
+ #[allow(deprecated)]
+ #[deprecated(reason = "use the crates.io `unicode-normalization` library instead",
+ since = "1.0.0")]
+ #[inline]
+ #[unstable(feature = "unicode",
+ reason = "this functionality may be replaced with a more generic \
+ unicode crate on crates.io")]
+ pub fn nfkd_chars(&self) -> Decompositions {
+ Decompositions {
+ iter: self[..].chars(),
+ buffer: Vec::new(),
+ sorted: false,
+ kind: Compatible
+ }
+ }
+
+ /// An Iterator over the string in Unicode Normalization Form C
+ /// (canonical decomposition followed by canonical composition).
+ #[allow(deprecated)]
+ #[deprecated(reason = "use the crates.io `unicode-normalization` library instead",
+ since = "1.0.0")]
+ #[inline]
+ #[unstable(feature = "unicode",
+ reason = "this functionality may be replaced with a more generic \
+ unicode crate on crates.io")]
+ pub fn nfc_chars(&self) -> Recompositions {
+ Recompositions {
+ iter: self.nfd_chars(),
+ state: Composing,
+ buffer: VecDeque::new(),
+ composee: None,
+ last_ccc: None
+ }
+ }
+
+ /// An Iterator over the string in Unicode Normalization Form KC
+ /// (compatibility decomposition followed by canonical composition).
+ #[allow(deprecated)]
+ #[deprecated(reason = "use the crates.io `unicode-normalization` library instead",
+ since = "1.0.0")]
+ #[inline]
+ #[unstable(feature = "unicode",
+ reason = "this functionality may be replaced with a more generic \
+ unicode crate on crates.io")]
+ pub fn nfkc_chars(&self) -> Recompositions {
+ Recompositions {
+ iter: self.nfkd_chars(),
+ state: Composing,
+ buffer: VecDeque::new(),
+ composee: None,
+ last_ccc: None
+ }
+ }
+
+ /// Returns an iterator over the [grapheme clusters][graphemes] of `self`.
///
- /// # Panics
+ /// [graphemes]: http://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries
///
- /// Panics if `begin` > `end` or the either `begin` or `end` are beyond the
- /// last character of the string.
+ /// If `is_extended` is true, the iterator is over the
+ /// *extended grapheme clusters*;
+ /// otherwise, the iterator is over the *legacy grapheme clusters*.
+ /// [UAX#29](http://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries)
+ /// recommends extended grapheme cluster boundaries for general processing.
///
/// # Examples
///
/// ```
- /// # #![feature(collections)]
- /// let s = "Löwe 老虎 Léopard";
+ /// # #![feature(unicode, core)]
+ /// let gr1 = "a\u{310}e\u{301}o\u{308}\u{332}".graphemes(true).collect::<Vec<&str>>();
+ /// let b: &[_] = &["a\u{310}", "e\u{301}", "o\u{308}\u{332}"];
///
- /// assert_eq!(s.slice_chars(0, 4), "Löwe");
- /// assert_eq!(s.slice_chars(5, 7), "老虎");
+ /// assert_eq!(&gr1[..], b);
+ ///
+ /// let gr2 = "a\r\nb🇷🇺🇸🇹".graphemes(true).collect::<Vec<&str>>();
+ /// let b: &[_] = &["a", "\r\n", "b", "🇷🇺🇸🇹"];
+ ///
+ /// assert_eq!(&gr2[..], b);
/// ```
- #[unstable(feature = "collections",
- reason = "may have yet to prove its worth")]
- pub fn slice_chars(&self, begin: usize, end: usize) -> &str {
- core_str::StrExt::slice_chars(&self[..], begin, end)
+ #[deprecated(reason = "use the crates.io `unicode-segmentation` library instead",
+ since = "1.0.0")]
+ #[unstable(feature = "unicode",
+ reason = "this functionality may only be provided by libunicode")]
+ pub fn graphemes(&self, is_extended: bool) -> Graphemes {
+ UnicodeStr::graphemes(self, is_extended)
}
- /// Takes a bytewise slice from a string.
+ /// Returns an iterator over the grapheme clusters of `self` and their
+ /// byte offsets. See
+ /// `graphemes()` for more information.
///
- /// Returns the substring from [`begin`..`end`).
+ /// # Examples
///
- /// # Unsafety
+ /// ```
+ /// # #![feature(unicode, core)]
+ /// let gr_inds = "a̐éö̲\r\n".grapheme_indices(true).collect::<Vec<(usize, &str)>>();
+ /// let b: &[_] = &[(0, "a̐"), (3, "é"), (6, "ö̲"), (11, "\r\n")];
///
- /// Caller must check both UTF-8 character boundaries and the boundaries
- /// of the entire slice as
- /// well.
+ /// assert_eq!(&gr_inds[..], b);
+ /// ```
+ #[deprecated(reason = "use the crates.io `unicode-segmentation` library instead",
+ since = "1.0.0")]
+ #[unstable(feature = "unicode",
+ reason = "this functionality may only be provided by libunicode")]
+ pub fn grapheme_indices(&self, is_extended: bool) -> GraphemeIndices {
+ UnicodeStr::grapheme_indices(self, is_extended)
+ }
+
+ /// Returns an iterator of `u16` over the string encoded as UTF-16.
+ #[unstable(feature = "str_utf16",
+ reason = "this functionality may only be provided by libunicode")]
+ pub fn utf16_units(&self) -> Utf16Units {
+ Utf16Units { encoder: Utf16Encoder::new(self[..].chars()) }
+ }
+
+ /// Returns `true` if `self` contains another `&str`.
///
/// # Examples
///
/// ```
- /// let s = "Löwe 老虎 Léopard";
+ /// assert!("bananas".contains("nana"));
///
- /// unsafe {
- /// assert_eq!(s.slice_unchecked(0, 21), "Löwe 老虎 Léopard");
- /// }
+ /// assert!(!"bananas".contains("foobar"));
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- pub unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str {
- core_str::StrExt::slice_unchecked(&self[..], begin, end)
+ pub fn contains<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool {
+ core_str::StrExt::contains(self, pat)
}
/// Returns `true` if the given `&str` is a prefix of the string.
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool {
- core_str::StrExt::starts_with(&self[..], pat)
+ core_str::StrExt::starts_with(self, pat)
}
/// Returns true if the given `&str` is a suffix of the string.
pub fn ends_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool
where P::Searcher: ReverseSearcher<'a>
{
- core_str::StrExt::ends_with(&self[..], pat)
+ core_str::StrExt::ends_with(self, pat)
}
- /// Returns a string with all pre- and suffixes that match a pattern
- /// repeatedly removed.
+ /// Returns the byte index of the first character of `self` that matches
+ /// the pattern, if it
+ /// exists.
+ ///
+ /// Returns `None` if it doesn't exist.
+ ///
+ /// The pattern can be a simple `&str`, `char`, or a closure that
+ /// determines the
+ /// split.
+ ///
+ /// # Examples
+ ///
+ /// Simple patterns:
+ ///
+ /// ```
+ /// let s = "Löwe 老虎 Léopard";
+ ///
+ /// assert_eq!(s.find('L'), Some(0));
+ /// assert_eq!(s.find('é'), Some(14));
+ /// assert_eq!(s.find("Léopard"), Some(13));
+ ///
+ /// ```
+ ///
+ /// More complex patterns with closures:
+ ///
+ /// ```
+ /// let s = "Löwe 老虎 Léopard";
+ ///
+ /// assert_eq!(s.find(char::is_whitespace), Some(5));
+ /// assert_eq!(s.find(char::is_lowercase), Some(1));
+ /// ```
+ ///
+ /// Not finding the pattern:
+ ///
+ /// ```
+ /// let s = "Löwe 老虎 Léopard";
+ /// let x: &[_] = &['1', '2'];
+ ///
+ /// assert_eq!(s.find(x), None);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize> {
+ core_str::StrExt::find(self, pat)
+ }
+
+ /// Returns the byte index of the last character of `self` that
+ /// matches the pattern, if it
+ /// exists.
+ ///
+ /// Returns `None` if it doesn't exist.
///
- /// The pattern can be a simple `char`, or a closure that determines
- /// the split.
+ /// The pattern can be a simple `&str`, `char`,
+ /// or a closure that determines the split.
///
/// # Examples
///
/// Simple patterns:
///
/// ```
- /// assert_eq!("11foo1bar11".trim_matches('1'), "foo1bar");
+ /// let s = "Löwe 老虎 Léopard";
///
- /// let x: &[_] = &['1', '2'];
- /// assert_eq!("12foo1bar12".trim_matches(x), "foo1bar");
+ /// assert_eq!(s.rfind('L'), Some(13));
+ /// assert_eq!(s.rfind('é'), Some(14));
/// ```
///
/// More complex patterns with closures:
///
/// ```
- /// assert_eq!("123foo1bar123".trim_matches(|c: char| c.is_numeric()), "foo1bar");
+ /// let s = "Löwe 老虎 Léopard";
+ ///
+ /// assert_eq!(s.rfind(char::is_whitespace), Some(12));
+ /// assert_eq!(s.rfind(char::is_lowercase), Some(20));
+ /// ```
+ ///
+ /// Not finding the pattern:
+ ///
+ /// ```
+ /// let s = "Löwe 老虎 Léopard";
+ /// let x: &[_] = &['1', '2'];
+ ///
+ /// assert_eq!(s.rfind(x), None);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn trim_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
- where P::Searcher: DoubleEndedSearcher<'a>
+ pub fn rfind<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize>
+ where P::Searcher: ReverseSearcher<'a>
{
- core_str::StrExt::trim_matches(&self[..], pat)
+ core_str::StrExt::rfind(self, pat)
}
- /// Returns a string with all prefixes that match a pattern
- /// repeatedly removed.
+ /// An iterator over substrings of `self`, separated by characters
+ /// matched by a pattern.
///
/// The pattern can be a simple `&str`, `char`, or a closure that
- /// determines the split.
+ /// determines the split. Additional libraries might provide more complex
+ /// patterns like regular expressions.
+ ///
+ /// # Iterator behavior
+ ///
+ /// The returned iterator will be double ended if the pattern allows a
+ /// reverse search and forward/reverse search yields the same elements.
+ /// This is true for, eg, `char` but not
+ /// for `&str`.
+ ///
+ /// If the pattern allows a reverse search but its results might differ
+ /// from a forward search, `rsplit()` can be used.
///
/// # Examples
///
/// Simple patterns:
///
/// ```
- /// assert_eq!("11foo1bar11".trim_left_matches('1'), "foo1bar11");
+ /// let v: Vec<&str> = "Mary had a little lamb".split(' ').collect();
+ /// assert_eq!(v, ["Mary", "had", "a", "little", "lamb"]);
///
- /// let x: &[_] = &['1', '2'];
- /// assert_eq!("12foo1bar12".trim_left_matches(x), "foo1bar12");
- /// ```
+ /// let v: Vec<&str> = "".split('X').collect();
+ /// assert_eq!(v, [""]);
///
- /// More complex patterns with closures:
+ /// let v: Vec<&str> = "lionXXtigerXleopard".split('X').collect();
+ /// assert_eq!(v, ["lion", "", "tiger", "leopard"]);
///
- /// ```
- /// assert_eq!("123foo1bar123".trim_left_matches(|c: char| c.is_numeric()), "foo1bar123");
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str {
- core_str::StrExt::trim_left_matches(&self[..], pat)
- }
-
- /// Returns a string with all suffixes that match a pattern
- /// repeatedly removed.
+ /// let v: Vec<&str> = "lion::tiger::leopard".split("::").collect();
+ /// assert_eq!(v, ["lion", "tiger", "leopard"]);
///
- /// The pattern can be a simple `&str`, `char`, or a closure that
- /// determines the split.
+ /// let v: Vec<&str> = "abc1def2ghi".split(char::is_numeric).collect();
+ /// assert_eq!(v, ["abc", "def", "ghi"]);
///
- /// # Examples
+ /// let v: Vec<&str> = "lionXtigerXleopard".split(char::is_uppercase).collect();
+ /// assert_eq!(v, ["lion", "tiger", "leopard"]);
+ /// ```
///
- /// Simple patterns:
+ /// A more complex pattern, using a closure:
///
/// ```
- /// assert_eq!("11foo1bar11".trim_right_matches('1'), "11foo1bar");
- /// let x: &[_] = &['1', '2'];
- /// assert_eq!("12foo1bar12".trim_right_matches(x), "12foo1bar");
+ /// let v: Vec<&str> = "abc1defXghi".split(|c| c == '1' || c == 'X').collect();
+ /// assert_eq!(v, ["abc", "def", "ghi"]);
/// ```
///
- /// More complex patterns with closures:
+ /// If a string contains multiple contiguous separators, you will end up
+ /// with empty strings in the output:
///
/// ```
- /// assert_eq!("123foo1bar123".trim_right_matches(|c: char| c.is_numeric()), "123foo1bar");
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
- where P::Searcher: ReverseSearcher<'a>
- {
- core_str::StrExt::trim_right_matches(&self[..], pat)
- }
-
- /// Checks that `index`-th byte lies at the start and/or end of a
- /// UTF-8 code point sequence.
- ///
- /// The start and end of the string (when `index == self.len()`) are
- /// considered to be
- /// boundaries.
+ /// let x = "||||a||b|c".to_string();
+ /// let d: Vec<_> = x.split('|').collect();
///
- /// # Panics
+ /// assert_eq!(d, &["", "", "", "", "a", "", "b", "c"]);
+ /// ```
///
- /// Panics if `index` is greater than `self.len()`.
+ /// This can lead to possibly surprising behavior when whitespace is used
+ /// as the separator. This code is correct:
///
- /// # Examples
+ /// ```
+ /// let x = " a b c".to_string();
+ /// let d: Vec<_> = x.split(' ').collect();
///
+ /// assert_eq!(d, &["", "", "", "", "a", "", "b", "c"]);
/// ```
- /// # #![feature(str_char)]
- /// let s = "Löwe 老虎 Léopard";
- /// assert!(s.is_char_boundary(0));
- /// // start of `老`
- /// assert!(s.is_char_boundary(6));
- /// assert!(s.is_char_boundary(s.len()));
///
- /// // second byte of `ö`
- /// assert!(!s.is_char_boundary(2));
+ /// It does _not_ give you:
///
- /// // third byte of `老`
- /// assert!(!s.is_char_boundary(8));
+ /// ```rust,ignore
+ /// assert_eq!(d, &["a", "b", "c"]);
/// ```
- #[unstable(feature = "str_char",
- reason = "it is unclear whether this method pulls its weight \
- with the existence of the char_indices iterator or \
- this method may want to be replaced with checked \
- slicing")]
- pub fn is_char_boundary(&self, index: usize) -> bool {
- core_str::StrExt::is_char_boundary(&self[..], index)
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P> {
+ core_str::StrExt::split(self, pat)
}
- /// Given a byte position, return the next char and its index.
+ /// An iterator over substrings of `self`, separated by characters
+ /// matched by a pattern and yielded in reverse order.
///
- /// This can be used to iterate over the Unicode characters of a string.
+ /// The pattern can be a simple `&str`, `char`, or a closure that
+ /// determines the split.
+ /// Additional libraries might provide more complex patterns like
+ /// regular expressions.
///
- /// # Panics
+ /// # Iterator behavior
///
- /// If `i` is greater than or equal to the length of the string.
- /// If `i` is not the index of the beginning of a valid UTF-8 character.
+ /// The returned iterator requires that the pattern supports a
+ /// reverse search,
+ /// and it will be double ended if a forward/reverse search yields
+ /// the same elements.
+ ///
+ /// For iterating from the front, `split()` can be used.
///
/// # Examples
///
- /// This example manually iterates through the characters of a string;
- /// this should normally be
- /// done by `.chars()` or `.char_indices()`.
+ /// Simple patterns:
///
- /// ```
- /// # #![feature(str_char, core)]
- /// use std::str::CharRange;
+ /// ```rust
+ /// let v: Vec<&str> = "Mary had a little lamb".rsplit(' ').collect();
+ /// assert_eq!(v, ["lamb", "little", "a", "had", "Mary"]);
///
- /// let s = "中华Việt Nam";
- /// let mut i = 0;
- /// while i < s.len() {
- /// let CharRange {ch, next} = s.char_range_at(i);
- /// println!("{}: {}", i, ch);
- /// i = next;
- /// }
+ /// let v: Vec<&str> = "".rsplit('X').collect();
+ /// assert_eq!(v, [""]);
+ ///
+ /// let v: Vec<&str> = "lionXXtigerXleopard".rsplit('X').collect();
+ /// assert_eq!(v, ["leopard", "tiger", "", "lion"]);
+ ///
+ /// let v: Vec<&str> = "lion::tiger::leopard".rsplit("::").collect();
+ /// assert_eq!(v, ["leopard", "tiger", "lion"]);
/// ```
///
- /// This outputs:
+ /// A more complex pattern, using a closure:
///
- /// ```text
- /// 0: 中
- /// 3: 华
- /// 6: V
- /// 7: i
- /// 8: ệ
- /// 11: t
- /// 12:
- /// 13: N
- /// 14: a
- /// 15: m
/// ```
- #[unstable(feature = "str_char",
- reason = "often replaced by char_indices, this method may \
- be removed in favor of just char_at() or eventually \
- removed altogether")]
- pub fn char_range_at(&self, start: usize) -> CharRange {
- core_str::StrExt::char_range_at(&self[..], start)
+ /// let v: Vec<&str> = "abc1defXghi".rsplit(|c| c == '1' || c == 'X').collect();
+ /// assert_eq!(v, ["ghi", "def", "abc"]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn rsplit<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplit<'a, P>
+ where P::Searcher: ReverseSearcher<'a>
+ {
+ core_str::StrExt::rsplit(self, pat)
}
- /// Given a byte position, return the previous `char` and its position.
+ /// An iterator over substrings of `self`, separated by characters
+ /// matched by a pattern.
///
- /// This function can be used to iterate over a Unicode string in reverse.
+ /// The pattern can be a simple `&str`, `char`, or a closure that
+ /// determines the split.
+ /// Additional libraries might provide more complex patterns
+ /// like regular expressions.
///
- /// Returns 0 for next index if called on start index 0.
+ /// Equivalent to `split`, except that the trailing substring
+ /// is skipped if empty.
///
- /// # Panics
+ /// This method can be used for string data that is _terminated_,
+ /// rather than _separated_ by a pattern.
///
- /// If `i` is greater than the length of the string.
- /// If `i` is not an index following a valid UTF-8 character.
+ /// # Iterator behavior
///
- /// # Examples
+ /// The returned iterator will be double ended if the pattern allows a
+ /// reverse search
+ /// and forward/reverse search yields the same elements. This is true
+ /// for, eg, `char` but not for `&str`.
///
- /// This example manually iterates through the characters of a string;
- /// this should normally be
- /// done by `.chars().rev()` or `.char_indices()`.
+ /// If the pattern allows a reverse search but its results might differ
+ /// from a forward search, `rsplit_terminator()` can be used.
///
- /// ```
- /// # #![feature(str_char, core)]
- /// use std::str::CharRange;
+ /// # Examples
///
- /// let s = "中华Việt Nam";
- /// let mut i = s.len();
- /// while i > 0 {
- /// let CharRange {ch, next} = s.char_range_at_reverse(i);
- /// println!("{}: {}", i, ch);
- /// i = next;
- /// }
/// ```
+ /// let v: Vec<&str> = "A.B.".split_terminator('.').collect();
+ /// assert_eq!(v, ["A", "B"]);
///
- /// This outputs:
- ///
- /// ```text
- /// 16: m
- /// 15: a
- /// 14: N
- /// 13:
- /// 12: t
- /// 11: ệ
- /// 8: i
- /// 7: V
- /// 6: 华
- /// 3: 中
+ /// let v: Vec<&str> = "A..B..".split_terminator(".").collect();
+ /// assert_eq!(v, ["A", "", "B", ""]);
/// ```
- #[unstable(feature = "str_char",
- reason = "often replaced by char_indices, this method may \
- be removed in favor of just char_at_reverse() or \
- eventually removed altogether")]
- pub fn char_range_at_reverse(&self, start: usize) -> CharRange {
- core_str::StrExt::char_range_at_reverse(&self[..], start)
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P> {
+ core_str::StrExt::split_terminator(self, pat)
}
- /// Given a byte position, return the `char` at that position.
+ /// An iterator over substrings of `self`, separated by characters
+ /// matched by a pattern and yielded in reverse order.
///
- /// # Panics
+ /// The pattern can be a simple `&str`, `char`, or a closure that
+ /// determines the split.
+ /// Additional libraries might provide more complex patterns like
+ /// regular expressions.
+ ///
+ /// Equivalent to `split`, except that the trailing substring is
+ /// skipped if empty.
+ ///
+ /// This method can be used for string data that is _terminated_,
+ /// rather than _separated_ by a pattern.
+ ///
+ /// # Iterator behavior
+ ///
+ /// The returned iterator requires that the pattern supports a
+ /// reverse search, and it will be double ended if a forward/reverse
+ /// search yields the same elements.
///
- /// If `i` is greater than or equal to the length of the string.
- /// If `i` is not the index of the beginning of a valid UTF-8 character.
+ /// For iterating from the front, `split_terminator()` can be used.
///
/// # Examples
///
/// ```
- /// # #![feature(str_char)]
- /// let s = "abπc";
- /// assert_eq!(s.char_at(1), 'b');
- /// assert_eq!(s.char_at(2), 'π');
+ /// let v: Vec<&str> = "A.B.".rsplit_terminator('.').collect();
+ /// assert_eq!(v, ["B", "A"]);
+ ///
+ /// let v: Vec<&str> = "A..B..".rsplit_terminator(".").collect();
+ /// assert_eq!(v, ["", "B", "", "A"]);
/// ```
- #[unstable(feature = "str_char",
- reason = "frequently replaced by the chars() iterator, this \
- method may be removed or possibly renamed in the \
- future; it is normally replaced by chars/char_indices \
- iterators or by getting the first char from a \
- subslice")]
- pub fn char_at(&self, i: usize) -> char {
- core_str::StrExt::char_at(&self[..], i)
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn rsplit_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplitTerminator<'a, P>
+ where P::Searcher: ReverseSearcher<'a>
+ {
+ core_str::StrExt::rsplit_terminator(self, pat)
}
- /// Given a byte position, return the `char` at that position, counting
- /// from the end.
+ /// An iterator over substrings of `self`, separated by a pattern,
+ /// restricted to returning
+ /// at most `count` items.
///
- /// # Panics
+ /// The last element returned, if any, will contain the remainder of the
+ /// string.
+ /// The pattern can be a simple `&str`, `char`, or a closure that
+ /// determines the split.
+ /// Additional libraries might provide more complex patterns like
+ /// regular expressions.
///
- /// If `i` is greater than the length of the string.
- /// If `i` is not an index following a valid UTF-8 character.
+ /// # Iterator behavior
+ ///
+ /// The returned iterator will not be double ended, because it is
+ /// not efficient to support.
+ ///
+ /// If the pattern allows a reverse search, `rsplitn()` can be used.
///
/// # Examples
///
+ /// Simple patterns:
+ ///
/// ```
- /// # #![feature(str_char)]
- /// let s = "abπc";
- /// assert_eq!(s.char_at_reverse(1), 'a');
- /// assert_eq!(s.char_at_reverse(2), 'b');
+ /// let v: Vec<&str> = "Mary had a little lambda".splitn(3, ' ').collect();
+ /// assert_eq!(v, ["Mary", "had", "a little lambda"]);
+ ///
+ /// let v: Vec<&str> = "lionXXtigerXleopard".splitn(3, "X").collect();
+ /// assert_eq!(v, ["lion", "", "tigerXleopard"]);
+ ///
+ /// let v: Vec<&str> = "abcXdef".splitn(1, 'X').collect();
+ /// assert_eq!(v, ["abcXdef"]);
+ ///
+ /// let v: Vec<&str> = "".splitn(1, 'X').collect();
+ /// assert_eq!(v, [""]);
/// ```
- #[unstable(feature = "str_char",
- reason = "see char_at for more details, but reverse semantics \
- are also somewhat unclear, especially with which \
- cases generate panics")]
- pub fn char_at_reverse(&self, i: usize) -> char {
- core_str::StrExt::char_at_reverse(&self[..], i)
- }
-
- /// Converts `self` to a byte slice.
///
- /// # Examples
+ /// A more complex pattern, using a closure:
///
/// ```
- /// assert_eq!("bors".as_bytes(), b"bors");
+ /// let v: Vec<&str> = "abc1defXghi".splitn(2, |c| c == '1' || c == 'X').collect();
+ /// assert_eq!(v, ["abc", "defXghi"]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn as_bytes(&self) -> &[u8] {
- core_str::StrExt::as_bytes(&self[..])
+ pub fn splitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> SplitN<'a, P> {
+ core_str::StrExt::splitn(self, count, pat)
}
- /// Returns the byte index of the first character of `self` that matches
- /// the pattern, if it
- /// exists.
+ /// An iterator over substrings of `self`, separated by a pattern,
+ /// starting from the end of the string, restricted to returning
+ /// at most `count` items.
///
- /// Returns `None` if it doesn't exist.
+ /// The last element returned, if any, will contain the remainder of the
+ /// string.
///
/// The pattern can be a simple `&str`, `char`, or a closure that
- /// determines the
- /// split.
+ /// determines the split.
+ /// Additional libraries might provide more complex patterns like
+ /// regular expressions.
+ ///
+ /// # Iterator behavior
+ ///
+ /// The returned iterator will not be double ended, because it is not
+ /// efficient to support.
+ ///
+ /// `splitn()` can be used for splitting from the front.
///
/// # Examples
///
/// Simple patterns:
///
/// ```
- /// let s = "Löwe 老虎 Léopard";
+ /// let v: Vec<&str> = "Mary had a little lamb".rsplitn(3, ' ').collect();
+ /// assert_eq!(v, ["lamb", "little", "Mary had a"]);
///
- /// assert_eq!(s.find('L'), Some(0));
- /// assert_eq!(s.find('é'), Some(14));
- /// assert_eq!(s.find("Léopard"), Some(13));
+ /// let v: Vec<&str> = "lionXXtigerXleopard".rsplitn(3, 'X').collect();
+ /// assert_eq!(v, ["leopard", "tiger", "lionX"]);
///
+ /// let v: Vec<&str> = "lion::tiger::leopard".rsplitn(2, "::").collect();
+ /// assert_eq!(v, ["leopard", "lion::tiger"]);
/// ```
///
- /// More complex patterns with closures:
+ /// A more complex pattern, using a closure:
///
/// ```
- /// let s = "Löwe 老虎 Léopard";
- ///
- /// assert_eq!(s.find(|c: char| c.is_whitespace()), Some(5));
- /// assert_eq!(s.find(char::is_lowercase), Some(1));
+ /// let v: Vec<&str> = "abc1defXghi".rsplitn(2, |c| c == '1' || c == 'X').collect();
+ /// assert_eq!(v, ["ghi", "abc1def"]);
/// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn rsplitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> RSplitN<'a, P>
+ where P::Searcher: ReverseSearcher<'a>
+ {
+ core_str::StrExt::rsplitn(self, count, pat)
+ }
+
+ /// An iterator over the matches of a pattern within `self`.
///
- /// Not finding the pattern:
+ /// The pattern can be a simple `&str`, `char`, or a closure that
+ /// determines the split.
+ /// Additional libraries might provide more complex patterns like
+ /// regular expressions.
+ ///
+ /// # Iterator behavior
+ ///
+ /// The returned iterator will be double ended if the pattern allows
+ /// a reverse search
+ /// and forward/reverse search yields the same elements. This is true
+ /// for, eg, `char` but not
+ /// for `&str`.
+ ///
+ /// If the pattern allows a reverse search but its results might differ
+ /// from a forward search, `rmatches()` can be used.
+ ///
+ /// # Examples
///
/// ```
- /// let s = "Löwe 老虎 Léopard";
- /// let x: &[_] = &['1', '2'];
+ /// let v: Vec<&str> = "abcXXXabcYYYabc".matches("abc").collect();
+ /// assert_eq!(v, ["abc", "abc", "abc"]);
///
- /// assert_eq!(s.find(x), None);
+ /// let v: Vec<&str> = "1abc2abc3".matches(char::is_numeric).collect();
+ /// assert_eq!(v, ["1", "2", "3"]);
/// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize> {
- core_str::StrExt::find(&self[..], pat)
+ #[stable(feature = "str_matches", since = "1.2.0")]
+ pub fn matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> Matches<'a, P> {
+ core_str::StrExt::matches(self, pat)
}
- /// Returns the byte index of the last character of `self` that
- /// matches the pattern, if it
- /// exists.
+ /// An iterator over the matches of a pattern within `self`, yielded in
+ /// reverse order.
///
- /// Returns `None` if it doesn't exist.
+ /// The pattern can be a simple `&str`, `char`, or a closure that
+ /// determines the split.
+ /// Additional libraries might provide more complex patterns like
+ /// regular expressions.
///
- /// The pattern can be a simple `&str`, `char`,
- /// or a closure that determines the split.
+ /// # Iterator behavior
///
- /// # Examples
+ /// The returned iterator requires that the pattern supports a
+ /// reverse search,
+ /// and it will be double ended if a forward/reverse search yields
+ /// the same elements.
///
- /// Simple patterns:
+ /// For iterating from the front, `matches()` can be used.
+ ///
+ /// # Examples
///
/// ```
- /// let s = "Löwe 老虎 Léopard";
+ /// let v: Vec<&str> = "abcXXXabcYYYabc".rmatches("abc").collect();
+ /// assert_eq!(v, ["abc", "abc", "abc"]);
///
- /// assert_eq!(s.rfind('L'), Some(13));
- /// assert_eq!(s.rfind('é'), Some(14));
+ /// let v: Vec<&str> = "1abc2abc3".rmatches(char::is_numeric).collect();
+ /// assert_eq!(v, ["3", "2", "1"]);
/// ```
+ #[stable(feature = "str_matches", since = "1.2.0")]
+ pub fn rmatches<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatches<'a, P>
+ where P::Searcher: ReverseSearcher<'a>
+ {
+ core_str::StrExt::rmatches(self, pat)
+ }
+
+ /// An iterator over the start and end indices of the disjoint matches
+ /// of a pattern within `self`.
///
- /// More complex patterns with closures:
+ /// For matches of `pat` within `self` that overlap, only the indices
+ /// corresponding to the first
+ /// match are returned.
///
- /// ```
- /// let s = "Löwe 老虎 Léopard";
+ /// The pattern can be a simple `&str`, `char`, or a closure that
+ /// determines
+ /// the split.
+ /// Additional libraries might provide more complex patterns like
+ /// regular expressions.
///
- /// assert_eq!(s.rfind(|c: char| c.is_whitespace()), Some(12));
- /// assert_eq!(s.rfind(char::is_lowercase), Some(20));
- /// ```
+ /// # Iterator behavior
///
- /// Not finding the pattern:
+ /// The returned iterator will be double ended if the pattern allows a
+ /// reverse search
+ /// and forward/reverse search yields the same elements. This is true for,
+ /// eg, `char` but not
+ /// for `&str`.
+ ///
+ /// If the pattern allows a reverse search but its results might differ
+ /// from a forward search, `rmatch_indices()` can be used.
+ ///
+ /// # Examples
///
/// ```
- /// let s = "Löwe 老虎 Léopard";
- /// let x: &[_] = &['1', '2'];
+ /// # #![feature(str_match_indices)]
+ /// let v: Vec<(usize, usize)> = "abcXXXabcYYYabc".match_indices("abc").collect();
+ /// assert_eq!(v, [(0, 3), (6, 9), (12, 15)]);
///
- /// assert_eq!(s.rfind(x), None);
+ /// let v: Vec<(usize, usize)> = "1abcabc2".match_indices("abc").collect();
+ /// assert_eq!(v, [(1, 4), (4, 7)]);
+ ///
+ /// let v: Vec<(usize, usize)> = "ababa".match_indices("aba").collect();
+ /// assert_eq!(v, [(0, 3)]); // only the first `aba`
/// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn rfind<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize>
- where P::Searcher: ReverseSearcher<'a>
- {
- core_str::StrExt::rfind(&self[..], pat)
+ #[unstable(feature = "str_match_indices",
+ reason = "might have its iterator type changed")]
+ // NB: Right now MatchIndices yields `(usize, usize)`, but it would
+ // be more consistent with `matches` and `char_indices` to return `(usize, &str)`
+ pub fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P> {
+ core_str::StrExt::match_indices(self, pat)
}
- /// Retrieves the first character from a `&str` and returns it.
+ /// An iterator over the start and end indices of the disjoint matches of
+ /// a pattern within
+ /// `self`, yielded in reverse order.
///
- /// This does not allocate a new string; instead, it returns a slice that
- /// points one character
- /// beyond the character that was shifted.
+ /// For matches of `pat` within `self` that overlap, only the indices
+ /// corresponding to the last
+ /// match are returned.
///
- /// If the slice does not contain any characters, None is returned instead.
+ /// The pattern can be a simple `&str`, `char`, or a closure that
+ /// determines
+ /// the split.
+ /// Additional libraries might provide more complex patterns like
+ /// regular expressions.
+ ///
+ /// # Iterator behavior
+ ///
+ /// The returned iterator requires that the pattern supports a
+ /// reverse search,
+ /// and it will be double ended if a forward/reverse search yields
+ /// the same elements.
+ ///
+ /// For iterating from the front, `match_indices()` can be used.
///
/// # Examples
///
/// ```
- /// # #![feature(str_char)]
- /// let s = "Löwe 老虎 Léopard";
- /// let (c, s1) = s.slice_shift_char().unwrap();
- ///
- /// assert_eq!(c, 'L');
- /// assert_eq!(s1, "öwe 老虎 Léopard");
+ /// # #![feature(str_match_indices)]
+ /// let v: Vec<(usize, usize)> = "abcXXXabcYYYabc".rmatch_indices("abc").collect();
+ /// assert_eq!(v, [(12, 15), (6, 9), (0, 3)]);
///
- /// let (c, s2) = s1.slice_shift_char().unwrap();
+ /// let v: Vec<(usize, usize)> = "1abcabc2".rmatch_indices("abc").collect();
+ /// assert_eq!(v, [(4, 7), (1, 4)]);
///
- /// assert_eq!(c, 'ö');
- /// assert_eq!(s2, "we 老虎 Léopard");
+ /// let v: Vec<(usize, usize)> = "ababa".rmatch_indices("aba").collect();
+ /// assert_eq!(v, [(2, 5)]); // only the last `aba`
/// ```
- #[unstable(feature = "str_char",
- reason = "awaiting conventions about shifting and slices and \
- may not be warranted with the existence of the chars \
- and/or char_indices iterators")]
- pub fn slice_shift_char(&self) -> Option<(char, &str)> {
- core_str::StrExt::slice_shift_char(&self[..])
+ #[unstable(feature = "str_match_indices",
+ reason = "might have its iterator type changed")]
+ // NB: Right now RMatchIndices yields `(usize, usize)`, but it would
+ // be more consistent with `rmatches` and `char_indices` to return `(usize, &str)`
+ pub fn rmatch_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatchIndices<'a, P>
+ where P::Searcher: ReverseSearcher<'a>
+ {
+ core_str::StrExt::rmatch_indices(self, pat)
}
/// Returns the byte offset of an inner slice relative to an enclosing
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(subslice_offset)]
/// let string = "a\nb\nc";
/// let lines: Vec<&str> = string.lines().collect();
///
/// assert!(string.subslice_offset(lines[1]) == 2); // &"b"
/// assert!(string.subslice_offset(lines[2]) == 4); // &"c"
/// ```
- #[unstable(feature = "collections",
+ #[unstable(feature = "subslice_offset",
reason = "awaiting convention about comparability of arbitrary slices")]
pub fn subslice_offset(&self, inner: &str) -> usize {
- core_str::StrExt::subslice_offset(&self[..], inner)
+ core_str::StrExt::subslice_offset(self, inner)
}
- /// Returns an unsafe pointer to the `&str`'s buffer.
- ///
- /// The caller must ensure that the string outlives this pointer, and
- /// that it is not
- /// reallocated (e.g. by pushing to the string).
+ /// Returns a `&str` with leading and trailing whitespace removed.
///
/// # Examples
///
/// ```
- /// let s = "Hello";
- /// let p = s.as_ptr();
+ /// let s = " Hello\tworld\t";
+ /// assert_eq!(s.trim(), "Hello\tworld");
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn as_ptr(&self) -> *const u8 {
- core_str::StrExt::as_ptr(&self[..])
- }
-
- /// Returns an iterator of `u16` over the string encoded as UTF-16.
- #[unstable(feature = "collections",
- reason = "this functionality may only be provided by libunicode")]
- pub fn utf16_units(&self) -> Utf16Units {
- Utf16Units { encoder: Utf16Encoder::new(self[..].chars()) }
+ pub fn trim(&self) -> &str {
+ UnicodeStr::trim(self)
}
- /// Returns the length of `self` in bytes.
+ /// Returns a `&str` with leading whitespace removed.
///
/// # Examples
///
/// ```
- /// assert_eq!("foo".len(), 3);
- /// assert_eq!("ƒoo".len(), 4); // fancy f!
+ /// let s = " Hello\tworld\t";
+ /// assert_eq!(s.trim_left(), "Hello\tworld\t");
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn len(&self) -> usize {
- core_str::StrExt::len(&self[..])
+ pub fn trim_left(&self) -> &str {
+ UnicodeStr::trim_left(self)
}
- /// Returns true if this slice has a length of zero bytes.
+ /// Returns a `&str` with trailing whitespace removed.
///
/// # Examples
///
/// ```
- /// assert!("".is_empty());
+ /// let s = " Hello\tworld\t";
+ /// assert_eq!(s.trim_right(), " Hello\tworld");
/// ```
- #[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn is_empty(&self) -> bool {
- core_str::StrExt::is_empty(&self[..])
+ pub fn trim_right(&self) -> &str {
+ UnicodeStr::trim_right(self)
}
- /// Parses `self` into the specified type.
+ /// Returns a string with all pre- and suffixes that match a pattern
+ /// repeatedly removed.
///
- /// # Failure
+ /// The pattern can be a simple `char`, or a closure that determines
+ /// the split.
///
- /// Will return `Err` if it's not possible to parse `self` into the type.
+ /// # Examples
///
- /// # Example
+ /// Simple patterns:
///
/// ```
- /// assert_eq!("4".parse::<u32>(), Ok(4));
+ /// assert_eq!("11foo1bar11".trim_matches('1'), "foo1bar");
+ /// assert_eq!("123foo1bar123".trim_matches(char::is_numeric), "foo1bar");
+ ///
+ /// let x: &[_] = &['1', '2'];
+ /// assert_eq!("12foo1bar12".trim_matches(x), "foo1bar");
/// ```
///
- /// Failing:
+ /// A more complex pattern, using a closure:
///
/// ```
- /// assert!("j".parse::<u32>().is_err());
+ /// assert_eq!("1foo1barXX".trim_matches(|c| c == '1' || c == 'X'), "foo1bar");
/// ```
- #[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn parse<F: FromStr>(&self) -> Result<F, F::Err> {
- core_str::StrExt::parse(&self[..])
+ pub fn trim_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
+ where P::Searcher: DoubleEndedSearcher<'a>
+ {
+ core_str::StrExt::trim_matches(self, pat)
}
- /// Returns an iterator over the [grapheme clusters][graphemes] of `self`.
- ///
- /// [graphemes]: http://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries
+ /// Returns a string with all prefixes that match a pattern
+ /// repeatedly removed.
///
- /// If `is_extended` is true, the iterator is over the
- /// *extended grapheme clusters*;
- /// otherwise, the iterator is over the *legacy grapheme clusters*.
- /// [UAX#29](http://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries)
- /// recommends extended grapheme cluster boundaries for general processing.
+ /// The pattern can be a simple `&str`, `char`, or a closure that
+ /// determines the split.
///
/// # Examples
///
/// ```
- /// # #![feature(unicode, core)]
- /// let gr1 = "a\u{310}e\u{301}o\u{308}\u{332}".graphemes(true).collect::<Vec<&str>>();
- /// let b: &[_] = &["a\u{310}", "e\u{301}", "o\u{308}\u{332}"];
- ///
- /// assert_eq!(&gr1[..], b);
- ///
- /// let gr2 = "a\r\nb🇷🇺🇸🇹".graphemes(true).collect::<Vec<&str>>();
- /// let b: &[_] = &["a", "\r\n", "b", "🇷🇺🇸🇹"];
+ /// assert_eq!("11foo1bar11".trim_left_matches('1'), "foo1bar11");
+ /// assert_eq!("123foo1bar123".trim_left_matches(char::is_numeric), "foo1bar123");
///
- /// assert_eq!(&gr2[..], b);
+ /// let x: &[_] = &['1', '2'];
+ /// assert_eq!("12foo1bar12".trim_left_matches(x), "foo1bar12");
/// ```
- #[deprecated(reason = "use the crates.io `unicode-segmentation` library instead",
- since = "1.0.0")]
- #[unstable(feature = "unicode",
- reason = "this functionality may only be provided by libunicode")]
- pub fn graphemes(&self, is_extended: bool) -> Graphemes {
- UnicodeStr::graphemes(&self[..], is_extended)
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str {
+ core_str::StrExt::trim_left_matches(self, pat)
}
- /// Returns an iterator over the grapheme clusters of `self` and their
- /// byte offsets. See
- /// `graphemes()` for more information.
+ /// Returns a string with all suffixes that match a pattern
+ /// repeatedly removed.
+ ///
+ /// The pattern can be a simple `&str`, `char`, or a closure that
+ /// determines the split.
///
/// # Examples
///
+ /// Simple patterns:
+ ///
/// ```
- /// # #![feature(unicode, core)]
- /// let gr_inds = "a̐éö̲\r\n".grapheme_indices(true).collect::<Vec<(usize, &str)>>();
- /// let b: &[_] = &[(0, "a̐"), (3, "é"), (6, "ö̲"), (11, "\r\n")];
+ /// assert_eq!("11foo1bar11".trim_right_matches('1'), "11foo1bar");
+ /// assert_eq!("123foo1bar123".trim_right_matches(char::is_numeric), "123foo1bar");
///
- /// assert_eq!(&gr_inds[..], b);
+ /// let x: &[_] = &['1', '2'];
+ /// assert_eq!("12foo1bar12".trim_right_matches(x), "12foo1bar");
/// ```
- #[deprecated(reason = "use the crates.io `unicode-segmentation` library instead",
- since = "1.0.0")]
- #[unstable(feature = "unicode",
- reason = "this functionality may only be provided by libunicode")]
- pub fn grapheme_indices(&self, is_extended: bool) -> GraphemeIndices {
- UnicodeStr::grapheme_indices(&self[..], is_extended)
- }
-
- /// An iterator over the non-empty substrings of `self` which contain no whitespace,
- /// and which are separated by any amount of whitespace.
///
- /// # Examples
+ /// A more complex pattern, using a closure:
///
/// ```
- /// # #![feature(str_words)]
- /// # #![allow(deprecated)]
- /// let some_words = " Mary had\ta little \n\t lamb";
- /// let v: Vec<&str> = some_words.words().collect();
- ///
- /// assert_eq!(v, ["Mary", "had", "a", "little", "lamb"]);
+ /// assert_eq!("1fooX".trim_left_matches(|c| c == '1' || c == 'X'), "fooX");
/// ```
- #[deprecated(reason = "words() will be removed. Use split_whitespace() instead",
- since = "1.1.0")]
- #[unstable(feature = "str_words",
- reason = "the precise algorithm to use is unclear")]
- #[allow(deprecated)]
- pub fn words(&self) -> Words {
- UnicodeStr::words(&self[..])
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
+ where P::Searcher: ReverseSearcher<'a>
+ {
+ core_str::StrExt::trim_right_matches(self, pat)
}
- /// An iterator over the non-empty substrings of `self` which contain no whitespace,
- /// and which are separated by any amount of whitespace.
- ///
- /// # Examples
+ /// Parses `self` into the specified type.
///
- /// ```
- /// let some_words = " Mary had\ta little \n\t lamb";
- /// let v: Vec<&str> = some_words.split_whitespace().collect();
+ /// # Failure
///
- /// assert_eq!(v, ["Mary", "had", "a", "little", "lamb"]);
- /// ```
- #[stable(feature = "split_whitespace", since = "1.1.0")]
- pub fn split_whitespace(&self) -> SplitWhitespace {
- UnicodeStr::split_whitespace(&self[..])
- }
-
- /// Returns a string's displayed width in columns.
+ /// Will return `Err` if it's not possible to parse `self` into the type.
///
- /// Control characters have zero width.
+ /// # Example
///
- /// `is_cjk` determines behavior for characters in the Ambiguous category:
- /// if `is_cjk` is
- /// `true`, these are 2 columns wide; otherwise, they are 1.
- /// In CJK locales, `is_cjk` should be
- /// `true`, else it should be `false`.
- /// [Unicode Standard Annex #11](http://www.unicode.org/reports/tr11/)
- /// recommends that these
- /// characters be treated as 1 column (i.e., `is_cjk = false`) if the
- /// locale is unknown.
- #[deprecated(reason = "use the crates.io `unicode-width` library instead",
- since = "1.0.0")]
- #[unstable(feature = "unicode",
- reason = "this functionality may only be provided by libunicode")]
- pub fn width(&self, is_cjk: bool) -> usize {
- UnicodeStr::width(&self[..], is_cjk)
- }
-
- /// Returns a `&str` with leading and trailing whitespace removed.
+ /// ```
+ /// assert_eq!("4".parse::<u32>(), Ok(4));
+ /// ```
///
- /// # Examples
+ /// Failing:
///
/// ```
- /// let s = " Hello\tworld\t";
- /// assert_eq!(s.trim(), "Hello\tworld");
+ /// assert!("j".parse::<u32>().is_err());
/// ```
+ #[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn trim(&self) -> &str {
- UnicodeStr::trim(&self[..])
+ pub fn parse<F: FromStr>(&self) -> Result<F, F::Err> {
+ core_str::StrExt::parse(self)
}
- /// Returns a `&str` with leading whitespace removed.
+ /// Replaces all occurrences of one string with another.
+ ///
+ /// `replace` takes two arguments, a sub-`&str` to find in `self`, and a
+ /// second `&str` to
+ /// replace it with. If the original `&str` isn't found, no change occurs.
///
/// # Examples
///
/// ```
- /// let s = " Hello\tworld\t";
- /// assert_eq!(s.trim_left(), "Hello\tworld\t");
+ /// let s = "this is old";
+ ///
+ /// assert_eq!(s.replace("old", "new"), "this is new");
/// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn trim_left(&self) -> &str {
- UnicodeStr::trim_left(&self[..])
- }
-
- /// Returns a `&str` with trailing whitespace removed.
///
- /// # Examples
+ /// When a `&str` isn't found:
///
/// ```
- /// let s = " Hello\tworld\t";
- /// assert_eq!(s.trim_right(), " Hello\tworld");
+ /// let s = "this is old";
+ /// assert_eq!(s.replace("cookie monster", "little lamb"), s);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn trim_right(&self) -> &str {
- UnicodeStr::trim_right(&self[..])
+ pub fn replace(&self, from: &str, to: &str) -> String {
+ let mut result = String::new();
+ let mut last_end = 0;
+ for (start, end) in self.match_indices(from) {
+ result.push_str(unsafe { self.slice_unchecked(last_end, start) });
+ result.push_str(to);
+ last_end = end;
+ }
+ result.push_str(unsafe { self.slice_unchecked(last_end, self.len()) });
+ result
}
/// Returns the lowercase equivalent of this string.
///
/// # Examples
///
+ /// ```
+ /// #![feature(str_casing)]
+ ///
/// let s = "HELLO";
/// assert_eq!(s.to_lowercase(), "hello");
- #[unstable(feature = "collections")]
+ /// ```
+ #[stable(feature = "unicode_case_mapping", since = "1.2.0")]
pub fn to_lowercase(&self) -> String {
let mut s = String::with_capacity(self.len());
- s.extend(self[..].chars().flat_map(|c| c.to_lowercase()));
+ for (i, c) in self[..].char_indices() {
+ if c == 'Σ' {
+ // Σ maps to σ, except at the end of a word where it maps to ς.
+ // This is the only conditional (contextual) but language-independent mapping
+ // in `SpecialCasing.txt`,
+ // so hard-code it rather than have a generic "condition" mechanim.
+ // See https://github.com/rust-lang/rust/issues/26035
+ map_uppercase_sigma(self, i, &mut s)
+ } else {
+ s.extend(c.to_lowercase());
+ }
+ }
return s;
+
+ fn map_uppercase_sigma(from: &str, i: usize, to: &mut String) {
+ // See http://www.unicode.org/versions/Unicode7.0.0/ch03.pdf#G33992
+ // for the definition of `Final_Sigma`.
+ debug_assert!('Σ'.len_utf8() == 2);
+ let is_word_final =
+ case_ignoreable_then_cased(from[..i].chars().rev()) &&
+ !case_ignoreable_then_cased(from[i + 2..].chars());
+ to.push_str(if is_word_final { "ς" } else { "σ" });
+ }
+
+ fn case_ignoreable_then_cased<I: Iterator<Item=char>>(iter: I) -> bool {
+ use rustc_unicode::derived_property::{Cased, Case_Ignorable};
+ match iter.skip_while(|&c| Case_Ignorable(c)).next() {
+ Some(c) => Cased(c),
+ None => false,
+ }
+ }
}
/// Returns the uppercase equivalent of this string.
///
/// # Examples
///
+ /// ```
+ /// #![feature(str_casing)]
+ ///
/// let s = "hello";
/// assert_eq!(s.to_uppercase(), "HELLO");
- #[unstable(feature = "collections")]
+ /// ```
+ #[stable(feature = "unicode_case_mapping", since = "1.2.0")]
pub fn to_uppercase(&self) -> String {
let mut s = String::with_capacity(self.len());
- s.extend(self[..].chars().flat_map(|c| c.to_uppercase()));
+ s.extend(self.chars().flat_map(|c| c.to_uppercase()));
return s;
}
+
+ /// Escapes each char in `s` with `char::escape_default`.
+ #[unstable(feature = "str_escape",
+ reason = "return type may change to be an iterator")]
+ pub fn escape_default(&self) -> String {
+ self.chars().flat_map(|c| c.escape_default()).collect()
+ }
+
+ /// Escapes each char in `s` with `char::escape_unicode`.
+ #[unstable(feature = "str_escape",
+ reason = "return type may change to be an iterator")]
+ pub fn escape_unicode(&self) -> String {
+ self.chars().flat_map(|c| c.escape_unicode()).collect()
+ }
}
/// # Examples
///
/// ```
- /// # #![feature(collections, core)]
- /// let s = String::from_str("hello");
+ /// # #![feature(collections)]
+ /// let s = String::from("hello");
/// assert_eq!(&s[..], "hello");
/// ```
#[inline]
- #[unstable(feature = "collections",
- reason = "needs investigation to see if to_string() can match perf")]
+ #[unstable(feature = "collections", reason = "use `String::from` instead")]
+ #[deprecated(since = "1.2.0", reason = "use `String::from` instead")]
#[cfg(not(test))]
pub fn from_str(string: &str) -> String {
String { vec: <[_]>::to_vec(string.as_bytes()) }
/// # Examples
///
/// ```
- /// # #![feature(core)]
- /// use std::str::Utf8Error;
- ///
/// let hello_vec = vec![104, 101, 108, 108, 111];
/// let s = String::from_utf8(hello_vec).unwrap();
/// assert_eq!(s, "hello");
/// # Examples
///
/// ```
- /// # #![feature(collections)]
- /// let s = String::from_str("hello");
+ /// let s = String::from("hello");
/// let bytes = s.into_bytes();
/// assert_eq!(bytes, [104, 101, 108, 108, 111]);
/// ```
/// # Examples
///
/// ```
- /// # #![feature(collections)]
- /// let mut s = String::from_str("foo");
+ /// let mut s = String::from("foo");
/// s.push_str("bar");
/// assert_eq!(s, "foobar");
/// ```
///
/// ```
/// let mut s = String::new();
- /// s.reserve(10);
+ /// s.reserve_exact(10);
/// assert!(s.capacity() >= 10);
/// ```
#[inline]
/// # Examples
///
/// ```
- /// # #![feature(collections)]
- /// let mut s = String::from_str("foo");
+ /// let mut s = String::from("foo");
/// s.reserve(100);
/// assert!(s.capacity() >= 100);
/// s.shrink_to_fit();
/// # Examples
///
/// ```
- /// # #![feature(collections)]
- /// let mut s = String::from_str("abc");
+ /// let mut s = String::from("abc");
/// s.push('1');
/// s.push('2');
/// s.push('3');
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn push(&mut self, ch: char) {
- if (ch as u32) < 0x80 {
- self.vec.push(ch as u8);
- return;
- }
+ match ch.len_utf8() {
+ 1 => self.vec.push(ch as u8),
+ ch_len => {
+ let cur_len = self.len();
+ // This may use up to 4 bytes.
+ self.vec.reserve(ch_len);
- let cur_len = self.len();
- // This may use up to 4 bytes.
- self.vec.reserve(4);
-
- unsafe {
- // Attempt to not use an intermediate buffer by just pushing bytes
- // directly onto this string.
- let slice = slice::from_raw_parts_mut (
- self.vec.as_mut_ptr().offset(cur_len as isize),
- 4
- );
- let used = ch.encode_utf8(slice).unwrap_or(0);
- self.vec.set_len(cur_len + used);
+ unsafe {
+ // Attempt to not use an intermediate buffer by just pushing bytes
+ // directly onto this string.
+ let slice = slice::from_raw_parts_mut (
+ self.vec.as_mut_ptr().offset(cur_len as isize),
+ ch_len
+ );
+ let used = ch.encode_utf8(slice).unwrap_or(0);
+ self.vec.set_len(cur_len + used);
+ }
+ }
}
}
/// # Examples
///
/// ```
- /// # #![feature(collections)]
- /// let s = String::from_str("hello");
- /// let b: &[_] = &[104, 101, 108, 108, 111];
- /// assert_eq!(s.as_bytes(), b);
+ /// let s = String::from("hello");
+ /// assert_eq!(s.as_bytes(), [104, 101, 108, 108, 111]);
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
/// # Examples
///
/// ```
- /// # #![feature(collections)]
- /// let mut s = String::from_str("hello");
+ /// let mut s = String::from("hello");
/// s.truncate(2);
/// assert_eq!(s, "he");
/// ```
/// # Examples
///
/// ```
- /// # #![feature(collections)]
- /// let mut s = String::from_str("foo");
+ /// let mut s = String::from("foo");
/// assert_eq!(s.pop(), Some('o'));
/// assert_eq!(s.pop(), Some('o'));
/// assert_eq!(s.pop(), Some('f'));
/// # Examples
///
/// ```
- /// # #![feature(collections)]
- /// let mut s = String::from_str("foo");
+ /// let mut s = String::from("foo");
/// assert_eq!(s.remove(0), 'f');
/// assert_eq!(s.remove(1), 'o');
/// assert_eq!(s.remove(0), 'o');
/// # Examples
///
/// ```
- /// # #![feature(collections)]
- /// let mut s = String::from_str("hello");
+ /// let mut s = String::from("hello");
/// unsafe {
/// let vec = s.as_mut_vec();
/// assert!(vec == &[104, 101, 108, 108, 111]);
/// # Examples
///
/// ```
- /// # #![feature(collections_drain)]
+ /// # #![feature(drain)]
///
/// let mut s = String::from("α is alpha, β is beta");
/// let beta_offset = s.find('β').unwrap_or(s.len());
/// s.drain(..);
/// assert_eq!(s, "");
/// ```
- #[unstable(feature = "collections_drain",
+ #[unstable(feature = "drain",
reason = "recently added, matches RFC")]
pub fn drain<R>(&mut self, range: R) -> Drain where R: RangeArgument<usize> {
// Memory safety
}
}
+#[stable(feature = "extend_ref", since = "1.2.0")]
+impl<'a> Extend<&'a char> for String {
+ fn extend<I: IntoIterator<Item=&'a char>>(&mut self, iter: I) {
+ self.extend(iter.into_iter().cloned());
+ }
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> Extend<&'a str> for String {
fn extend<I: IntoIterator<Item=&'a str>>(&mut self, iterable: I) {
/// Wrapper type providing a `&String` reference via `Deref`.
#[unstable(feature = "collections")]
+#[deprecated(since = "1.2.0",
+ reason = "replaced with deref coercions or Borrow")]
+#[allow(deprecated)]
pub struct DerefString<'a> {
x: DerefVec<'a, u8>
}
+#[allow(deprecated)]
impl<'a> Deref for DerefString<'a> {
type Target = String;
/// string_consumer(&as_string("foo"));
/// ```
#[unstable(feature = "collections")]
+#[deprecated(since = "1.2.0",
+ reason = "replaced with deref coercions or Borrow")]
+#[allow(deprecated)]
pub fn as_string<'a>(x: &'a str) -> DerefString<'a> {
DerefString { x: as_vec(x.as_bytes()) }
}
-/// Error returned from `String::from_str`
+/// Error returned from `String::from`
#[unstable(feature = "str_parse_error", reason = "may want to be replaced with \
Void if it ever exists")]
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
type Err = ParseError;
#[inline]
fn from_str(s: &str) -> Result<String, ParseError> {
- Ok(String::from_str(s))
+ Ok(String::from(s))
}
}
}
/// A draining iterator for `String`.
-#[unstable(feature = "collections_drain", reason = "recently added")]
+#[unstable(feature = "drain", reason = "recently added")]
pub struct Drain<'a> {
/// Will be used as &'a mut String in the destructor
string: *mut String,
unsafe impl<'a> Sync for Drain<'a> {}
unsafe impl<'a> Send for Drain<'a> {}
-#[unstable(feature = "collections_drain", reason = "recently added")]
+#[unstable(feature = "drain", reason = "recently added")]
impl<'a> Drop for Drain<'a> {
fn drop(&mut self) {
unsafe {
}
}
-#[unstable(feature = "collections_drain", reason = "recently added")]
+#[unstable(feature = "drain", reason = "recently added")]
impl<'a> Iterator for Drain<'a> {
type Item = char;
}
}
-#[unstable(feature = "collections_drain", reason = "recently added")]
+#[unstable(feature = "drain", reason = "recently added")]
impl<'a> DoubleEndedIterator for Drain<'a> {
#[inline]
fn next_back(&mut self) -> Option<char> {
//! A growable list type with heap-allocated contents, written `Vec<T>` but
//! pronounced 'vector.'
//!
-//! Vectors have `O(1)` indexing, push (to the end) and pop (from the end).
+//! Vectors have `O(1)` indexing, amortized `O(1)` push (to the end) and
+//! `O(1)` pop (from the end).
//!
//! # Examples
//!
use core::cmp::Ordering;
use core::fmt;
use core::hash::{self, Hash};
-use core::intrinsics::assume;
+use core::intrinsics::{arith_offset, assume};
use core::iter::{repeat, FromIterator};
use core::marker::PhantomData;
use core::mem;
use super::range::RangeArgument;
// FIXME- fix places which assume the max vector allowed has memory usize::MAX.
-static MAX_MEMORY_SIZE: usize = isize::MAX as usize;
+const MAX_MEMORY_SIZE: usize = isize::MAX as usize;
/// A growable list type, written `Vec<T>` but pronounced 'vector.'
///
/// # Examples
///
/// ```
-/// # #![feature(collections)]
/// let mut vec = Vec::new();
/// vec.push(1);
/// vec.push(2);
/// vec[0] = 7;
/// assert_eq!(vec[0], 7);
///
-/// vec.push_all(&[1, 2, 3]);
+/// vec.extend([1, 2, 3].iter().cloned());
///
-/// for x in vec.iter() {
+/// for x in &vec {
/// println!("{}", x);
/// }
/// assert_eq!(vec, [7, 1, 2, 3]);
} else {
let size = capacity.checked_mul(mem::size_of::<T>())
.expect("capacity overflow");
- let ptr = unsafe { allocate(size, mem::min_align_of::<T>()) };
+ let ptr = unsafe { allocate(size, mem::align_of::<T>()) };
if ptr.is_null() { ::alloc::oom() }
unsafe { Vec::from_raw_parts(ptr as *mut T, 0, capacity) }
}
/// the buffer are copied into the vector without cloning, as if
/// `ptr::read()` were called on them.
#[inline]
- #[unstable(feature = "collections",
+ #[unstable(feature = "vec_from_raw_buf",
reason = "may be better expressed via composition")]
+ #[deprecated(since = "1.2.0",
+ reason = "use slice::from_raw_parts + .to_vec() instead")]
pub unsafe fn from_raw_buf(ptr: *const T, elts: usize) -> Vec<T> {
let mut dst = Vec::with_capacity(elts);
dst.set_len(elts);
/// # Examples
///
/// ```
- /// # #![feature(collections)]
/// let mut vec = Vec::with_capacity(10);
- /// vec.push_all(&[1, 2, 3]);
+ /// vec.extend([1, 2, 3].iter().cloned());
/// assert_eq!(vec.capacity(), 10);
/// vec.shrink_to_fit();
/// assert!(vec.capacity() >= 3);
let ptr = reallocate(*self.ptr as *mut u8,
self.cap * mem::size_of::<T>(),
self.len * mem::size_of::<T>(),
- mem::min_align_of::<T>()) as *mut T;
+ mem::align_of::<T>()) as *mut T;
if ptr.is_null() { ::alloc::oom() }
self.ptr = Unique::new(ptr);
}
/// # Examples
///
/// ```
- /// # #![feature(collections)]
/// let mut vec = vec![1, 2, 3, 4];
/// vec.truncate(2);
/// assert_eq!(vec, [1, 2]);
}
/// Extracts a slice containing the entire vector.
+ ///
+ /// Equivalent to `&s[..]`.
#[inline]
#[unstable(feature = "convert",
reason = "waiting on RFC revision")]
self
}
- /// Deprecated: use `&mut s[..]` instead.
+ /// Extracts a mutable slice of the entire vector.
+ ///
+ /// Equivalent to `&mut s[..]`.
#[inline]
#[unstable(feature = "convert",
reason = "waiting on RFC revision")]
/// # Examples
///
/// ```
- /// # #![feature(collections)]
/// let mut v = vec![1, 2, 3];
/// assert_eq!(v.remove(1), 2);
/// assert_eq!(v, [1, 3]);
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(append)]
/// let mut vec = vec![1, 2, 3];
/// let mut vec2 = vec![4, 5, 6];
/// vec.append(&mut vec2);
/// assert_eq!(vec2, []);
/// ```
#[inline]
- #[unstable(feature = "collections",
+ #[unstable(feature = "append",
reason = "new API, waiting for dust to settle")]
pub fn append(&mut self, other: &mut Self) {
if mem::size_of::<T>() == 0 {
/// # Examples
///
/// ```
- /// # #![feature(collections_drain, collections_range)]
+ /// # #![feature(drain)]
///
/// // Draining using `..` clears the whole vector.
/// let mut v = vec![1, 2, 3];
/// assert_eq!(v, &[]);
/// assert_eq!(u, &[1, 2, 3]);
/// ```
- #[unstable(feature = "collections_drain",
+ #[unstable(feature = "drain",
reason = "recently added, matches RFC")]
pub fn drain<R>(&mut self, range: R) -> Drain<T> where R: RangeArgument<usize> {
// Memory safety
/// # Examples
///
/// ```
- /// # #![feature(collections, core)]
+ /// # #![feature(map_in_place)]
/// let v = vec![0, 1, 2];
/// let w = v.map_in_place(|i| i + 3);
/// assert_eq!(&w[..], &[3, 4, 5]);
/// let newtyped_bytes = bytes.map_in_place(|x| Newtype(x));
/// assert_eq!(&newtyped_bytes[..], &[Newtype(0x11), Newtype(0x22)]);
/// ```
- #[unstable(feature = "collections",
+ #[unstable(feature = "map_in_place",
reason = "API may change to provide stronger guarantees")]
pub fn map_in_place<U, F>(self, mut f: F) -> Vec<U> where F: FnMut(T) -> U {
// FIXME: Assert statically that the types `T` and `U` have the same
// FIXME: Assert statically that the types `T` and `U` have the
// same minimal alignment in case they are not zero-sized.
- // These asserts are necessary because the `min_align_of` of the
+ // These asserts are necessary because the `align_of` of the
// types are passed to the allocator by `Vec`.
- assert!(mem::min_align_of::<T>() == mem::min_align_of::<U>());
+ assert!(mem::align_of::<T>() == mem::align_of::<U>());
// This `as isize` cast is safe, because the size of the elements of the
// vector is not 0, and:
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(split_off)]
/// let mut vec = vec![1,2,3];
/// let vec2 = vec.split_off(1);
/// assert_eq!(vec, [1]);
/// assert_eq!(vec2, [2, 3]);
/// ```
#[inline]
- #[unstable(feature = "collections",
+ #[unstable(feature = "split_off",
reason = "new API, waiting for dust to settle")]
pub fn split_off(&mut self, at: usize) -> Self {
assert!(at <= self.len(), "`at` out of bounds");
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(vec_resize)]
/// let mut vec = vec!["hello"];
/// vec.resize(3, "world");
/// assert_eq!(vec, ["hello", "world", "world"]);
/// vec.resize(2, 0);
/// assert_eq!(vec, [1, 2]);
/// ```
- #[unstable(feature = "collections",
+ #[unstable(feature = "vec_resize",
reason = "matches collection reform specification; waiting for dust to settle")]
pub fn resize(&mut self, new_len: usize, value: T) {
let len = self.len();
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(vec_push_all)]
/// let mut vec = vec![1];
/// vec.push_all(&[2, 3, 4]);
/// assert_eq!(vec, [1, 2, 3, 4]);
/// ```
#[inline]
- #[unstable(feature = "collections",
+ #[unstable(feature = "vec_push_all",
reason = "likely to be replaced by a more optimized extend")]
pub fn push_all(&mut self, other: &[T]) {
self.reserve(other.len());
// Duplicate, advance r. End of vec. Truncate to w.
let ln = self.len();
- if ln < 1 { return; }
+ if ln <= 1 { return; }
- // Avoid bounds checks by using unsafe pointers.
+ // Avoid bounds checks by using raw pointers.
let p = self.as_mut_ptr();
let mut r: usize = 1;
let mut w: usize = 1;
#[inline(never)]
unsafe fn alloc_or_realloc<T>(ptr: *mut T, old_size: usize, size: usize) -> *mut T {
if old_size == 0 {
- allocate(size, mem::min_align_of::<T>()) as *mut T
+ allocate(size, mem::align_of::<T>()) as *mut T
} else {
- reallocate(ptr as *mut u8, old_size, size, mem::min_align_of::<T>()) as *mut T
+ reallocate(ptr as *mut u8, old_size, size, mem::align_of::<T>()) as *mut T
}
}
if mem::size_of::<T>() != 0 {
deallocate(ptr as *mut u8,
len * mem::size_of::<T>(),
- mem::min_align_of::<T>())
+ mem::align_of::<T>())
}
}
}
// reuse the contained values' allocations/resources.
- for (place, thing) in self.iter_mut().zip(other.iter()) {
+ for (place, thing) in self.iter_mut().zip(other) {
place.clone_from(thing)
}
impl<T> FromIterator<T> for Vec<T> {
#[inline]
fn from_iter<I: IntoIterator<Item=T>>(iterable: I) -> Vec<T> {
+ // Unroll the first iteration, as the vector is going to be
+ // expanded on this iteration in every case when the iterable is not
+ // empty, but the loop in extend_desugared() is not going to see the
+ // vector being full in the few subsequent loop iterations.
+ // So we get better branch prediction and the possibility to
+ // construct the vector with initial estimated capacity.
let mut iterator = iterable.into_iter();
- let (lower, _) = iterator.size_hint();
- let mut vector = Vec::with_capacity(lower);
-
- // This function should be the moral equivalent of:
- //
- // for item in iterator {
- // vector.push(item);
- // }
- //
- // This equivalent crucially runs the iterator precisely once. Below we
- // actually in theory run the iterator twice (one without bounds checks
- // and one with). To achieve the "moral equivalent", we use the `if`
- // statement below to break out early.
- //
- // If the first loop has terminated, then we have one of two conditions.
- //
- // 1. The underlying iterator returned `None`. In this case we are
- // guaranteed that less than `vector.capacity()` elements have been
- // returned, so we break out early.
- // 2. The underlying iterator yielded `vector.capacity()` elements and
- // has not yielded `None` yet. In this case we run the iterator to
- // its end below.
- for element in iterator.by_ref().take(vector.capacity()) {
- let len = vector.len();
- unsafe {
- ptr::write(vector.get_unchecked_mut(len), element);
- vector.set_len(len + 1);
- }
- }
-
- if vector.len() == vector.capacity() {
- for element in iterator {
- vector.push(element);
+ let mut vector = match iterator.next() {
+ None => return Vec::new(),
+ Some(element) => {
+ let (lower, _) = iterator.size_hint();
+ let mut vector = Vec::with_capacity(lower.saturating_add(1));
+ unsafe {
+ ptr::write(vector.get_unchecked_mut(0), element);
+ vector.set_len(1);
+ }
+ vector
}
- }
+ };
+ vector.extend_desugared(iterator);
vector
}
}
let cap = self.cap;
let begin = ptr as *const T;
let end = if mem::size_of::<T>() == 0 {
- (ptr as usize + self.len()) as *const T
+ arith_offset(ptr as *const i8, self.len() as isize) as *const T
} else {
ptr.offset(self.len() as isize) as *const T
};
impl<T> Extend<T> for Vec<T> {
#[inline]
fn extend<I: IntoIterator<Item=T>>(&mut self, iterable: I) {
- let iterator = iterable.into_iter();
- let (lower, _) = iterator.size_hint();
- self.reserve(lower);
- for element in iterator {
- self.push(element)
+ self.extend_desugared(iterable.into_iter())
+ }
+}
+
+impl<T> Vec<T> {
+ fn extend_desugared<I: Iterator<Item=T>>(&mut self, mut iterator: I) {
+ // This function should be the moral equivalent of:
+ //
+ // for item in iterator {
+ // self.push(item);
+ // }
+ while let Some(element) = iterator.next() {
+ let len = self.len();
+ if len == self.capacity() {
+ let (lower, _) = iterator.size_hint();
+ self.reserve(lower.saturating_add(1));
+ }
+ unsafe {
+ ptr::write(self.get_unchecked_mut(len), element);
+ // NB can't overflow since we would have had to alloc the address space
+ self.set_len(len + 1);
+ }
}
}
}
+#[stable(feature = "extend_ref", since = "1.2.0")]
+impl<'a, T: 'a + Copy> Extend<&'a T> for Vec<T> {
+ fn extend<I: IntoIterator<Item=&'a T>>(&mut self, iter: I) {
+ self.extend(iter.into_iter().cloned());
+ }
+}
+
__impl_slice_eq1! { Vec<A>, Vec<B> }
__impl_slice_eq1! { Vec<A>, &'b [B] }
__impl_slice_eq1! { Vec<A>, &'b mut [B] }
// zeroed (when moving out, because of #[unsafe_no_drop_flag]).
if self.cap != 0 && self.cap != mem::POST_DROP_USIZE {
unsafe {
- for x in &*self {
+ for x in self.iter() {
ptr::read(x);
}
dealloc(*self.ptr, self.cap)
}
}
+#[allow(deprecated)]
impl<'a, T: 'a> IntoCow<'a, [T]> for Vec<T> where T: Clone {
fn into_cow(self) -> Cow<'a, [T]> {
Cow::Owned(self)
}
}
+#[allow(deprecated)]
impl<'a, T> IntoCow<'a, [T]> for &'a [T] where T: Clone {
fn into_cow(self) -> Cow<'a, [T]> {
Cow::Borrowed(self)
impl<T> IntoIter<T> {
#[inline]
/// Drops all items that have not yet been moved and returns the empty vector.
- #[unstable(feature = "collections")]
+ #[unstable(feature = "iter_to_vec")]
pub fn into_inner(mut self) -> Vec<T> {
unsafe {
for _x in self.by_ref() { }
// purposefully don't use 'ptr.offset' because for
// vectors with 0-size elements this would return the
// same pointer.
- self.ptr = mem::transmute(self.ptr as usize + 1);
+ self.ptr = arith_offset(self.ptr as *const i8, 1) as *const T;
// Use a non-null pointer value
Some(ptr::read(EMPTY as *mut T))
} else {
if mem::size_of::<T>() == 0 {
// See above for why 'ptr.offset' isn't used
- self.end = mem::transmute(self.end as usize - 1);
+ self.end = arith_offset(self.end as *const i8, -1) as *const T;
// Use a non-null pointer value
Some(ptr::read(EMPTY as *mut T))
}
/// A draining iterator for `Vec<T>`.
-#[unstable(feature = "collections_drain", reason = "recently added")]
+#[unstable(feature = "drain", reason = "recently added")]
pub struct Drain<'a, T: 'a> {
/// Index of tail to preserve
tail_start: usize,
/// Wrapper type providing a `&Vec<T>` reference via `Deref`.
#[unstable(feature = "collections")]
+#[deprecated(since = "1.2.0",
+ reason = "replaced with deref coercions or Borrow")]
pub struct DerefVec<'a, T:'a> {
x: Vec<T>,
l: PhantomData<&'a T>,
}
#[unstable(feature = "collections")]
+#[deprecated(since = "1.2.0",
+ reason = "replaced with deref coercions or Borrow")]
+#[allow(deprecated)]
impl<'a, T> Deref for DerefVec<'a, T> {
type Target = Vec<T>;
// Prevent the inner `Vec<T>` from attempting to deallocate memory.
#[stable(feature = "rust1", since = "1.0.0")]
+#[deprecated(since = "1.2.0",
+ reason = "replaced with deref coercions or Borrow")]
+#[allow(deprecated)]
impl<'a, T> Drop for DerefVec<'a, T> {
fn drop(&mut self) {
self.x.len = 0;
/// vec_consumer(&as_vec(&values));
/// ```
#[unstable(feature = "collections")]
+#[deprecated(since = "1.2.0",
+ reason = "replaced with deref coercions or Borrow")]
+#[allow(deprecated)]
pub fn as_vec<'a, T>(x: &'a [T]) -> DerefVec<'a, T> {
unsafe {
DerefVec {
if mem::size_of::<T>() != 0 {
heap::deallocate(*self.ptr as *mut u8,
self.cap * mem::size_of::<T>(),
- mem::min_align_of::<T>())
+ mem::align_of::<T>())
}
}
}
let ptr = unsafe {
if mem::size_of::<T>() != 0 {
- let ptr = heap::allocate(size, mem::min_align_of::<T>()) as *mut T;;
+ let ptr = heap::allocate(size, mem::align_of::<T>()) as *mut T;;
if ptr.is_null() { ::alloc::oom() }
Unique::new(ptr)
} else {
/// # Examples
///
/// ```
- /// # #![feature(collections)]
/// use std::collections::VecDeque;
///
/// let mut buf = VecDeque::new();
/// # Examples
///
/// ```
- /// # #![feature(collections)]
/// use std::collections::VecDeque;
///
/// let buf: VecDeque<i32> = VecDeque::with_capacity(10);
/// # Examples
///
/// ```
- /// # #![feature(collections)]
/// use std::collections::VecDeque;
///
/// let mut buf: VecDeque<i32> = vec![1].into_iter().collect();
/// # Examples
///
/// ```
- /// # #![feature(collections)]
/// use std::collections::VecDeque;
///
/// let mut buf: VecDeque<i32> = vec![1].into_iter().collect();
let ptr = heap::reallocate(*self.ptr as *mut u8,
old,
new,
- mem::min_align_of::<T>()) as *mut T;
+ mem::align_of::<T>()) as *mut T;
if ptr.is_null() { ::alloc::oom() }
self.ptr = Unique::new(ptr);
}
let ptr = heap::reallocate(*self.ptr as *mut u8,
old,
new_size,
- mem::min_align_of::<T>()) as *mut T;
+ mem::align_of::<T>()) as *mut T;
if ptr.is_null() { ::alloc::oom() }
self.ptr = Unique::new(ptr);
}
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(deque_extras)]
/// use std::collections::VecDeque;
///
/// let mut buf = VecDeque::new();
/// assert_eq!(buf.len(), 1);
/// assert_eq!(Some(&5), buf.get(0));
/// ```
- #[unstable(feature = "collections",
+ #[unstable(feature = "deque_extras",
reason = "matches collection reform specification; waiting on panic semantics")]
pub fn truncate(&mut self, len: usize) {
for _ in len..self.len() {
/// # Examples
///
/// ```
- /// # #![feature(core)]
/// use std::collections::VecDeque;
///
/// let mut buf = VecDeque::new();
/// # Examples
///
/// ```
- /// # #![feature(core)]
/// use std::collections::VecDeque;
///
/// let mut buf = VecDeque::new();
/// Returns a pair of slices which contain, in order, the contents of the
/// `VecDeque`.
#[inline]
- #[unstable(feature = "collections",
+ #[unstable(feature = "deque_extras",
reason = "matches collection reform specification, waiting for dust to settle")]
pub fn as_slices(&self) -> (&[T], &[T]) {
unsafe {
/// Returns a pair of slices which contain, in order, the contents of the
/// `VecDeque`.
#[inline]
- #[unstable(feature = "collections",
+ #[unstable(feature = "deque_extras",
reason = "matches collection reform specification, waiting for dust to settle")]
pub fn as_mut_slices(&mut self) -> (&mut [T], &mut [T]) {
unsafe {
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(drain)]
/// use std::collections::VecDeque;
///
/// let mut v = VecDeque::new();
/// assert!(v.is_empty());
/// ```
#[inline]
- #[unstable(feature = "collections",
+ #[unstable(feature = "drain",
reason = "matches collection reform specification, waiting for dust to settle")]
pub fn drain(&mut self) -> Drain<T> {
Drain {
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(deque_extras)]
/// use std::collections::VecDeque;
///
/// let mut buf = VecDeque::new();
/// buf.push_back(10);
/// assert_eq!(buf.swap_back_remove(1), Some(99));
/// ```
- #[unstable(feature = "collections",
+ #[unstable(feature = "deque_extras",
reason = "the naming of this function may be altered")]
pub fn swap_back_remove(&mut self, index: usize) -> Option<T> {
let length = self.len();
self.pop_back()
}
- /// Removes an element from anywhere in the ringbuf and returns it, replacing it with the first
- /// element.
+ /// Removes an element from anywhere in the ringbuf and returns it,
+ /// replacing it with the first element.
///
/// This does not preserve ordering, but is O(1).
///
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(deque_extras)]
/// use std::collections::VecDeque;
///
/// let mut buf = VecDeque::new();
/// buf.push_back(20);
/// assert_eq!(buf.swap_front_remove(3), Some(99));
/// ```
- #[unstable(feature = "collections",
+ #[unstable(feature = "deque_extras",
reason = "the naming of this function may be altered")]
pub fn swap_front_remove(&mut self, index: usize) -> Option<T> {
let length = self.len();
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(split_off)]
/// use std::collections::VecDeque;
///
/// let mut buf: VecDeque<_> = vec![1,2,3].into_iter().collect();
/// assert_eq!(buf2.len(), 2);
/// ```
#[inline]
- #[unstable(feature = "collections",
+ #[unstable(feature = "split_off",
reason = "new API, waiting for dust to settle")]
pub fn split_off(&mut self, at: usize) -> Self {
let len = self.len();
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(append)]
/// use std::collections::VecDeque;
///
/// let mut buf: VecDeque<_> = vec![1, 2, 3].into_iter().collect();
/// assert_eq!(buf2.len(), 0);
/// ```
#[inline]
- #[unstable(feature = "collections",
+ #[unstable(feature = "append",
reason = "new API, waiting for dust to settle")]
pub fn append(&mut self, other: &mut Self) {
// naive impl
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(deque_extras)]
/// use std::collections::VecDeque;
///
/// let mut buf = VecDeque::new();
/// buf.push_back(15);
/// buf.resize(2, 0);
/// buf.resize(6, 20);
- /// for (a, b) in [5, 10, 20, 20, 20, 20].iter().zip(buf.iter()) {
+ /// for (a, b) in [5, 10, 20, 20, 20, 20].iter().zip(&buf) {
/// assert_eq!(a, b);
/// }
/// ```
- #[unstable(feature = "collections",
+ #[unstable(feature = "deque_extras",
reason = "matches collection reform specification; waiting on panic semantics")]
pub fn resize(&mut self, new_len: usize, value: T) {
let len = self.len();
impl<'a, T> ExactSizeIterator for Iter<'a, T> {}
#[stable(feature = "rust1", since = "1.0.0")]
+#[allow(deprecated)]
impl<'a, T> RandomAccessIterator for Iter<'a, T> {
#[inline]
fn indexable(&self) -> usize {
impl<T> ExactSizeIterator for IntoIter<T> {}
/// A draining VecDeque iterator
-#[unstable(feature = "collections",
+#[unstable(feature = "drain",
reason = "matches collection reform specification, waiting for dust to settle")]
pub struct Drain<'a, T: 'a> {
inner: &'a mut VecDeque<T>,
impl<A: PartialEq> PartialEq for VecDeque<A> {
fn eq(&self, other: &VecDeque<A>) -> bool {
self.len() == other.len() &&
- self.iter().zip(other.iter()).all(|(a, b)| a.eq(b))
+ self.iter().zip(other).all(|(a, b)| a.eq(b))
}
}
}
}
+#[stable(feature = "extend_ref", since = "1.2.0")]
+impl<'a, T: 'a + Copy> Extend<&'a T> for VecDeque<T> {
+ fn extend<I: IntoIterator<Item=&'a T>>(&mut self, iter: I) {
+ self.extend(iter.into_iter().cloned());
+ }
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: fmt::Debug> fmt::Debug for VecDeque<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
#[cfg(test)]
mod tests {
- use core::iter::{Iterator, self};
+ use core::iter::Iterator;
use core::option::Option::Some;
use test;
//! are O(highest integer key).
#![allow(missing_docs)]
+#![unstable(feature = "vecmap",
+ reason = "may not be stabilized in the standard library")]
use self::Entry::*;
/// # Examples
///
/// ```
-/// # #![feature(collections)]
+/// # #![feature(vecmap)]
/// use std::collections::VecMap;
///
/// let mut months = VecMap::new();
/// assert_eq!(months.get(&3), Some(&"Venus"));
///
/// // Print out all months
-/// for (key, value) in months.iter() {
+/// for (key, value) in &months {
/// println!("month {} is {}", key, value);
/// }
///
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(vecmap)]
/// use std::collections::VecMap;
/// let mut map: VecMap<&str> = VecMap::new();
/// ```
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(vecmap)]
/// use std::collections::VecMap;
/// let mut map: VecMap<&str> = VecMap::with_capacity(10);
/// ```
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(vecmap)]
/// use std::collections::VecMap;
/// let map: VecMap<String> = VecMap::with_capacity(10);
/// assert!(map.capacity() >= 10);
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(vecmap)]
/// use std::collections::VecMap;
/// let mut map: VecMap<&str> = VecMap::new();
/// map.reserve_len(10);
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(vecmap)]
/// use std::collections::VecMap;
/// let mut map: VecMap<&str> = VecMap::new();
/// map.reserve_len_exact(10);
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(vecmap)]
/// use std::collections::VecMap;
///
/// let mut map = VecMap::new();
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(vecmap)]
/// use std::collections::VecMap;
///
/// let mut map = VecMap::new();
/// *value = "x";
/// }
///
- /// for (key, value) in map.iter() {
+ /// for (key, value) in &map {
/// assert_eq!(value, &"x");
/// }
/// ```
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(vecmap, append)]
/// use std::collections::VecMap;
///
/// let mut a = VecMap::new();
/// assert_eq!(a[3], "c");
/// assert_eq!(a[4], "d");
/// ```
- #[unstable(feature = "collections",
+ #[unstable(feature = "append",
reason = "recently added as part of collections reform 2")]
pub fn append(&mut self, other: &mut Self) {
self.extend(other.drain());
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(vecmap, split_off)]
/// use std::collections::VecMap;
///
/// let mut a = VecMap::new();
/// assert_eq!(b[3], "c");
/// assert_eq!(b[4], "d");
/// ```
- #[unstable(feature = "collections",
+ #[unstable(feature = "split_off",
reason = "recently added as part of collections reform 2")]
pub fn split_off(&mut self, at: usize) -> Self {
let mut other = VecMap::new();
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(vecmap, drain)]
/// use std::collections::VecMap;
///
/// let mut map = VecMap::new();
///
/// assert_eq!(vec, [(1, "a"), (2, "b"), (3, "c")]);
/// ```
- #[unstable(feature = "collections",
+ #[unstable(feature = "drain",
reason = "matches collection reform specification, waiting for dust to settle")]
pub fn drain<'a>(&'a mut self) -> Drain<'a, V> {
fn filter<A>((i, v): (usize, Option<A>)) -> Option<(usize, A)> {
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(vecmap)]
/// use std::collections::VecMap;
///
/// let mut a = VecMap::new();
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(vecmap)]
/// use std::collections::VecMap;
///
/// let mut a = VecMap::new();
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(vecmap)]
/// use std::collections::VecMap;
///
/// let mut a = VecMap::new();
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(vecmap)]
/// use std::collections::VecMap;
///
/// let mut map = VecMap::new();
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(vecmap)]
/// use std::collections::VecMap;
///
/// let mut map = VecMap::new();
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(vecmap)]
/// use std::collections::VecMap;
///
/// let mut map = VecMap::new();
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(vecmap)]
/// use std::collections::VecMap;
///
/// let mut map = VecMap::new();
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(vecmap)]
/// use std::collections::VecMap;
///
/// let mut map = VecMap::new();
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(vecmap, entry)]
/// use std::collections::VecMap;
///
/// let mut count: VecMap<u32> = VecMap::new();
impl<'a, V> Entry<'a, V> {
- #[unstable(feature = "collections",
+ #[unstable(feature = "entry",
reason = "will soon be replaced by or_insert")]
#[deprecated(since = "1.0",
reason = "replaced with more ergonomic `or_insert` and `or_insert_with`")]
}
}
- #[unstable(feature = "collections",
- reason = "matches entry v3 specification, waiting for dust to settle")]
- /// Ensures a value is in the entry by inserting the default if empty, and returns
- /// a mutable reference to the value in the entry.
+ #[stable(feature = "vecmap_entry", since = "1.2.0")]
+ /// Ensures a value is in the entry by inserting the default if empty, and
+ /// returns a mutable reference to the value in the entry.
pub fn or_insert(self, default: V) -> &'a mut V {
match self {
Occupied(entry) => entry.into_mut(),
}
}
- #[unstable(feature = "collections",
- reason = "matches entry v3 specification, waiting for dust to settle")]
- /// Ensures a value is in the entry by inserting the result of the default function if empty,
- /// and returns a mutable reference to the value in the entry.
+ #[stable(feature = "vecmap_entry", since = "1.2.0")]
+ /// Ensures a value is in the entry by inserting the result of the default
+ /// function if empty, and returns a mutable reference to the value in the
+ /// entry.
pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V {
match self {
Occupied(entry) => entry.into_mut(),
/// # Examples
///
/// ```
- /// # #![feature(collections)]
+ /// # #![feature(vecmap)]
/// use std::collections::VecMap;
///
/// let mut map = VecMap::new();
}
}
+#[stable(feature = "extend_ref", since = "1.2.0")]
+impl<'a, V: Copy> Extend<(usize, &'a V)> for VecMap<V> {
+ fn extend<I: IntoIterator<Item=(usize, &'a V)>>(&mut self, iter: I) {
+ self.extend(iter.into_iter().map(|(key, &value)| (key, value)));
+ }
+}
+
impl<V> Index<usize> for VecMap<V> {
type Output = V;
fn((usize, Option<V>)) -> Option<(usize, V)>>
}
-#[unstable(feature = "collections")]
+#[unstable(feature = "drain")]
pub struct Drain<'a, V:'a> {
iter: FilterMap<
Enumerate<vec::Drain<'a, Option<V>>>,
fn((usize, Option<V>)) -> Option<(usize, V)>>
}
-#[unstable(feature = "collections")]
+#[unstable(feature = "drain")]
impl<'a, V> Iterator for Drain<'a, V> {
type Item = (usize, V);
fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
}
-#[unstable(feature = "collections")]
+#[unstable(feature = "drain")]
impl<'a, V> DoubleEndedIterator for Drain<'a, V> {
fn next_back(&mut self) -> Option<(usize, V)> { self.iter.next_back() }
}
assert!(q.is_empty());
}
+
+#[test]
+fn test_extend_ref() {
+ let mut a = BinaryHeap::new();
+ a.push(1);
+ a.push(2);
+
+ a.extend(&[3, 4, 5]);
+
+ assert_eq!(a.len(), 5);
+ assert_eq!(a.into_sorted_vec(), [1, 2, 3, 4, 5]);
+
+ let mut a = BinaryHeap::new();
+ a.push(1);
+ a.push(2);
+ let mut b = BinaryHeap::new();
+ b.push(3);
+ b.push(4);
+ b.push(5);
+
+ a.extend(&b);
+
+ assert_eq!(a.len(), 5);
+ assert_eq!(a.into_sorted_vec(), [1, 2, 3, 4, 5]);
+}
0b00101011, 0b10101101])));
}
+#[test]
+fn test_bit_set_extend_ref() {
+ let mut a = BitSet::new();
+ a.insert(3);
+
+ a.extend(&[5, 7, 10]);
+
+ assert_eq!(a.len(), 4);
+ assert_eq!(a, BitSet::from_bit_vec(BitVec::from_bytes(&[0b00010101,0b00100000])));
+
+ let mut b = BitSet::new();
+ b.insert(11);
+ b.insert(15);
+
+ a.extend(&b);
+
+ assert_eq!(a.len(), 6);
+ assert_eq!(a, BitSet::from_bit_vec(BitVec::from_bytes(&[0b00010101,0b00110001])));
+}
+
mod bench {
use std::collections::{BitSet, BitVec};
use std::__rand::{Rng, thread_rng, ThreadRng};
fn test_bit_vec_extend() {
let mut bit_vec = BitVec::from_bytes(&[0b10110110, 0b00000000, 0b11111111]);
let ext = BitVec::from_bytes(&[0b01001001, 0b10010010, 0b10111101]);
- bit_vec.extend(ext.iter());
+ bit_vec.extend(&ext);
assert_eq!(bit_vec, BitVec::from_bytes(&[0b10110110, 0b00000000, 0b11111111,
0b01001001, 0b10010010, 0b10111101]));
}
+#[test]
+fn test_bit_vecextend_ref() {
+ let mut bv = BitVec::from_bytes(&[0b10100011]);
+ bv.extend(&[true, false, true]);
+
+ assert_eq!(bv.len(), 11);
+ assert!(bv.eq_vec(&[true, false, true, false, false, false, true, true,
+ true, false, true]));
+
+ let bw = BitVec::from_bytes(&[0b00010001]);
+ bv.extend(&bw);
+
+ assert_eq!(bv.len(), 19);
+ assert!(bv.eq_vec(&[true, false, true, false, false, false, true, true,
+ true, false, true, false, false, false, true, false,
+ false, false, true]));
+}
+
#[test]
fn test_bit_vec_append() {
// Append to BitVec that holds a multiple of u32::BITS bits
assert_eq!(map.len(), 6);
}
+#[test]
+fn test_extend_ref() {
+ let mut a = BTreeMap::new();
+ a.insert(1, "one");
+ let mut b = BTreeMap::new();
+ b.insert(2, "two");
+ b.insert(3, "three");
+
+ a.extend(&b);
+
+ assert_eq!(a.len(), 3);
+ assert_eq!(a[&1], "one");
+ assert_eq!(a[&2], "two");
+ assert_eq!(a[&3], "three");
+}
+
mod bench {
use std::collections::BTreeMap;
use std::__rand::{Rng, thread_rng};
let x = x;
let y = y;
- let mut z = x.iter().zip(y.iter());
+ let mut z = x.iter().zip(&y);
// FIXME: #5801: this needs a type hint to compile...
let result: Option<(&usize, & &'static str)> = z.next();
assert_eq!(set_str, "{1, 2}");
assert_eq!(format!("{:?}", empty), "{}");
}
+
+#[test]
+fn test_extend_ref() {
+ let mut a = BTreeSet::new();
+ a.insert(1);
+
+ a.extend(&[2, 3, 4]);
+
+ assert_eq!(a.len(), 4);
+ assert!(a.contains(&1));
+ assert!(a.contains(&2));
+ assert!(a.contains(&3));
+ assert!(a.contains(&4));
+
+ let mut b = BTreeSet::new();
+ b.insert(5);
+ b.insert(6);
+
+ a.extend(&b);
+
+ assert_eq!(a.len(), 6);
+ assert!(a.contains(&1));
+ assert!(a.contains(&2));
+ assert!(a.contains(&3));
+ assert!(a.contains(&4));
+ assert!(a.contains(&5));
+ assert!(a.contains(&6));
+}
let mut set = EnumSet::new();
set.insert(Bar::V64);
}
+
+#[test]
+fn test_extend_ref() {
+ let mut a = EnumSet::new();
+ a.insert(A);
+
+ a.extend(&[A, C]);
+
+ assert_eq!(a.len(), 2);
+ assert!(a.contains(&A));
+ assert!(a.contains(&C));
+
+ let mut b = EnumSet::new();
+ b.insert(B);
+
+ a.extend(&b);
+
+ assert_eq!(a.len(), 3);
+ assert!(a.contains(&A));
+ assert!(a.contains(&B));
+ assert!(a.contains(&C));
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(bit_set_append_split_off)]
+#![feature(append)]
#![feature(bit_vec_append_split_off)]
+#![feature(bitset)]
+#![feature(bitvec)]
#![feature(box_syntax)]
+#![feature(btree_range)]
#![feature(collections)]
-#![feature(collections_drain)]
+#![feature(collections_bound)]
+#![feature(const_fn)]
#![feature(core)]
-#![feature(hash)]
+#![feature(deque_extras)]
+#![feature(drain)]
+#![feature(enumset)]
+#![feature(hash_default)]
+#![feature(into_cow)]
+#![feature(iter_idx)]
+#![feature(iter_order)]
+#![feature(iter_arith)]
+#![feature(iter_to_vec)]
+#![feature(map_in_place)]
+#![feature(move_from)]
+#![feature(num_bits_bytes)]
+#![feature(pattern)]
+#![feature(permutations)]
#![feature(rand)]
+#![feature(range_inclusive)]
#![feature(rustc_private)]
+#![feature(slice_bytes)]
+#![feature(slice_chars)]
+#![feature(slice_extras)]
+#![feature(slice_position_elem)]
+#![feature(split_off)]
+#![feature(step_by)]
+#![feature(str_char)]
+#![feature(str_escape)]
+#![feature(str_match_indices)]
+#![feature(str_utf16)]
+#![feature(subslice_offset)]
#![feature(test)]
#![feature(unboxed_closures)]
#![feature(unicode)]
-#![feature(into_cow)]
-#![feature(step_by)]
-#![cfg_attr(test, feature(str_char))]
-#![cfg_attr(test, feature(vec_deque_retain))]
+#![feature(vec_deque_retain)]
+#![feature(vec_from_raw_buf)]
+#![feature(vec_push_all)]
+#![feature(vec_split_off)]
+#![feature(vecmap)]
#[macro_use] extern crate log;
assert_eq!(format!("{:?}", list), "[\"just\", \"one\", \"test\", \"more\"]");
}
+#[test]
+fn test_extend_ref() {
+ let mut a = LinkedList::new();
+ a.push_back(1);
+
+ a.extend(&[2, 3, 4]);
+
+ assert_eq!(a.len(), 4);
+ assert_eq!(a, list_from(&[1, 2, 3, 4]));
+
+ let mut b = LinkedList::new();
+ b.push_back(5);
+ b.push_back(6);
+ a.extend(&b);
+
+ assert_eq!(a.len(), 6);
+ assert_eq!(a, list_from(&[1, 2, 3, 4, 5, 6]));
+}
+
#[bench]
fn bench_collect_into(b: &mut test::Bencher) {
let v = &[0; 64];
// except according to those terms.
use std::cmp::Ordering::{Equal, Greater, Less};
-use std::str::{Utf8Error, from_utf8};
+use std::str::from_utf8;
#[test]
fn test_le() {
#[test]
fn test_collect() {
- let empty = String::from_str("");
+ let empty = String::from("");
let s: String = empty.chars().collect();
assert_eq!(empty, s);
- let data = String::from_str("ประเทศไทย中");
+ let data = String::from("ประเทศไทย中");
let s: String = data.chars().collect();
assert_eq!(data, s);
}
#[test]
fn test_into_bytes() {
- let data = String::from_str("asdf");
+ let data = String::from("asdf");
let buf = data.into_bytes();
assert_eq!(buf, b"asdf");
}
assert!(data[2..4].find("ab").is_none());
let string = "ประเทศไทย中华Việt Nam";
- let mut data = String::from_str(string);
+ let mut data = String::from(string);
data.push_str(string);
assert!(data.find("ไท华").is_none());
assert_eq!(data[0..43].find(""), Some(0));
}
let letters = a_million_letter_a();
assert!(half_a_million_letter_a() ==
- unsafe {String::from_str(letters.slice_unchecked(
+ unsafe {String::from(letters.slice_unchecked(
0,
500000))});
}
#[test]
fn test_replace() {
let a = "a";
- assert_eq!("".replace(a, "b"), String::from_str(""));
- assert_eq!("a".replace(a, "b"), String::from_str("b"));
- assert_eq!("ab".replace(a, "b"), String::from_str("bb"));
+ assert_eq!("".replace(a, "b"), String::from(""));
+ assert_eq!("a".replace(a, "b"), String::from("b"));
+ assert_eq!("ab".replace(a, "b"), String::from("bb"));
let test = "test";
assert!(" test test ".replace(test, "toast") ==
- String::from_str(" toast toast "));
- assert_eq!(" test test ".replace(test, ""), String::from_str(" "));
+ String::from(" toast toast "));
+ assert_eq!(" test test ".replace(test, ""), String::from(" "));
}
#[test]
}
let letters = a_million_letter_x();
assert!(half_a_million_letter_x() ==
- String::from_str(&letters[0..3 * 500000]));
+ String::from(&letters[0..3 * 500000]));
}
#[test]
fn test_as_bytes_fail() {
// Don't double free. (I'm not sure if this exercises the
// original problem code path anymore.)
- let s = String::from_str("");
+ let s = String::from("");
let _bytes = s.as_bytes();
panic!();
}
#[test]
fn vec_str_conversions() {
- let s1: String = String::from_str("All mimsy were the borogoves");
+ let s1: String = String::from("All mimsy were the borogoves");
let v: Vec<u8> = s1.as_bytes().to_vec();
- let s2: String = String::from_str(from_utf8(&v).unwrap());
+ let s2: String = String::from(from_utf8(&v).unwrap());
let mut i = 0;
let n1 = s1.len();
let n2 = v.len();
}
}
+#[test]
+fn test_split_at() {
+ let s = "ศไทย中华Việt Nam";
+ for (index, _) in s.char_indices() {
+ let (a, b) = s.split_at(index);
+ assert_eq!(&s[..a.len()], a);
+ assert_eq!(&s[a.len()..], b);
+ }
+ let (a, b) = s.split_at(s.len());
+ assert_eq!(a, s);
+ assert_eq!(b, "");
+}
+
+#[test]
+#[should_panic]
+fn test_split_at_boundscheck() {
+ let s = "ศไทย中华Việt Nam";
+ let (a, b) = s.split_at(1);
+}
+
#[test]
fn test_escape_unicode() {
assert_eq!("abc".escape_unicode(),
- String::from_str("\\u{61}\\u{62}\\u{63}"));
+ String::from("\\u{61}\\u{62}\\u{63}"));
assert_eq!("a c".escape_unicode(),
- String::from_str("\\u{61}\\u{20}\\u{63}"));
+ String::from("\\u{61}\\u{20}\\u{63}"));
assert_eq!("\r\n\t".escape_unicode(),
- String::from_str("\\u{d}\\u{a}\\u{9}"));
+ String::from("\\u{d}\\u{a}\\u{9}"));
assert_eq!("'\"\\".escape_unicode(),
- String::from_str("\\u{27}\\u{22}\\u{5c}"));
+ String::from("\\u{27}\\u{22}\\u{5c}"));
assert_eq!("\x00\x01\u{fe}\u{ff}".escape_unicode(),
- String::from_str("\\u{0}\\u{1}\\u{fe}\\u{ff}"));
+ String::from("\\u{0}\\u{1}\\u{fe}\\u{ff}"));
assert_eq!("\u{100}\u{ffff}".escape_unicode(),
- String::from_str("\\u{100}\\u{ffff}"));
+ String::from("\\u{100}\\u{ffff}"));
assert_eq!("\u{10000}\u{10ffff}".escape_unicode(),
- String::from_str("\\u{10000}\\u{10ffff}"));
+ String::from("\\u{10000}\\u{10ffff}"));
assert_eq!("ab\u{fb00}".escape_unicode(),
- String::from_str("\\u{61}\\u{62}\\u{fb00}"));
+ String::from("\\u{61}\\u{62}\\u{fb00}"));
assert_eq!("\u{1d4ea}\r".escape_unicode(),
- String::from_str("\\u{1d4ea}\\u{d}"));
+ String::from("\\u{1d4ea}\\u{d}"));
}
#[test]
fn test_escape_default() {
- assert_eq!("abc".escape_default(), String::from_str("abc"));
- assert_eq!("a c".escape_default(), String::from_str("a c"));
- assert_eq!("\r\n\t".escape_default(), String::from_str("\\r\\n\\t"));
- assert_eq!("'\"\\".escape_default(), String::from_str("\\'\\\"\\\\"));
+ assert_eq!("abc".escape_default(), String::from("abc"));
+ assert_eq!("a c".escape_default(), String::from("a c"));
+ assert_eq!("\r\n\t".escape_default(), String::from("\\r\\n\\t"));
+ assert_eq!("'\"\\".escape_default(), String::from("\\'\\\"\\\\"));
assert_eq!("\u{100}\u{ffff}".escape_default(),
- String::from_str("\\u{100}\\u{ffff}"));
+ String::from("\\u{100}\\u{ffff}"));
assert_eq!("\u{10000}\u{10ffff}".escape_default(),
- String::from_str("\\u{10000}\\u{10ffff}"));
+ String::from("\\u{10000}\\u{10ffff}"));
assert_eq!("ab\u{fb00}".escape_default(),
- String::from_str("ab\\u{fb00}"));
+ String::from("ab\\u{fb00}"));
assert_eq!("\u{1d4ea}\r".escape_default(),
- String::from_str("\\u{1d4ea}\\r"));
+ String::from("\\u{1d4ea}\\r"));
}
#[test]
v.iter().map(|x| x.len()).sum()
}
- let s = String::from_str("01234");
+ let s = String::from("01234");
assert_eq!(5, sum_len(&["012", "", "34"]));
- assert_eq!(5, sum_len(&[&String::from_str("01"),
- &String::from_str("2"),
- &String::from_str("34"),
- &String::from_str("")]));
+ assert_eq!(5, sum_len(&[&String::from("01"),
+ &String::from("2"),
+ &String::from("34"),
+ &String::from("")]));
assert_eq!(5, sum_len(&[&s]));
}
"");
}
+#[test]
+fn to_lowercase() {
+ assert_eq!("".to_lowercase(), "");
+ assert_eq!("AÉDžaé ".to_lowercase(), "aédžaé ");
+
+ // https://github.com/rust-lang/rust/issues/26035
+ assert_eq!("ΑΣ".to_lowercase(), "ας");
+ assert_eq!("Α'Σ".to_lowercase(), "α'ς");
+ assert_eq!("Α''Σ".to_lowercase(), "α''ς");
+
+ assert_eq!("ΑΣ Α".to_lowercase(), "ας α");
+ assert_eq!("Α'Σ Α".to_lowercase(), "α'ς α");
+ assert_eq!("Α''Σ Α".to_lowercase(), "α''ς α");
+
+ assert_eq!("ΑΣ' Α".to_lowercase(), "ας' α");
+ assert_eq!("ΑΣ'' Α".to_lowercase(), "ας'' α");
+
+ assert_eq!("Α'Σ' Α".to_lowercase(), "α'ς' α");
+ assert_eq!("Α''Σ'' Α".to_lowercase(), "α''ς'' α");
+
+ assert_eq!("Α Σ".to_lowercase(), "α σ");
+ assert_eq!("Α 'Σ".to_lowercase(), "α 'σ");
+ assert_eq!("Α ''Σ".to_lowercase(), "α ''σ");
+
+ assert_eq!("Σ".to_lowercase(), "σ");
+ assert_eq!("'Σ".to_lowercase(), "'σ");
+ assert_eq!("''Σ".to_lowercase(), "''σ");
+
+ assert_eq!("ΑΣΑ".to_lowercase(), "ασα");
+ assert_eq!("ΑΣ'Α".to_lowercase(), "ασ'α");
+ assert_eq!("ΑΣ''Α".to_lowercase(), "ασ''α");
+}
+
+#[test]
+fn to_uppercase() {
+ assert_eq!("".to_uppercase(), "");
+ assert_eq!("aéDžßfiᾀ".to_uppercase(), "AÉDŽSSFIἈΙ");
+}
+
mod pattern {
use std::str::pattern::Pattern;
use std::str::pattern::{Searcher, ReverseSearcher};
macro_rules! make_test {
($name:ident, $p:expr, $h:expr, [$($e:expr,)*]) => {
+ #[allow(unused_imports)]
mod $name {
use std::str::pattern::SearchStep::{Match, Reject};
use super::{cmp_search_to_vec};
use std::borrow::{IntoCow, Cow};
use std::iter::repeat;
-use std::str::Utf8Error;
+#[allow(deprecated)]
use std::string::as_string;
use test::Bencher;
#[test]
+#[allow(deprecated)]
fn test_as_string() {
let x = "foo";
assert_eq!(x, &**as_string(x));
fn test_from_utf8() {
let xs = b"hello".to_vec();
assert_eq!(String::from_utf8(xs).unwrap(),
- String::from_str("hello"));
+ String::from("hello"));
let xs = "ศไทย中华Việt Nam".as_bytes().to_vec();
assert_eq!(String::from_utf8(xs).unwrap(),
- String::from_str("ศไทย中华Việt Nam"));
+ String::from("ศไทย中华Việt Nam"));
let xs = b"hello\xFF".to_vec();
let err = String::from_utf8(xs).err().unwrap();
let xs = b"Hello\xC2 There\xFF Goodbye";
assert_eq!(String::from_utf8_lossy(xs),
- String::from_str("Hello\u{FFFD} There\u{FFFD} Goodbye").into_cow());
+ String::from("Hello\u{FFFD} There\u{FFFD} Goodbye").into_cow());
let xs = b"Hello\xC0\x80 There\xE6\x83 Goodbye";
assert_eq!(String::from_utf8_lossy(xs),
- String::from_str("Hello\u{FFFD}\u{FFFD} There\u{FFFD} Goodbye").into_cow());
+ String::from("Hello\u{FFFD}\u{FFFD} There\u{FFFD} Goodbye").into_cow());
let xs = b"\xF5foo\xF5\x80bar";
assert_eq!(String::from_utf8_lossy(xs),
- String::from_str("\u{FFFD}foo\u{FFFD}\u{FFFD}bar").into_cow());
+ String::from("\u{FFFD}foo\u{FFFD}\u{FFFD}bar").into_cow());
let xs = b"\xF1foo\xF1\x80bar\xF1\x80\x80baz";
assert_eq!(String::from_utf8_lossy(xs),
- String::from_str("\u{FFFD}foo\u{FFFD}bar\u{FFFD}baz").into_cow());
+ String::from("\u{FFFD}foo\u{FFFD}bar\u{FFFD}baz").into_cow());
let xs = b"\xF4foo\xF4\x80bar\xF4\xBFbaz";
assert_eq!(String::from_utf8_lossy(xs),
- String::from_str("\u{FFFD}foo\u{FFFD}bar\u{FFFD}\u{FFFD}baz").into_cow());
+ String::from("\u{FFFD}foo\u{FFFD}bar\u{FFFD}\u{FFFD}baz").into_cow());
let xs = b"\xF0\x80\x80\x80foo\xF0\x90\x80\x80bar";
- assert_eq!(String::from_utf8_lossy(xs), String::from_str("\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\
+ assert_eq!(String::from_utf8_lossy(xs), String::from("\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}\
foo\u{10000}bar").into_cow());
// surrogates
let xs = b"\xED\xA0\x80foo\xED\xBF\xBFbar";
- assert_eq!(String::from_utf8_lossy(xs), String::from_str("\u{FFFD}\u{FFFD}\u{FFFD}foo\
+ assert_eq!(String::from_utf8_lossy(xs), String::from("\u{FFFD}\u{FFFD}\u{FFFD}foo\
\u{FFFD}\u{FFFD}\u{FFFD}bar").into_cow());
}
#[test]
fn test_from_utf16() {
let pairs =
- [(String::from_str("𐍅𐌿𐌻𐍆𐌹𐌻𐌰\n"),
+ [(String::from("𐍅𐌿𐌻𐍆𐌹𐌻𐌰\n"),
vec![0xd800, 0xdf45, 0xd800, 0xdf3f,
0xd800, 0xdf3b, 0xd800, 0xdf46,
0xd800, 0xdf39, 0xd800, 0xdf3b,
0xd800, 0xdf30, 0x000a]),
- (String::from_str("𐐒𐑉𐐮𐑀𐐲𐑋 𐐏𐐲𐑍\n"),
+ (String::from("𐐒𐑉𐐮𐑀𐐲𐑋 𐐏𐐲𐑍\n"),
vec![0xd801, 0xdc12, 0xd801,
0xdc49, 0xd801, 0xdc2e, 0xd801,
0xdc40, 0xd801, 0xdc32, 0xd801,
0xd801, 0xdc32, 0xd801, 0xdc4d,
0x000a]),
- (String::from_str("𐌀𐌖𐌋𐌄𐌑𐌉·𐌌𐌄𐌕𐌄𐌋𐌉𐌑\n"),
+ (String::from("𐌀𐌖𐌋𐌄𐌑𐌉·𐌌𐌄𐌕𐌄𐌋𐌉𐌑\n"),
vec![0xd800, 0xdf00, 0xd800, 0xdf16,
0xd800, 0xdf0b, 0xd800, 0xdf04,
0xd800, 0xdf11, 0xd800, 0xdf09,
0xdf04, 0xd800, 0xdf0b, 0xd800,
0xdf09, 0xd800, 0xdf11, 0x000a ]),
- (String::from_str("𐒋𐒘𐒈𐒑𐒛𐒒 𐒕𐒓 𐒈𐒚𐒍 𐒏𐒜𐒒𐒖𐒆 𐒕𐒆\n"),
+ (String::from("𐒋𐒘𐒈𐒑𐒛𐒒 𐒕𐒓 𐒈𐒚𐒍 𐒏𐒜𐒒𐒖𐒆 𐒕𐒆\n"),
vec![0xd801, 0xdc8b, 0xd801, 0xdc98,
0xd801, 0xdc88, 0xd801, 0xdc91,
0xd801, 0xdc9b, 0xd801, 0xdc92,
0xd801, 0xdc95, 0xd801, 0xdc86,
0x000a ]),
// Issue #12318, even-numbered non-BMP planes
- (String::from_str("\u{20000}"),
+ (String::from("\u{20000}"),
vec![0xD840, 0xDC00])];
for p in &pairs {
fn test_from_utf16_lossy() {
// completely positive cases tested above.
// lead + eof
- assert_eq!(String::from_utf16_lossy(&[0xD800]), String::from_str("\u{FFFD}"));
+ assert_eq!(String::from_utf16_lossy(&[0xD800]), String::from("\u{FFFD}"));
// lead + lead
assert_eq!(String::from_utf16_lossy(&[0xD800, 0xD800]),
- String::from_str("\u{FFFD}\u{FFFD}"));
+ String::from("\u{FFFD}\u{FFFD}"));
// isolated trail
- assert_eq!(String::from_utf16_lossy(&[0x0061, 0xDC00]), String::from_str("a\u{FFFD}"));
+ assert_eq!(String::from_utf16_lossy(&[0x0061, 0xDC00]), String::from("a\u{FFFD}"));
// general
assert_eq!(String::from_utf16_lossy(&[0xD800, 0xd801, 0xdc8b, 0xD800]),
- String::from_str("\u{FFFD}𐒋\u{FFFD}"));
+ String::from("\u{FFFD}𐒋\u{FFFD}"));
}
#[test]
fn test_push_bytes() {
- let mut s = String::from_str("ABC");
+ let mut s = String::from("ABC");
unsafe {
let mv = s.as_mut_vec();
mv.push_all(&[b'D']);
#[test]
fn test_push() {
- let mut data = String::from_str("ประเทศไทย中");
+ let mut data = String::from("ประเทศไทย中");
data.push('华');
data.push('b'); // 1 byte
data.push('¢'); // 2 byte
#[test]
fn test_pop() {
- let mut data = String::from_str("ประเทศไทย中华b¢€𤭢");
+ let mut data = String::from("ประเทศไทย中华b¢€𤭢");
assert_eq!(data.pop().unwrap(), '𤭢'); // 4 bytes
assert_eq!(data.pop().unwrap(), '€'); // 3 bytes
assert_eq!(data.pop().unwrap(), '¢'); // 2 bytes
#[test]
fn test_str_truncate() {
- let mut s = String::from_str("12345");
+ let mut s = String::from("12345");
s.truncate(5);
assert_eq!(s, "12345");
s.truncate(3);
s.truncate(0);
assert_eq!(s, "");
- let mut s = String::from_str("12345");
+ let mut s = String::from("12345");
let p = s.as_ptr();
s.truncate(3);
s.push_str("6");
#[test]
#[should_panic]
fn test_str_truncate_invalid_len() {
- let mut s = String::from_str("12345");
+ let mut s = String::from("12345");
s.truncate(6);
}
#[test]
#[should_panic]
fn test_str_truncate_split_codepoint() {
- let mut s = String::from_str("\u{FC}"); // ü
+ let mut s = String::from("\u{FC}"); // ü
s.truncate(1);
}
#[test]
fn test_str_clear() {
- let mut s = String::from_str("12345");
+ let mut s = String::from("12345");
s.clear();
assert_eq!(s.len(), 0);
assert_eq!(s, "");
#[test]
fn test_str_add() {
- let a = String::from_str("12345");
+ let a = String::from("12345");
let b = a + "2";
let b = b + "2";
assert_eq!(b.len(), 7);
assert_eq!(s, c);
let mut d = t.to_string();
- d.extend(vec![u].into_iter());
+ d.extend(vec![u]);
assert_eq!(s, d);
}
assert_eq!(t, "");
}
+#[test]
+fn test_extend_ref() {
+ let mut a = "foo".to_string();
+ a.extend(&['b', 'a', 'r']);
+
+ assert_eq!(&a, "foobar");
+}
+
#[bench]
fn bench_with_capacity(b: &mut Bencher) {
b.iter(|| {
let s = "Hello there, the quick brown fox jumped over the lazy dog! \
Lorem ipsum dolor sit amet, consectetur. ";
b.iter(|| {
- String::from_str(s)
+ String::from(s)
})
}
use std::iter::{FromIterator, repeat};
use std::mem::size_of;
+#[allow(deprecated)]
use std::vec::as_vec;
use test::Bencher;
}
#[test]
+#[allow(deprecated)]
fn test_as_vec() {
let xs = [1u8, 2u8, 3u8];
assert_eq!(&**as_vec(&xs), xs);
}
#[test]
+#[allow(deprecated)]
fn test_as_vec_dtor() {
let (mut count_x, mut count_y) = (0, 0);
{
assert_eq!(v, w);
}
+#[test]
+fn test_extend_ref() {
+ let mut v = vec![1, 2];
+ v.extend(&[3, 4, 5]);
+
+ assert_eq!(v.len(), 5);
+ assert_eq!(v, [1, 2, 3, 4, 5]);
+
+ let w = vec![6, 7];
+ v.extend(&w);
+
+ assert_eq!(v.len(), 7);
+ assert_eq!(v, [1, 2, 3, 4, 5, 6, 7]);
+}
+
#[test]
fn test_slice_from_mut() {
let mut values = vec![1, 2, 3, 4, 5];
#[test]
fn test_map_in_place_zero_drop_count() {
- use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
+ use std::sync::atomic::{AtomicUsize, Ordering};
#[derive(Clone, PartialEq, Debug)]
struct Nothing;
}
}
const NUM_ELEMENTS: usize = 2;
- static DROP_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT;
+ static DROP_COUNTER: AtomicUsize = AtomicUsize::new(0);
let v = repeat(Nothing).take(NUM_ELEMENTS).collect::<Vec<_>>();
b.bytes = src_len as u64;
b.iter(|| {
- let dst: Vec<_> = FromIterator::from_iter(src.clone().into_iter());
+ let dst: Vec<_> = FromIterator::from_iter(src.clone());
assert_eq!(dst.len(), src_len);
assert!(dst.iter().enumerate().all(|(i, x)| i == *x));
});
b.iter(|| {
let mut dst = dst.clone();
- dst.extend(src.clone().into_iter());
+ dst.extend(src.clone());
assert_eq!(dst.len(), dst_len + src_len);
assert!(dst.iter().enumerate().all(|(i, x)| i == *x));
});
b.iter(|| {
let mut dst = dst.clone();
- dst.extend(src.clone().into_iter());
+ dst.extend(src.clone());
assert_eq!(dst.len(), dst_len + src_len);
assert!(dst.iter().enumerate().all(|(i, x)| i == *x));
});
#[test]
fn test_from_iter() {
- use std::iter;
-
let v = vec!(1,2,3,4,5,6,7);
let deq: VecDeque<_> = v.iter().cloned().collect();
let u: Vec<_> = deq.iter().cloned().collect();
let v: Vec<_> = buf.into_iter().collect();
assert_eq!(&v[..], &[2, 4]);
}
+
+#[test]
+fn test_extend_ref() {
+ let mut v = VecDeque::new();
+ v.push_back(1);
+ v.extend(&[2, 3, 4]);
+
+ assert_eq!(v.len(), 4);
+ assert_eq!(v[0], 1);
+ assert_eq!(v[1], 2);
+ assert_eq!(v[2], 3);
+ assert_eq!(v[3], 4);
+
+ let mut w = VecDeque::new();
+ w.push_back(5);
+ w.push_back(6);
+ v.extend(&w);
+
+ assert_eq!(v.len(), 6);
+ assert_eq!(v[0], 1);
+ assert_eq!(v[1], 2);
+ assert_eq!(v[2], 3);
+ assert_eq!(v[3], 4);
+ assert_eq!(v[4], 5);
+ assert_eq!(v[5], 6);
+}
assert_eq!(map.len(), 6);
}
+#[test]
+fn test_extend_ref() {
+ let mut a = VecMap::new();
+ a.insert(1, "one");
+ let mut b = VecMap::new();
+ b.insert(2, "two");
+ b.insert(3, "three");
+
+ a.extend(&b);
+
+ assert_eq!(a.len(), 3);
+ assert_eq!(a[&1], "one");
+ assert_eq!(a[&2], "two");
+ assert_eq!(a[&3], "three");
+}
+
mod bench {
use std::collections::VecMap;
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Any: Reflect + 'static {
/// Gets the `TypeId` of `self`.
- #[unstable(feature = "core",
+ #[unstable(feature = "get_type_id",
reason = "this method will likely be replaced by an associated static")]
fn get_type_id(&self) -> TypeId;
}
//! up to a certain length. Eventually we should able to generalize
//! to all lengths.
-#![unstable(feature = "core")] // not yet reviewed
-
#![doc(primitive = "array")]
+#![unstable(feature = "fixed_size_array",
+ reason = "traits and impls are better expressed through generic \
+ integer constants")]
use clone::Clone;
use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering};
///
/// This trait can be used to implement other traits on fixed-size arrays
/// without causing much metadata bloat.
-#[unstable(feature = "core")]
pub trait FixedSizeArray<T> {
/// Converts the array to immutable slice
fn as_slice(&self) -> &[T];
macro_rules! array_impls {
($($N:expr)+) => {
$(
- #[unstable(feature = "core")]
impl<T> FixedSizeArray<T> for [T; $N] {
#[inline]
fn as_slice(&self) -> &[T] {
}
}
- #[unstable(feature = "array_as_ref",
- reason = "should ideally be implemented for all fixed-sized arrays")]
impl<T> AsRef<[T]> for [T; $N] {
#[inline]
fn as_ref(&self) -> &[T] {
}
}
- #[unstable(feature = "array_as_ref",
- reason = "should ideally be implemented for all fixed-sized arrays")]
impl<T> AsMut<[T]> for [T; $N] {
#[inline]
fn as_mut(&mut self) -> &mut [T] {
use intrinsics;
use cell::UnsafeCell;
-use marker::PhantomData;
use default::Default;
}
impl Default for AtomicBool {
- fn default() -> AtomicBool {
- ATOMIC_BOOL_INIT
+ fn default() -> Self {
+ Self::new(Default::default())
}
}
}
impl Default for AtomicIsize {
- fn default() -> AtomicIsize {
- ATOMIC_ISIZE_INIT
+ fn default() -> Self {
+ Self::new(Default::default())
}
}
}
impl Default for AtomicUsize {
- fn default() -> AtomicUsize {
- ATOMIC_USIZE_INIT
+ fn default() -> Self {
+ Self::new(Default::default())
}
}
/// A raw pointer type which can be safely shared between threads.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct AtomicPtr<T> {
- p: UnsafeCell<usize>,
- _marker: PhantomData<*mut T>,
+ p: UnsafeCell<*mut T>,
}
impl<T> Default for AtomicPtr<T> {
/// An `AtomicBool` initialized to `false`.
#[stable(feature = "rust1", since = "1.0.0")]
-pub const ATOMIC_BOOL_INIT: AtomicBool =
- AtomicBool { v: UnsafeCell { value: 0 } };
+pub const ATOMIC_BOOL_INIT: AtomicBool = AtomicBool::new(false);
/// An `AtomicIsize` initialized to `0`.
#[stable(feature = "rust1", since = "1.0.0")]
-pub const ATOMIC_ISIZE_INIT: AtomicIsize =
- AtomicIsize { v: UnsafeCell { value: 0 } };
+pub const ATOMIC_ISIZE_INIT: AtomicIsize = AtomicIsize::new(0);
/// An `AtomicUsize` initialized to `0`.
#[stable(feature = "rust1", since = "1.0.0")]
-pub const ATOMIC_USIZE_INIT: AtomicUsize =
- AtomicUsize { v: UnsafeCell { value: 0, } };
+pub const ATOMIC_USIZE_INIT: AtomicUsize = AtomicUsize::new(0);
// NB: Needs to be -1 (0b11111111...) to make fetch_nand work correctly
const UINT_TRUE: usize = !0;
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn new(v: bool) -> AtomicBool {
- let val = if v { UINT_TRUE } else { 0 };
- AtomicBool { v: UnsafeCell::new(val) }
+ pub const fn new(v: bool) -> AtomicBool {
+ AtomicBool { v: UnsafeCell::new(-(v as isize) as usize) }
}
/// Loads a value from the bool.
///
/// let some_bool = AtomicBool::new(true);
///
- /// let value = some_bool.load(Ordering::Relaxed);
+ /// assert_eq!(some_bool.load(Ordering::Relaxed), true);
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
/// let some_bool = AtomicBool::new(true);
///
/// some_bool.store(false, Ordering::Relaxed);
+ /// assert_eq!(some_bool.load(Ordering::Relaxed), false);
/// ```
///
/// # Panics
///
/// let some_bool = AtomicBool::new(true);
///
- /// let value = some_bool.swap(false, Ordering::Relaxed);
+ /// assert_eq!(some_bool.swap(false, Ordering::Relaxed), true);
+ /// assert_eq!(some_bool.load(Ordering::Relaxed), false);
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
///
/// let some_bool = AtomicBool::new(true);
///
- /// let value = some_bool.store(false, Ordering::Relaxed);
+ /// assert_eq!(some_bool.compare_and_swap(true, false, Ordering::Relaxed), true);
+ /// assert_eq!(some_bool.load(Ordering::Relaxed), false);
+ ///
+ /// assert_eq!(some_bool.compare_and_swap(true, true, Ordering::Relaxed), false);
+ /// assert_eq!(some_bool.load(Ordering::Relaxed), false);
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
/// use std::sync::atomic::{AtomicBool, Ordering};
///
/// let foo = AtomicBool::new(true);
- /// assert_eq!(true, foo.fetch_and(false, Ordering::SeqCst));
- /// assert_eq!(false, foo.load(Ordering::SeqCst));
+ /// assert_eq!(foo.fetch_and(false, Ordering::SeqCst), true);
+ /// assert_eq!(foo.load(Ordering::SeqCst), false);
///
/// let foo = AtomicBool::new(true);
- /// assert_eq!(true, foo.fetch_and(true, Ordering::SeqCst));
- /// assert_eq!(true, foo.load(Ordering::SeqCst));
+ /// assert_eq!(foo.fetch_and(true, Ordering::SeqCst), true);
+ /// assert_eq!(foo.load(Ordering::SeqCst), true);
///
/// let foo = AtomicBool::new(false);
- /// assert_eq!(false, foo.fetch_and(false, Ordering::SeqCst));
- /// assert_eq!(false, foo.load(Ordering::SeqCst));
+ /// assert_eq!(foo.fetch_and(false, Ordering::SeqCst), false);
+ /// assert_eq!(foo.load(Ordering::SeqCst), false);
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
/// use std::sync::atomic::{AtomicBool, Ordering};
///
/// let foo = AtomicBool::new(true);
- /// assert_eq!(true, foo.fetch_nand(false, Ordering::SeqCst));
- /// assert_eq!(true, foo.load(Ordering::SeqCst));
+ /// assert_eq!(foo.fetch_nand(false, Ordering::SeqCst), true);
+ /// assert_eq!(foo.load(Ordering::SeqCst), true);
///
/// let foo = AtomicBool::new(true);
- /// assert_eq!(true, foo.fetch_nand(true, Ordering::SeqCst));
- /// assert_eq!(0, foo.load(Ordering::SeqCst) as usize);
- /// assert_eq!(false, foo.load(Ordering::SeqCst));
+ /// assert_eq!(foo.fetch_nand(true, Ordering::SeqCst), true);
+ /// assert_eq!(foo.load(Ordering::SeqCst) as usize, 0);
+ /// assert_eq!(foo.load(Ordering::SeqCst), false);
///
/// let foo = AtomicBool::new(false);
- /// assert_eq!(false, foo.fetch_nand(false, Ordering::SeqCst));
- /// assert_eq!(true, foo.load(Ordering::SeqCst));
+ /// assert_eq!(foo.fetch_nand(false, Ordering::SeqCst), false);
+ /// assert_eq!(foo.load(Ordering::SeqCst), true);
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
/// use std::sync::atomic::{AtomicBool, Ordering};
///
/// let foo = AtomicBool::new(true);
- /// assert_eq!(true, foo.fetch_or(false, Ordering::SeqCst));
- /// assert_eq!(true, foo.load(Ordering::SeqCst));
+ /// assert_eq!(foo.fetch_or(false, Ordering::SeqCst), true);
+ /// assert_eq!(foo.load(Ordering::SeqCst), true);
///
/// let foo = AtomicBool::new(true);
- /// assert_eq!(true, foo.fetch_or(true, Ordering::SeqCst));
- /// assert_eq!(true, foo.load(Ordering::SeqCst));
+ /// assert_eq!(foo.fetch_or(true, Ordering::SeqCst), true);
+ /// assert_eq!(foo.load(Ordering::SeqCst), true);
///
/// let foo = AtomicBool::new(false);
- /// assert_eq!(false, foo.fetch_or(false, Ordering::SeqCst));
- /// assert_eq!(false, foo.load(Ordering::SeqCst));
+ /// assert_eq!(foo.fetch_or(false, Ordering::SeqCst), false);
+ /// assert_eq!(foo.load(Ordering::SeqCst), false);
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
/// use std::sync::atomic::{AtomicBool, Ordering};
///
/// let foo = AtomicBool::new(true);
- /// assert_eq!(true, foo.fetch_xor(false, Ordering::SeqCst));
- /// assert_eq!(true, foo.load(Ordering::SeqCst));
+ /// assert_eq!(foo.fetch_xor(false, Ordering::SeqCst), true);
+ /// assert_eq!(foo.load(Ordering::SeqCst), true);
///
/// let foo = AtomicBool::new(true);
- /// assert_eq!(true, foo.fetch_xor(true, Ordering::SeqCst));
- /// assert_eq!(false, foo.load(Ordering::SeqCst));
+ /// assert_eq!(foo.fetch_xor(true, Ordering::SeqCst), true);
+ /// assert_eq!(foo.load(Ordering::SeqCst), false);
///
/// let foo = AtomicBool::new(false);
- /// assert_eq!(false, foo.fetch_xor(false, Ordering::SeqCst));
- /// assert_eq!(false, foo.load(Ordering::SeqCst));
+ /// assert_eq!(foo.fetch_xor(false, Ordering::SeqCst), false);
+ /// assert_eq!(foo.load(Ordering::SeqCst), false);
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn new(v: isize) -> AtomicIsize {
+ pub const fn new(v: isize) -> AtomicIsize {
AtomicIsize {v: UnsafeCell::new(v)}
}
///
/// let some_isize = AtomicIsize::new(5);
///
- /// let value = some_isize.load(Ordering::Relaxed);
+ /// assert_eq!(some_isize.load(Ordering::Relaxed), 5);
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
/// let some_isize = AtomicIsize::new(5);
///
/// some_isize.store(10, Ordering::Relaxed);
+ /// assert_eq!(some_isize.load(Ordering::Relaxed), 10);
/// ```
///
/// # Panics
///
/// let some_isize = AtomicIsize::new(5);
///
- /// let value = some_isize.swap(10, Ordering::Relaxed);
+ /// assert_eq!(some_isize.swap(10, Ordering::Relaxed), 5);
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
///
/// let some_isize = AtomicIsize::new(5);
///
- /// let value = some_isize.compare_and_swap(5, 10, Ordering::Relaxed);
+ /// assert_eq!(some_isize.compare_and_swap(5, 10, Ordering::Relaxed), 5);
+ /// assert_eq!(some_isize.load(Ordering::Relaxed), 10);
+ ///
+ /// assert_eq!(some_isize.compare_and_swap(6, 12, Ordering::Relaxed), 10);
+ /// assert_eq!(some_isize.load(Ordering::Relaxed), 10);
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
/// use std::sync::atomic::{AtomicIsize, Ordering};
///
/// let foo = AtomicIsize::new(0);
- /// assert_eq!(0, foo.fetch_add(10, Ordering::SeqCst));
- /// assert_eq!(10, foo.load(Ordering::SeqCst));
+ /// assert_eq!(foo.fetch_add(10, Ordering::SeqCst), 0);
+ /// assert_eq!(foo.load(Ordering::SeqCst), 10);
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
/// use std::sync::atomic::{AtomicIsize, Ordering};
///
/// let foo = AtomicIsize::new(0);
- /// assert_eq!(0, foo.fetch_sub(10, Ordering::SeqCst));
- /// assert_eq!(-10, foo.load(Ordering::SeqCst));
+ /// assert_eq!(foo.fetch_sub(10, Ordering::SeqCst), 0);
+ /// assert_eq!(foo.load(Ordering::SeqCst), -10);
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
/// use std::sync::atomic::{AtomicIsize, Ordering};
///
/// let foo = AtomicIsize::new(0b101101);
- /// assert_eq!(0b101101, foo.fetch_and(0b110011, Ordering::SeqCst));
- /// assert_eq!(0b100001, foo.load(Ordering::SeqCst));
+ /// assert_eq!(foo.fetch_and(0b110011, Ordering::SeqCst), 0b101101);
+ /// assert_eq!(foo.load(Ordering::SeqCst), 0b100001);
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn fetch_and(&self, val: isize, order: Ordering) -> isize {
/// use std::sync::atomic::{AtomicIsize, Ordering};
///
/// let foo = AtomicIsize::new(0b101101);
- /// assert_eq!(0b101101, foo.fetch_or(0b110011, Ordering::SeqCst));
- /// assert_eq!(0b111111, foo.load(Ordering::SeqCst));
+ /// assert_eq!(foo.fetch_or(0b110011, Ordering::SeqCst), 0b101101);
+ /// assert_eq!(foo.load(Ordering::SeqCst), 0b111111);
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn fetch_or(&self, val: isize, order: Ordering) -> isize {
/// use std::sync::atomic::{AtomicIsize, Ordering};
///
/// let foo = AtomicIsize::new(0b101101);
- /// assert_eq!(0b101101, foo.fetch_xor(0b110011, Ordering::SeqCst));
- /// assert_eq!(0b011110, foo.load(Ordering::SeqCst));
+ /// assert_eq!(foo.fetch_xor(0b110011, Ordering::SeqCst), 0b101101);
+ /// assert_eq!(foo.load(Ordering::SeqCst), 0b011110);
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn fetch_xor(&self, val: isize, order: Ordering) -> isize {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn new(v: usize) -> AtomicUsize {
+ pub const fn new(v: usize) -> AtomicUsize {
AtomicUsize { v: UnsafeCell::new(v) }
}
///
/// let some_usize = AtomicUsize::new(5);
///
- /// let value = some_usize.load(Ordering::Relaxed);
+ /// assert_eq!(some_usize.load(Ordering::Relaxed), 5);
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
/// let some_usize = AtomicUsize::new(5);
///
/// some_usize.store(10, Ordering::Relaxed);
+ /// assert_eq!(some_usize.load(Ordering::Relaxed), 10);
/// ```
///
/// # Panics
///
/// let some_usize= AtomicUsize::new(5);
///
- /// let value = some_usize.swap(10, Ordering::Relaxed);
+ /// assert_eq!(some_usize.swap(10, Ordering::Relaxed), 5);
+ /// assert_eq!(some_usize.load(Ordering::Relaxed), 10);
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
///
/// let some_usize = AtomicUsize::new(5);
///
- /// let value = some_usize.compare_and_swap(5, 10, Ordering::Relaxed);
+ /// assert_eq!(some_usize.compare_and_swap(5, 10, Ordering::Relaxed), 5);
+ /// assert_eq!(some_usize.load(Ordering::Relaxed), 10);
+ ///
+ /// assert_eq!(some_usize.compare_and_swap(6, 12, Ordering::Relaxed), 10);
+ /// assert_eq!(some_usize.load(Ordering::Relaxed), 10);
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
/// use std::sync::atomic::{AtomicUsize, Ordering};
///
/// let foo = AtomicUsize::new(0);
- /// assert_eq!(0, foo.fetch_add(10, Ordering::SeqCst));
- /// assert_eq!(10, foo.load(Ordering::SeqCst));
+ /// assert_eq!(foo.fetch_add(10, Ordering::SeqCst), 0);
+ /// assert_eq!(foo.load(Ordering::SeqCst), 10);
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
/// use std::sync::atomic::{AtomicUsize, Ordering};
///
/// let foo = AtomicUsize::new(10);
- /// assert_eq!(10, foo.fetch_sub(10, Ordering::SeqCst));
- /// assert_eq!(0, foo.load(Ordering::SeqCst));
+ /// assert_eq!(foo.fetch_sub(10, Ordering::SeqCst), 10);
+ /// assert_eq!(foo.load(Ordering::SeqCst), 0);
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
/// use std::sync::atomic::{AtomicUsize, Ordering};
///
/// let foo = AtomicUsize::new(0b101101);
- /// assert_eq!(0b101101, foo.fetch_and(0b110011, Ordering::SeqCst));
- /// assert_eq!(0b100001, foo.load(Ordering::SeqCst));
+ /// assert_eq!(foo.fetch_and(0b110011, Ordering::SeqCst), 0b101101);
+ /// assert_eq!(foo.load(Ordering::SeqCst), 0b100001);
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn fetch_and(&self, val: usize, order: Ordering) -> usize {
/// use std::sync::atomic::{AtomicUsize, Ordering};
///
/// let foo = AtomicUsize::new(0b101101);
- /// assert_eq!(0b101101, foo.fetch_or(0b110011, Ordering::SeqCst));
- /// assert_eq!(0b111111, foo.load(Ordering::SeqCst));
+ /// assert_eq!(foo.fetch_or(0b110011, Ordering::SeqCst), 0b101101);
+ /// assert_eq!(foo.load(Ordering::SeqCst), 0b111111);
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn fetch_or(&self, val: usize, order: Ordering) -> usize {
/// use std::sync::atomic::{AtomicUsize, Ordering};
///
/// let foo = AtomicUsize::new(0b101101);
- /// assert_eq!(0b101101, foo.fetch_xor(0b110011, Ordering::SeqCst));
- /// assert_eq!(0b011110, foo.load(Ordering::SeqCst));
+ /// assert_eq!(foo.fetch_xor(0b110011, Ordering::SeqCst), 0b101101);
+ /// assert_eq!(foo.load(Ordering::SeqCst), 0b011110);
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn fetch_xor(&self, val: usize, order: Ordering) -> usize {
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn new(p: *mut T) -> AtomicPtr<T> {
- AtomicPtr { p: UnsafeCell::new(p as usize),
- _marker: PhantomData }
+ pub const fn new(p: *mut T) -> AtomicPtr<T> {
+ AtomicPtr { p: UnsafeCell::new(p) }
}
/// Loads a value from the pointer.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn load(&self, order: Ordering) -> *mut T {
unsafe {
- atomic_load(self.p.get(), order) as *mut T
+ atomic_load(self.p.get() as *mut usize, order) as *mut T
}
}
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn store(&self, ptr: *mut T, order: Ordering) {
- unsafe { atomic_store(self.p.get(), ptr as usize, order); }
+ unsafe { atomic_store(self.p.get() as *mut usize, ptr as usize, order); }
}
/// Stores a value into the pointer, returning the old value.
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn swap(&self, ptr: *mut T, order: Ordering) -> *mut T {
- unsafe { atomic_swap(self.p.get(), ptr as usize, order) as *mut T }
+ unsafe { atomic_swap(self.p.get() as *mut usize, ptr as usize, order) as *mut T }
}
/// Stores a value into the pointer if the current value is the same as the expected value.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn compare_and_swap(&self, old: *mut T, new: *mut T, order: Ordering) -> *mut T {
unsafe {
- atomic_compare_and_swap(self.p.get(), old as usize,
+ atomic_compare_and_swap(self.p.get() as *mut usize, old as usize,
new as usize, order) as *mut T
}
}
//!
//! * Introducing inherited mutability roots to shared types.
//! * Implementation details of logically-immutable methods.
-//! * Mutating implementations of `clone`.
+//! * Mutating implementations of `Clone`.
//!
//! ## Introducing inherited mutability roots to shared types
//!
//! }
//! ```
//!
-//! ## Mutating implementations of `clone`
+//! ## Mutating implementations of `Clone`
//!
//! This is simply a special - but common - case of the previous: hiding mutability for operations
//! that appear to be immutable. The `clone` method is expected to not change the source value, and
#![stable(feature = "rust1", since = "1.0.0")]
use clone::Clone;
-use cmp::PartialEq;
+use cmp::{PartialEq, Eq};
use default::Default;
use marker::{Copy, Send, Sync, Sized};
-use ops::{Deref, DerefMut, Drop};
+use ops::{Deref, DerefMut, Drop, FnOnce};
use option::Option;
use option::Option::{None, Some};
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn new(value: T) -> Cell<T> {
+ pub const fn new(value: T) -> Cell<T> {
Cell {
value: UnsafeCell::new(value),
}
}
}
- /// Gets a reference to the underlying `UnsafeCell`.
+ /// Returns a reference to the underlying `UnsafeCell`.
///
/// # Unsafety
///
/// # Examples
///
/// ```
- /// # #![feature(core)]
+ /// # #![feature(as_unsafe_cell)]
/// use std::cell::Cell;
///
/// let c = Cell::new(5);
/// let uc = unsafe { c.as_unsafe_cell() };
/// ```
#[inline]
- #[unstable(feature = "core")]
+ #[unstable(feature = "as_unsafe_cell")]
pub unsafe fn as_unsafe_cell<'a>(&'a self) -> &'a UnsafeCell<T> {
&self.value
}
}
}
+#[stable(feature = "cell_eq", since = "1.2.0")]
+impl<T:Eq + Copy> Eq for Cell<T> {}
+
/// A mutable memory location with dynamically checked borrow rules
///
/// See the [module-level documentation](index.html) for more.
}
/// An enumeration of values returned from the `state` method on a `RefCell<T>`.
-#[derive(Copy, Clone, PartialEq, Debug)]
-#[unstable(feature = "std_misc")]
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+#[unstable(feature = "borrow_state")]
pub enum BorrowState {
/// The cell is currently being read, there is at least one active `borrow`.
Reading,
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn new(value: T) -> RefCell<T> {
+ pub const fn new(value: T) -> RefCell<T> {
RefCell {
value: UnsafeCell::new(value),
borrow: Cell::new(UNUSED),
///
/// The returned value can be dispatched on to determine if a call to
/// `borrow` or `borrow_mut` would succeed.
- #[unstable(feature = "std_misc")]
+ #[unstable(feature = "borrow_state")]
#[inline]
pub fn borrow_state(&self) -> BorrowState {
match self.borrow.get() {
}
}
- /// Gets a reference to the underlying `UnsafeCell`.
+ /// Returns a reference to the underlying `UnsafeCell`.
///
/// This can be used to circumvent `RefCell`'s safety checks.
///
/// This function is `unsafe` because `UnsafeCell`'s field is public.
#[inline]
- #[unstable(feature = "core")]
+ #[unstable(feature = "as_unsafe_cell")]
pub unsafe fn as_unsafe_cell<'a>(&'a self) -> &'a UnsafeCell<T> {
&self.value
}
}
}
+#[stable(feature = "cell_eq", since = "1.2.0")]
+impl<T: ?Sized + Eq> Eq for RefCell<T> {}
+
struct BorrowRef<'b> {
_borrow: &'b Cell<BorrowFlag>,
}
///
/// A `Clone` implementation would interfere with the widespread
/// use of `r.borrow().clone()` to clone the contents of a `RefCell`.
+#[deprecated(since = "1.2.0", reason = "moved to a `Ref::clone` associated function")]
#[unstable(feature = "core",
reason = "likely to be moved to a method, pending language changes")]
#[inline]
pub fn clone_ref<'b, T:Clone>(orig: &Ref<'b, T>) -> Ref<'b, T> {
- Ref {
- _value: orig._value,
- _borrow: orig._borrow.clone(),
+ Ref::clone(orig)
+}
+
+impl<'b, T: ?Sized> Ref<'b, T> {
+ /// Copies a `Ref`.
+ ///
+ /// The `RefCell` is already immutably borrowed, so this cannot fail.
+ ///
+ /// This is an associated function that needs to be used as
+ /// `Ref::clone(...)`. A `Clone` implementation or a method would interfere
+ /// with the widespread use of `r.borrow().clone()` to clone the contents of
+ /// a `RefCell`.
+ #[unstable(feature = "cell_extras",
+ reason = "likely to be moved to a method, pending language changes")]
+ #[inline]
+ pub fn clone(orig: &Ref<'b, T>) -> Ref<'b, T> {
+ Ref {
+ _value: orig._value,
+ _borrow: orig._borrow.clone(),
+ }
+ }
+
+ /// Make a new `Ref` for a component of the borrowed data.
+ ///
+ /// The `RefCell` is already immutably borrowed, so this cannot fail.
+ ///
+ /// This is an associated function that needs to be used as `Ref::map(...)`.
+ /// A method would interfere with methods of the same name on the contents
+ /// of a `RefCell` used through `Deref`.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # #![feature(cell_extras)]
+ /// use std::cell::{RefCell, Ref};
+ ///
+ /// let c = RefCell::new((5, 'b'));
+ /// let b1: Ref<(u32, char)> = c.borrow();
+ /// let b2: Ref<u32> = Ref::map(b1, |t| &t.0);
+ /// assert_eq!(*b2, 5)
+ /// ```
+ #[unstable(feature = "cell_extras", reason = "recently added")]
+ #[inline]
+ pub fn map<U: ?Sized, F>(orig: Ref<'b, T>, f: F) -> Ref<'b, U>
+ where F: FnOnce(&T) -> &U
+ {
+ Ref {
+ _value: f(orig._value),
+ _borrow: orig._borrow,
+ }
+ }
+
+ /// Make a new `Ref` for a optional component of the borrowed data, e.g. an
+ /// enum variant.
+ ///
+ /// The `RefCell` is already immutably borrowed, so this cannot fail.
+ ///
+ /// This is an associated function that needs to be used as
+ /// `Ref::filter_map(...)`. A method would interfere with methods of the
+ /// same name on the contents of a `RefCell` used through `Deref`.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # #![feature(cell_extras)]
+ /// use std::cell::{RefCell, Ref};
+ ///
+ /// let c = RefCell::new(Ok(5));
+ /// let b1: Ref<Result<u32, ()>> = c.borrow();
+ /// let b2: Ref<u32> = Ref::filter_map(b1, |o| o.as_ref().ok()).unwrap();
+ /// assert_eq!(*b2, 5)
+ /// ```
+ #[unstable(feature = "cell_extras", reason = "recently added")]
+ #[inline]
+ pub fn filter_map<U: ?Sized, F>(orig: Ref<'b, T>, f: F) -> Option<Ref<'b, U>>
+ where F: FnOnce(&T) -> Option<&U>
+ {
+ f(orig._value).map(move |new| Ref {
+ _value: new,
+ _borrow: orig._borrow,
+ })
+ }
+}
+
+impl<'b, T: ?Sized> RefMut<'b, T> {
+ /// Make a new `RefMut` for a component of the borrowed data, e.g. an enum
+ /// variant.
+ ///
+ /// The `RefCell` is already mutably borrowed, so this cannot fail.
+ ///
+ /// This is an associated function that needs to be used as
+ /// `RefMut::map(...)`. A method would interfere with methods of the same
+ /// name on the contents of a `RefCell` used through `Deref`.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # #![feature(cell_extras)]
+ /// use std::cell::{RefCell, RefMut};
+ ///
+ /// let c = RefCell::new((5, 'b'));
+ /// {
+ /// let b1: RefMut<(u32, char)> = c.borrow_mut();
+ /// let mut b2: RefMut<u32> = RefMut::map(b1, |t| &mut t.0);
+ /// assert_eq!(*b2, 5);
+ /// *b2 = 42;
+ /// }
+ /// assert_eq!(*c.borrow(), (42, 'b'));
+ /// ```
+ #[unstable(feature = "cell_extras", reason = "recently added")]
+ #[inline]
+ pub fn map<U: ?Sized, F>(orig: RefMut<'b, T>, f: F) -> RefMut<'b, U>
+ where F: FnOnce(&mut T) -> &mut U
+ {
+ RefMut {
+ _value: f(orig._value),
+ _borrow: orig._borrow,
+ }
+ }
+
+ /// Make a new `RefMut` for a optional component of the borrowed data, e.g.
+ /// an enum variant.
+ ///
+ /// The `RefCell` is already mutably borrowed, so this cannot fail.
+ ///
+ /// This is an associated function that needs to be used as
+ /// `RefMut::filter_map(...)`. A method would interfere with methods of the
+ /// same name on the contents of a `RefCell` used through `Deref`.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # #![feature(cell_extras)]
+ /// use std::cell::{RefCell, RefMut};
+ ///
+ /// let c = RefCell::new(Ok(5));
+ /// {
+ /// let b1: RefMut<Result<u32, ()>> = c.borrow_mut();
+ /// let mut b2: RefMut<u32> = RefMut::filter_map(b1, |o| {
+ /// o.as_mut().ok()
+ /// }).unwrap();
+ /// assert_eq!(*b2, 5);
+ /// *b2 = 42;
+ /// }
+ /// assert_eq!(*c.borrow(), Ok(42));
+ /// ```
+ #[unstable(feature = "cell_extras", reason = "recently added")]
+ #[inline]
+ pub fn filter_map<U: ?Sized, F>(orig: RefMut<'b, T>, f: F) -> Option<RefMut<'b, U>>
+ where F: FnOnce(&mut T) -> Option<&mut U>
+ {
+ let RefMut { _value, _borrow } = orig;
+ f(_value).map(move |new| RefMut {
+ _value: new,
+ _borrow: _borrow,
+ })
}
}
///
/// This field should not be accessed directly, it is made public for static
/// initializers.
+ #[deprecated(since = "1.2.0", reason = "use `get` to access the wrapped \
+ value or `new` to initialize `UnsafeCell` in statics")]
#[unstable(feature = "core")]
pub value: T,
}
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn new(value: T) -> UnsafeCell<T> {
+ pub const fn new(value: T) -> UnsafeCell<T> {
+ #![allow(deprecated)]
UnsafeCell { value: value }
}
///
/// # Unsafety
///
- /// This function is unsafe because there is no guarantee that this or other threads are
- /// currently inspecting the inner value.
+ /// This function is unsafe because this thread or another thread may currently be
+ /// inspecting the inner value.
///
/// # Examples
///
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- pub unsafe fn into_inner(self) -> T { self.value }
+ pub unsafe fn into_inner(self) -> T {
+ #![allow(deprecated)]
+ self.value
+ }
}
impl<T: ?Sized> UnsafeCell<T> {
pub fn get(&self) -> *mut T {
// FIXME(#23542) Replace with type ascription.
#![allow(trivial_casts)]
+ #![allow(deprecated)]
&self.value as *const T as *mut T
}
}
#![allow(non_snake_case)]
#![doc(primitive = "char")]
+#![stable(feature = "core_char", since = "1.2.0")]
use iter::Iterator;
use mem::transmute;
/// ```
/// use std::char;
///
-/// let c = char::from_u32(10084); // produces `Some(❤)`
-/// assert_eq!(c, Some('❤'));
-/// ```
-///
-/// An invalid character:
-///
-/// ```
-/// use std::char;
-///
-/// let none = char::from_u32(1114112);
-/// assert_eq!(none, None);
+/// assert_eq!(char::from_u32(0x2764), Some('❤'));
+/// assert_eq!(char::from_u32(0x110000), None); // invalid character
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
// unicode/char.rs, not here
#[allow(missing_docs)] // docs in libunicode/u_char.rs
#[doc(hidden)]
+#[unstable(feature = "core_char_ext",
+ reason = "the stable interface is `impl char` in later crate")]
pub trait CharExt {
fn is_digit(self, radix: u32) -> bool;
fn to_digit(self, radix: u32) -> Option<u32>;
}
impl CharExt for char {
+ #[inline]
fn is_digit(self, radix: u32) -> bool {
self.to_digit(radix).is_some()
}
+ #[inline]
fn to_digit(self, radix: u32) -> Option<u32> {
if radix > 36 {
panic!("to_digit: radix is too high (maximum 36)");
else { None }
}
+ #[inline]
fn escape_unicode(self) -> EscapeUnicode {
EscapeUnicode { c: self, state: EscapeUnicodeState::Backslash }
}
+ #[inline]
fn escape_default(self) -> EscapeDefault {
let init_state = match self {
'\t' => EscapeDefaultState::Backslash('t'),
/// If the buffer is not large enough, nothing will be written into it
/// and a `None` will be returned.
#[inline]
+#[unstable(feature = "char_internals",
+ reason = "this function should not be exposed publicly")]
+#[doc(hidden)]
pub fn encode_utf8_raw(code: u32, dst: &mut [u8]) -> Option<usize> {
// Marked #[inline] to allow llvm optimizing it away
if code < MAX_ONE_B && !dst.is_empty() {
/// If the buffer is not large enough, nothing will be written into it
/// and a `None` will be returned.
#[inline]
+#[unstable(feature = "char_internals",
+ reason = "this function should not be exposed publicly")]
+#[doc(hidden)]
pub fn encode_utf16_raw(mut ch: u32, dst: &mut [u16]) -> Option<usize> {
// Marked #[inline] to allow llvm optimizing it away
if (ch & 0xFFFF) == ch && !dst.is_empty() {
macro_rules! extern_fn_clone {
($($A:ident),*) => (
- #[unstable(feature = "core",
- reason = "this may not be sufficient for fns with region parameters")]
+ #[stable(feature = "rust1", since = "1.0.0")]
impl<$($A,)* ReturnType> Clone for extern "Rust" fn($($A),*) -> ReturnType {
/// Returns a copy of a function pointer.
#[inline]
fn clone(&self) -> extern "Rust" fn($($A),*) -> ReturnType { *self }
}
- #[unstable(feature = "core", reason = "brand new")]
+ #[stable(feature = "rust1", since = "1.0.0")]
impl<$($A,)* ReturnType> Clone for extern "C" fn($($A),*) -> ReturnType {
/// Returns a copy of a function pointer.
#[inline]
fn clone(&self) -> extern "C" fn($($A),*) -> ReturnType { *self }
}
- #[unstable(feature = "core", reason = "brand new")]
+ #[stable(feature = "rust1", since = "1.0.0")]
impl<$($A,)* ReturnType> Clone for unsafe extern "Rust" fn($($A),*) -> ReturnType {
/// Returns a copy of a function pointer.
#[inline]
fn clone(&self) -> unsafe extern "Rust" fn($($A),*) -> ReturnType { *self }
}
- #[unstable(feature = "core", reason = "brand new")]
+ #[stable(feature = "rust1", since = "1.0.0")]
impl<$($A,)* ReturnType> Clone for unsafe extern "C" fn($($A),*) -> ReturnType {
/// Returns a copy of a function pointer.
#[inline]
//! Functionality for ordering and comparison.
//!
-//! This module defines both `PartialOrd` and `PartialEq` traits which are used by the compiler to
-//! implement comparison operators. Rust programs may implement `PartialOrd` to overload the `<`,
-//! `<=`, `>`, and `>=` operators, and may implement `PartialEq` to overload the `==` and `!=`
-//! operators.
+//! This module defines both `PartialOrd` and `PartialEq` traits which are used
+//! by the compiler to implement comparison operators. Rust programs may
+//! implement `PartialOrd` to overload the `<`, `<=`, `>`, and `>=` operators,
+//! and may implement `PartialEq` to overload the `==` and `!=` operators.
#![stable(feature = "rust1", since = "1.0.0")]
use marker::Sized;
use option::Option::{self, Some, None};
-/// Trait for equality comparisons which are [partial equivalence relations](
-/// http://en.wikipedia.org/wiki/Partial_equivalence_relation).
+/// Trait for equality comparisons which are [partial equivalence
+/// relations](http://en.wikipedia.org/wiki/Partial_equivalence_relation).
///
-/// This trait allows for partial equality, for types that do not have a full equivalence relation.
-/// For example, in floating point numbers `NaN != NaN`, so floating point types implement
-/// `PartialEq` but not `Eq`.
+/// This trait allows for partial equality, for types that do not have a full
+/// equivalence relation. For example, in floating point numbers `NaN != NaN`,
+/// so floating point types implement `PartialEq` but not `Eq`.
///
/// Formally, the equality must be (for all `a`, `b` and `c`):
///
/// - symmetric: `a == b` implies `b == a`; and
/// - transitive: `a == b` and `b == c` implies `a == c`.
///
-/// Note that these requirements mean that the trait itself must be implemented symmetrically and
-/// transitively: if `T: PartialEq<U>` and `U: PartialEq<V>` then `U: PartialEq<T>` and `T:
-/// PartialEq<V>`.
+/// Note that these requirements mean that the trait itself must be implemented
+/// symmetrically and transitively: if `T: PartialEq<U>` and `U: PartialEq<V>`
+/// then `U: PartialEq<T>` and `T: PartialEq<V>`.
///
-/// PartialEq only requires the `eq` method to be implemented; `ne` is defined in terms of it by
-/// default. Any manual implementation of `ne` *must* respect the rule that `eq` is a strict
-/// inverse of `ne`; that is, `!(a == b)` if and only if `a != b`.
+/// PartialEq only requires the `eq` method to be implemented; `ne` is defined
+/// in terms of it by default. Any manual implementation of `ne` *must* respect
+/// the rule that `eq` is a strict inverse of `ne`; that is, `!(a == b)` if and
+/// only if `a != b`.
#[lang = "eq"]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait PartialEq<Rhs: ?Sized = Self> {
- /// This method tests for `self` and `other` values to be equal, and is used by `==`.
+ /// This method tests for `self` and `other` values to be equal, and is used
+ /// by `==`.
#[stable(feature = "rust1", since = "1.0.0")]
fn eq(&self, other: &Rhs) -> bool;
/// # Examples
///
/// ```
-/// # #![feature(core)]
+/// # #![feature(cmp_partial)]
/// use std::cmp;
///
/// assert_eq!(Some(1), cmp::partial_min(1, 2));
/// When comparison is impossible:
///
/// ```
-/// # #![feature(core)]
+/// # #![feature(cmp_partial)]
/// use std::cmp;
///
/// let result = cmp::partial_min(std::f64::NAN, 1.0);
/// assert_eq!(result, None);
/// ```
#[inline]
-#[unstable(feature = "core")]
+#[unstable(feature = "cmp_partial")]
pub fn partial_min<T: PartialOrd>(v1: T, v2: T) -> Option<T> {
match v1.partial_cmp(&v2) {
Some(Less) | Some(Equal) => Some(v1),
/// # Examples
///
/// ```
-/// # #![feature(core)]
+/// # #![feature(cmp_partial)]
/// use std::cmp;
///
/// assert_eq!(Some(2), cmp::partial_max(1, 2));
/// When comparison is impossible:
///
/// ```
-/// # #![feature(core)]
+/// # #![feature(cmp_partial)]
/// use std::cmp;
///
/// let result = cmp::partial_max(std::f64::NAN, 1.0);
/// assert_eq!(result, None);
/// ```
#[inline]
-#[unstable(feature = "core")]
+#[unstable(feature = "cmp_partial")]
pub fn partial_max<T: PartialOrd>(v1: T, v2: T) -> Option<T> {
match v1.partial_cmp(&v2) {
Some(Equal) | Some(Less) => Some(v2),
//! Traits for conversions between types.
//!
-//! The traits in this module provide a general way to talk about conversions from one type to
-//! another. They follow the standard Rust conventions of `as`/`into`/`from`.
+//! The traits in this module provide a general way to talk about conversions
+//! from one type to another. They follow the standard Rust conventions of
+//! `as`/`into`/`from`.
//!
-//! Like many traits, these are often used as bounds for generic functions, to support arguments of
-//! multiple types.
+//! Like many traits, these are often used as bounds for generic functions, to
+//! support arguments of multiple types.
//!
//! See each trait for usage examples.
///
/// Constructed by the `Formatter::debug_struct` method.
#[must_use]
+#[stable(feature = "debug_builders", since = "1.2.0")]
pub struct DebugStruct<'a, 'b: 'a> {
fmt: &'a mut fmt::Formatter<'b>,
result: fmt::Result,
impl<'a, 'b: 'a> DebugStruct<'a, 'b> {
/// Adds a new field to the generated struct output.
- #[unstable(feature = "debug_builders", reason = "method was just created")]
- pub fn field(mut self, name: &str, value: &fmt::Debug) -> DebugStruct<'a, 'b> {
+ #[stable(feature = "debug_builders", since = "1.2.0")]
+ pub fn field(&mut self, name: &str, value: &fmt::Debug) -> &mut DebugStruct<'a, 'b> {
self.result = self.result.and_then(|_| {
let prefix = if self.has_fields {
","
self
}
- /// Consumes the `DebugStruct`, finishing output and returning any error
- /// encountered.
- #[unstable(feature = "debug_builders", reason = "method was just created")]
- pub fn finish(mut self) -> fmt::Result {
+ /// Finishes output and returns any error encountered.
+ #[stable(feature = "debug_builders", since = "1.2.0")]
+ pub fn finish(&mut self) -> fmt::Result {
if self.has_fields {
self.result = self.result.and_then(|_| {
if self.is_pretty() {
///
/// Constructed by the `Formatter::debug_tuple` method.
#[must_use]
+#[stable(feature = "debug_builders", since = "1.2.0")]
pub struct DebugTuple<'a, 'b: 'a> {
fmt: &'a mut fmt::Formatter<'b>,
result: fmt::Result,
impl<'a, 'b: 'a> DebugTuple<'a, 'b> {
/// Adds a new field to the generated tuple struct output.
- #[unstable(feature = "debug_builders", reason = "method was just created")]
- pub fn field(mut self, value: &fmt::Debug) -> DebugTuple<'a, 'b> {
+ #[stable(feature = "debug_builders", since = "1.2.0")]
+ pub fn field(&mut self, value: &fmt::Debug) -> &mut DebugTuple<'a, 'b> {
self.result = self.result.and_then(|_| {
let (prefix, space) = if self.has_fields {
(",", " ")
self
}
- /// Consumes the `DebugTuple`, finishing output and returning any error
- /// encountered.
- #[unstable(feature = "debug_builders", reason = "method was just created")]
- pub fn finish(mut self) -> fmt::Result {
+ /// Finishes output and returns any error encountered.
+ #[stable(feature = "debug_builders", since = "1.2.0")]
+ pub fn finish(&mut self) -> fmt::Result {
if self.has_fields {
self.result = self.result.and_then(|_| {
if self.is_pretty() {
///
/// Constructed by the `Formatter::debug_set` method.
#[must_use]
+#[stable(feature = "debug_builders", since = "1.2.0")]
pub struct DebugSet<'a, 'b: 'a> {
inner: DebugInner<'a, 'b>,
}
impl<'a, 'b: 'a> DebugSet<'a, 'b> {
/// Adds a new entry to the set output.
- #[unstable(feature = "debug_builders", reason = "method was just created")]
- pub fn entry(mut self, entry: &fmt::Debug) -> DebugSet<'a, 'b> {
+ #[stable(feature = "debug_builders", since = "1.2.0")]
+ pub fn entry(&mut self, entry: &fmt::Debug) -> &mut DebugSet<'a, 'b> {
self.inner.entry(entry);
self
}
- /// Consumes the `DebugSet`, finishing output and returning any error
- /// encountered.
- #[unstable(feature = "debug_builders", reason = "method was just created")]
- pub fn finish(mut self) -> fmt::Result {
+ /// Adds the contents of an iterator of entries to the set output.
+ #[stable(feature = "debug_builders", since = "1.2.0")]
+ pub fn entries<D, I>(&mut self, entries: I) -> &mut DebugSet<'a, 'b>
+ where D: fmt::Debug, I: IntoIterator<Item=D> {
+ for entry in entries {
+ self.entry(&entry);
+ }
+ self
+ }
+
+ /// Finishes output and returns any error encountered.
+ #[stable(feature = "debug_builders", since = "1.2.0")]
+ pub fn finish(&mut self) -> fmt::Result {
self.inner.finish();
self.inner.result.and_then(|_| self.inner.fmt.write_str("}"))
}
///
/// Constructed by the `Formatter::debug_list` method.
#[must_use]
+#[stable(feature = "debug_builders", since = "1.2.0")]
pub struct DebugList<'a, 'b: 'a> {
inner: DebugInner<'a, 'b>,
}
}
impl<'a, 'b: 'a> DebugList<'a, 'b> {
- /// Adds a new entry to the set output.
- #[unstable(feature = "debug_builders", reason = "method was just created")]
- pub fn entry(mut self, entry: &fmt::Debug) -> DebugList<'a, 'b> {
+ /// Adds a new entry to the list output.
+ #[stable(feature = "debug_builders", since = "1.2.0")]
+ pub fn entry(&mut self, entry: &fmt::Debug) -> &mut DebugList<'a, 'b> {
self.inner.entry(entry);
self
}
- /// Consumes the `DebugSet`, finishing output and returning any error
- /// encountered.
- #[unstable(feature = "debug_builders", reason = "method was just created")]
- pub fn finish(mut self) -> fmt::Result {
+ /// Adds the contents of an iterator of entries to the list output.
+ #[stable(feature = "debug_builders", since = "1.2.0")]
+ pub fn entries<D, I>(&mut self, entries: I) -> &mut DebugList<'a, 'b>
+ where D: fmt::Debug, I: IntoIterator<Item=D> {
+ for entry in entries {
+ self.entry(&entry);
+ }
+ self
+ }
+
+ /// Finishes output and returns any error encountered.
+ #[stable(feature = "debug_builders", since = "1.2.0")]
+ pub fn finish(&mut self) -> fmt::Result {
self.inner.finish();
self.inner.result.and_then(|_| self.inner.fmt.write_str("]"))
}
///
/// Constructed by the `Formatter::debug_map` method.
#[must_use]
+#[stable(feature = "debug_builders", since = "1.2.0")]
pub struct DebugMap<'a, 'b: 'a> {
fmt: &'a mut fmt::Formatter<'b>,
result: fmt::Result,
impl<'a, 'b: 'a> DebugMap<'a, 'b> {
/// Adds a new entry to the map output.
- #[unstable(feature = "debug_builders", reason = "method was just created")]
- pub fn entry(mut self, key: &fmt::Debug, value: &fmt::Debug) -> DebugMap<'a, 'b> {
+ #[stable(feature = "debug_builders", since = "1.2.0")]
+ pub fn entry(&mut self, key: &fmt::Debug, value: &fmt::Debug) -> &mut DebugMap<'a, 'b> {
self.result = self.result.and_then(|_| {
if self.is_pretty() {
let mut writer = PadAdapter::new(self.fmt);
self
}
- /// Consumes the `DebugMap`, finishing output and returning any error
- /// encountered.
- #[unstable(feature = "debug_builders", reason = "method was just created")]
- pub fn finish(self) -> fmt::Result {
+ /// Adds the contents of an iterator of entries to the map output.
+ #[stable(feature = "debug_builders", since = "1.2.0")]
+ pub fn entries<K, V, I>(&mut self, entries: I) -> &mut DebugMap<'a, 'b>
+ where K: fmt::Debug, V: fmt::Debug, I: IntoIterator<Item=(K, V)> {
+ for (k, v) in entries {
+ self.entry(&k, &v);
+ }
+ self
+ }
+
+ /// Finishes output and returns any error encountered.
+ #[stable(feature = "debug_builders", since = "1.2.0")]
+ pub fn finish(&mut self) -> fmt::Result {
let prefix = if self.is_pretty() && self.has_fields { "\n" } else { "" };
self.result.and_then(|_| write!(self.fmt, "{}}}", prefix))
}
mod num;
mod builders;
-#[unstable(feature = "core", reason = "internal to format_args!")]
+#[unstable(feature = "fmt_internals", reason = "internal to format_args!")]
#[doc(hidden)]
pub mod rt {
pub mod v1;
///
/// # Errors
///
- /// This function will return an instance of `FormatError` on error.
+ /// This function will return an instance of `Error` on error.
#[stable(feature = "rust1", since = "1.0.0")]
fn write_str(&mut self, s: &str) -> Result;
///
/// # Errors
///
- /// This function will return an instance of `FormatError` on error.
+ /// This function will return an instance of `Error` on error.
#[stable(feature = "fmt_write_char", since = "1.1.0")]
fn write_char(&mut self, c: char) -> Result {
let mut utf_8 = [0u8; 4];
/// compile time it is ensured that the function and the value have the correct
/// types, and then this struct is used to canonicalize arguments to one type.
#[derive(Copy)]
-#[unstable(feature = "core", reason = "internal to format_args!")]
+#[unstable(feature = "fmt_internals", reason = "internal to format_args!")]
#[doc(hidden)]
pub struct ArgumentV1<'a> {
value: &'a Void,
}
#[doc(hidden)]
- #[unstable(feature = "core", reason = "internal to format_args!")]
+ #[unstable(feature = "fmt_internals", reason = "internal to format_args!")]
pub fn new<'b, T>(x: &'b T,
f: fn(&T, &mut Formatter) -> Result) -> ArgumentV1<'b> {
unsafe {
}
#[doc(hidden)]
- #[unstable(feature = "core", reason = "internal to format_args!")]
+ #[unstable(feature = "fmt_internals", reason = "internal to format_args!")]
pub fn from_usize(x: &usize) -> ArgumentV1 {
ArgumentV1::new(x, ArgumentV1::show_usize)
}
/// When using the format_args!() macro, this function is used to generate the
/// Arguments structure.
#[doc(hidden)] #[inline]
- #[unstable(feature = "core", reason = "internal to format_args!")]
+ #[unstable(feature = "fmt_internals", reason = "internal to format_args!")]
pub fn new_v1(pieces: &'a [&'a str],
args: &'a [ArgumentV1<'a>]) -> Arguments<'a> {
Arguments {
/// created with `argumentusize`. However, failing to do so doesn't cause
/// unsafety, but will ignore invalid .
#[doc(hidden)] #[inline]
- #[unstable(feature = "core", reason = "internal to format_args!")]
+ #[unstable(feature = "fmt_internals", reason = "internal to format_args!")]
pub fn new_v1_formatted(pieces: &'a [&'a str],
args: &'a [ArgumentV1<'a>],
fmt: &'a [rt::v1::Argument]) -> Arguments<'a> {
/// Format trait for the `:?` format. Useful for debugging, all types
/// should implement this.
+///
+/// Generally speaking, you should just `derive` a `Debug` implementation.
+///
+/// # Examples
+///
+/// Deriving an implementation:
+///
+/// ```
+/// #[derive(Debug)]
+/// struct Point {
+/// x: i32,
+/// y: i32,
+/// }
+///
+/// let origin = Point { x: 0, y: 0 };
+///
+/// println!("The origin is: {:?}", origin);
+/// ```
+///
+/// Manually implementing:
+///
+/// ```
+/// use std::fmt;
+///
+/// struct Point {
+/// x: i32,
+/// y: i32,
+/// }
+///
+/// impl fmt::Debug for Point {
+/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+/// write!(f, "({}, {})", self.x, self.y)
+/// }
+/// }
+///
+/// let origin = Point { x: 0, y: 0 };
+///
+/// println!("The origin is: {:?}", origin);
+/// ```
+///
+/// There are a number of `debug_*` methods on `Formatter` to help you with manual
+/// implementations, such as [`debug_struct`][debug_struct].
+///
+/// [debug_struct]: ../std/fmt/struct.Formatter.html#method.debug_struct
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_on_unimplemented = "`{Self}` cannot be formatted using `:?`; if it is \
defined in your crate, add `#[derive(Debug)]` or \
pub fn flags(&self) -> u32 { self.flags }
/// Character used as 'fill' whenever there is alignment
- #[unstable(feature = "core", reason = "method was just created")]
+ #[unstable(feature = "fmt_flags", reason = "method was just created")]
pub fn fill(&self) -> char { self.fill }
/// Flag indicating what form of alignment was requested
- #[unstable(feature = "core", reason = "method was just created")]
+ #[unstable(feature = "fmt_flags", reason = "method was just created")]
pub fn align(&self) -> Alignment { self.align }
/// Optionally specified integer width that the output should be
- #[unstable(feature = "core", reason = "method was just created")]
+ #[unstable(feature = "fmt_flags", reason = "method was just created")]
pub fn width(&self) -> Option<usize> { self.width }
/// Optionally specified precision for numeric types
- #[unstable(feature = "core", reason = "method was just created")]
+ #[unstable(feature = "fmt_flags", reason = "method was just created")]
pub fn precision(&self) -> Option<usize> { self.precision }
/// Creates a `DebugStruct` builder designed to assist with creation of
/// # Examples
///
/// ```rust
- /// # #![feature(debug_builders, core)]
/// use std::fmt;
///
/// struct Foo {
/// // prints "Foo { bar: 10, baz: "Hello World" }"
/// println!("{:?}", Foo { bar: 10, baz: "Hello World".to_string() });
/// ```
- #[unstable(feature = "debug_builders", reason = "method was just created")]
+ #[stable(feature = "debug_builders", since = "1.2.0")]
#[inline]
pub fn debug_struct<'b>(&'b mut self, name: &str) -> DebugStruct<'b, 'a> {
builders::debug_struct_new(self, name)
/// # Examples
///
/// ```rust
- /// # #![feature(debug_builders, core)]
/// use std::fmt;
///
/// struct Foo(i32, String);
/// // prints "Foo(10, "Hello World")"
/// println!("{:?}", Foo(10, "Hello World".to_string()));
/// ```
- #[unstable(feature = "debug_builders", reason = "method was just created")]
+ #[stable(feature = "debug_builders", since = "1.2.0")]
#[inline]
pub fn debug_tuple<'b>(&'b mut self, name: &str) -> DebugTuple<'b, 'a> {
builders::debug_tuple_new(self, name)
/// # Examples
///
/// ```rust
- /// # #![feature(debug_builders, core)]
/// use std::fmt;
///
/// struct Foo(Vec<i32>);
///
/// impl fmt::Debug for Foo {
/// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- /// self.0.iter().fold(fmt.debug_list(), |b, e| b.entry(e)).finish()
+ /// fmt.debug_list().entries(self.0.iter()).finish()
/// }
/// }
///
/// // prints "[10, 11]"
/// println!("{:?}", Foo(vec![10, 11]));
/// ```
- #[unstable(feature = "debug_builders", reason = "method was just created")]
+ #[stable(feature = "debug_builders", since = "1.2.0")]
#[inline]
pub fn debug_list<'b>(&'b mut self) -> DebugList<'b, 'a> {
builders::debug_list_new(self)
/// # Examples
///
/// ```rust
- /// # #![feature(debug_builders, core)]
/// use std::fmt;
///
/// struct Foo(Vec<i32>);
///
/// impl fmt::Debug for Foo {
/// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- /// self.0.iter().fold(fmt.debug_set(), |b, e| b.entry(e)).finish()
+ /// fmt.debug_set().entries(self.0.iter()).finish()
/// }
/// }
///
/// // prints "{10, 11}"
/// println!("{:?}", Foo(vec![10, 11]));
/// ```
- #[unstable(feature = "debug_builders", reason = "method was just created")]
+ #[stable(feature = "debug_builders", since = "1.2.0")]
#[inline]
pub fn debug_set<'b>(&'b mut self) -> DebugSet<'b, 'a> {
builders::debug_set_new(self)
/// # Examples
///
/// ```rust
- /// # #![feature(debug_builders, core)]
/// use std::fmt;
///
/// struct Foo(Vec<(String, i32)>);
///
/// impl fmt::Debug for Foo {
/// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- /// self.0.iter().fold(fmt.debug_map(), |b, &(ref k, ref v)| b.entry(k, v)).finish()
+ /// fmt.debug_map().entries(self.0.iter().map(|&(ref k, ref v)| (k, v))).finish()
/// }
/// }
///
/// // prints "{"A": 10, "B": 11}"
/// println!("{:?}", Foo(vec![("A".to_string(), 10), ("B".to_string(), 11)]));
/// ```
- #[unstable(feature = "debug_builders", reason = "method was just created")]
+ #[stable(feature = "debug_builders", since = "1.2.0")]
#[inline]
pub fn debug_map<'b>(&'b mut self) -> DebugMap<'b, 'a> {
builders::debug_map_new(self)
}
}
+#[stable(since = "1.2.0", feature = "formatter_write")]
+impl<'a> Write for Formatter<'a> {
+ fn write_str(&mut self, s: &str) -> Result {
+ self.buf.write_str(s)
+ }
+
+ fn write_char(&mut self, c: char) -> Result {
+ self.buf.write_char(c)
+ }
+
+ fn write_fmt(&mut self, args: Arguments) -> Result {
+ write(self.buf, args)
+ }
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl Display for Error {
fn fmt(&self, f: &mut Formatter) -> Result {
#[stable(feature = "rust1", since = "1.0.0")]
impl Display for char {
fn fmt(&self, f: &mut Formatter) -> Result {
- let mut utf8 = [0; 4];
- let amt = self.encode_utf8(&mut utf8).unwrap_or(0);
- let s: &str = unsafe { mem::transmute(&utf8[..amt]) };
- Display::fmt(s, f)
+ if f.width.is_none() && f.precision.is_none() {
+ f.write_char(*self)
+ } else {
+ let mut utf8 = [0; 4];
+ let amt = self.encode_utf8(&mut utf8).unwrap_or(0);
+ let s: &str = unsafe { mem::transmute(&utf8[..amt]) };
+ f.pad(s)
+ }
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Debug> Debug for [T] {
fn fmt(&self, f: &mut Formatter) -> Result {
- self.iter().fold(f.debug_list(), |b, e| b.entry(e)).finish()
+ f.debug_list().entries(self.iter()).finish()
}
}
/// A radix with in the range of `2..36`.
#[derive(Clone, Copy, PartialEq)]
-#[unstable(feature = "core",
+#[unstable(feature = "fmt_radix",
reason = "may be renamed or move to a different module")]
pub struct Radix {
base: u8,
}
/// A helper type for formatting radixes.
-#[unstable(feature = "core",
+#[unstable(feature = "fmt_radix",
reason = "may be renamed or move to a different module")]
#[derive(Copy, Clone)]
pub struct RadixFmt<T, R>(T, R);
/// # Examples
///
/// ```
-/// # #![feature(core)]
+/// # #![feature(fmt_radix)]
/// use std::fmt::radix;
/// assert_eq!(format!("{}", radix(55, 36)), "1j".to_string());
/// ```
-#[unstable(feature = "core",
+#[unstable(feature = "fmt_radix",
reason = "may be renamed or move to a different module")]
pub fn radix<T>(x: T, base: u8) -> RadixFmt<T, Radix> {
RadixFmt(x, Radix::new(base))
//! These definitions are similar to their `ct` equivalents, but differ in that
//! these can be statically allocated and are slightly optimized for the runtime
-#![unstable(feature = "core", reason = "internal to format_args!")]
-
#[derive(Copy, Clone)]
pub struct Argument {
pub position: Position,
//! # Examples
//!
//! ```rust
-//! # #![feature(hash)]
+//! # #![feature(hash_default)]
//! use std::hash::{hash, Hash, SipHasher};
//!
//! #[derive(Hash)]
//! the trait `Hash`:
//!
//! ```rust
-//! # #![feature(hash)]
+//! # #![feature(hash_default)]
//! use std::hash::{hash, Hash, Hasher, SipHasher};
//!
//! struct Person {
fn hash<H: Hasher>(&self, state: &mut H);
/// Feeds a slice of this type into the state provided.
- #[unstable(feature = "hash", reason = "module was recently redesigned")]
+ #[unstable(feature = "hash_slice",
+ reason = "module was recently redesigned")]
fn hash_slice<H: Hasher>(data: &[Self], state: &mut H) where Self: Sized {
for piece in data {
piece.hash(state);
/// Write a single `u8` into this hasher
#[inline]
- #[unstable(feature = "hash", reason = "module was recently redesigned")]
+ #[unstable(feature = "hasher_write", reason = "module was recently redesigned")]
fn write_u8(&mut self, i: u8) { self.write(&[i]) }
/// Write a single `u16` into this hasher.
#[inline]
- #[unstable(feature = "hash", reason = "module was recently redesigned")]
+ #[unstable(feature = "hasher_write", reason = "module was recently redesigned")]
fn write_u16(&mut self, i: u16) {
self.write(&unsafe { mem::transmute::<_, [u8; 2]>(i) })
}
/// Write a single `u32` into this hasher.
#[inline]
- #[unstable(feature = "hash", reason = "module was recently redesigned")]
+ #[unstable(feature = "hasher_write", reason = "module was recently redesigned")]
fn write_u32(&mut self, i: u32) {
self.write(&unsafe { mem::transmute::<_, [u8; 4]>(i) })
}
/// Write a single `u64` into this hasher.
#[inline]
- #[unstable(feature = "hash", reason = "module was recently redesigned")]
+ #[unstable(feature = "hasher_write", reason = "module was recently redesigned")]
fn write_u64(&mut self, i: u64) {
self.write(&unsafe { mem::transmute::<_, [u8; 8]>(i) })
}
/// Write a single `usize` into this hasher.
#[inline]
- #[unstable(feature = "hash", reason = "module was recently redesigned")]
+ #[unstable(feature = "hasher_write", reason = "module was recently redesigned")]
fn write_usize(&mut self, i: usize) {
if cfg!(target_pointer_width = "32") {
self.write_u32(i as u32)
/// Write a single `i8` into this hasher.
#[inline]
- #[unstable(feature = "hash", reason = "module was recently redesigned")]
+ #[unstable(feature = "hasher_write", reason = "module was recently redesigned")]
fn write_i8(&mut self, i: i8) { self.write_u8(i as u8) }
/// Write a single `i16` into this hasher.
#[inline]
- #[unstable(feature = "hash", reason = "module was recently redesigned")]
+ #[unstable(feature = "hasher_write", reason = "module was recently redesigned")]
fn write_i16(&mut self, i: i16) { self.write_u16(i as u16) }
/// Write a single `i32` into this hasher.
#[inline]
- #[unstable(feature = "hash", reason = "module was recently redesigned")]
+ #[unstable(feature = "hasher_write", reason = "module was recently redesigned")]
fn write_i32(&mut self, i: i32) { self.write_u32(i as u32) }
/// Write a single `i64` into this hasher.
#[inline]
- #[unstable(feature = "hash", reason = "module was recently redesigned")]
+ #[unstable(feature = "hasher_write", reason = "module was recently redesigned")]
fn write_i64(&mut self, i: i64) { self.write_u64(i as u64) }
/// Write a single `isize` into this hasher.
#[inline]
- #[unstable(feature = "hash", reason = "module was recently redesigned")]
+ #[unstable(feature = "hasher_write", reason = "module was recently redesigned")]
fn write_isize(&mut self, i: isize) { self.write_usize(i as usize) }
}
///
/// The specified value will be hashed with this hasher and then the resulting
/// hash will be returned.
-#[unstable(feature = "hash", reason = "module was recently redesigned")]
+#[unstable(feature = "hash_default",
+ reason = "not the most ergonomic interface unless `H` is defaulted \
+ to SipHasher, but perhaps not ready to commit to that")]
pub fn hash<T: Hash, H: Hasher + Default>(value: &T) -> u64 {
let mut h: H = Default::default();
value.hash(&mut h);
//! guaranteed to happen in order. This is the standard mode for working
//! with atomic types and is equivalent to Java's `volatile`.
-#![unstable(feature = "core")]
+#![unstable(feature = "core_intrinsics",
+ reason = "intrinsics are unlikely to ever be stabilized, instead \
+ they should be used through stabilized interfaces \
+ in the rest of the standard library")]
#![allow(missing_docs)]
use marker::Sized;
extern "rust-intrinsic" {
- // NB: These intrinsics take unsafe pointers because they mutate aliased
+ // NB: These intrinsics take raw pointers because they mutate aliased
// memory, which is not valid for either `&` or `&mut`.
pub fn atomic_cxchg<T>(dst: *mut T, old: T, src: T) -> T;
/// A compiler-only memory barrier.
///
- /// Memory accesses will never be reordered across this barrier by the compiler,
- /// but no instructions will be emitted for it. This is appropriate for operations
- /// on the same thread that may be preempted, such as when interacting with signal
- /// handlers.
- #[cfg(not(stage0))] // SNAP 857ef6e
+ /// Memory accesses will never be reordered across this barrier by the
+ /// compiler, but no instructions will be emitted for it. This is
+ /// appropriate for operations on the same thread that may be preempted,
+ /// such as when interacting with signal handlers.
pub fn atomic_singlethreadfence();
- #[cfg(not(stage0))] // SNAP 857ef6e
pub fn atomic_singlethreadfence_acq();
- #[cfg(not(stage0))] // SNAP 857ef6e
pub fn atomic_singlethreadfence_rel();
- #[cfg(not(stage0))] // SNAP 857ef6e
pub fn atomic_singlethreadfence_acqrel();
/// Aborts the execution of the process.
pub fn min_align_of<T>() -> usize;
pub fn pref_align_of<T>() -> usize;
- #[cfg(not(stage0))]
pub fn size_of_val<T: ?Sized>(_: &T) -> usize;
- #[cfg(not(stage0))]
pub fn min_align_of_val<T: ?Sized>(_: &T) -> usize;
- #[cfg(not(stage0))]
pub fn drop_in_place<T: ?Sized>(_: *mut T);
/// Gets a static string slice containing the name of a type.
/// returned value will result in undefined behavior.
pub fn offset<T>(dst: *const T, offset: isize) -> *const T;
+ /// Calculates the offset from a pointer, potentially wrapping.
+ ///
+ /// This is implemented as an intrinsic to avoid converting to and from an
+ /// integer, since the conversion inhibits certain optimizations.
+ ///
+ /// # Safety
+ ///
+ /// Unlike the `offset` intrinsic, this intrinsic does not restrict the
+ /// resulting pointer to point into or one byte past the end of an allocated
+ /// object, and it wraps with two's complement arithmetic. The resulting
+ /// value is not necessarily valid to be used to actually access memory.
+ pub fn arith_offset<T>(dst: *const T, offset: isize) -> *const T;
+
/// Copies `count * size_of<T>` bytes from `src` to `dst`. The source
/// and destination may *not* overlap.
///
/// A safe swap function:
///
/// ```
- /// # #![feature(core)]
/// use std::mem;
/// use std::ptr;
///
/// Efficiently create a Rust vector from an unsafe buffer:
///
/// ```
- /// # #![feature(core)]
/// use std::ptr;
///
/// unsafe fn from_buf_raw<T>(ptr: *const T, elts: usize) -> Vec<T> {
/// Returns (a * b) mod 2^N, where N is the width of N in bits.
pub fn overflowing_mul<T>(a: T, b: T) -> T;
- /// Returns the value of the discriminant for the variant in 'v',
- /// cast to a `u64`; if `T` has no discriminant, returns 0.
- pub fn discriminant_value<T>(v: &T) -> u64;
-}
-
-#[cfg(not(stage0))]
-extern "rust-intrinsic" {
/// Performs an unchecked signed division, which results in undefined behavior,
/// in cases where y == 0, or x == int::MIN and y == -1
pub fn unchecked_sdiv<T>(x: T, y: T) -> T;
/// Returns the remainder of an unchecked signed division, which results in
/// undefined behavior, in cases where y == 0
pub fn unchecked_srem<T>(x: T, y: T) -> T;
+
+ /// Returns the value of the discriminant for the variant in 'v',
+ /// cast to a `u64`; if `T` has no discriminant, returns 0.
+ pub fn discriminant_value<T>(v: &T) -> u64;
}
//! }
//! ```
//!
-//! Because `Iterator`s implement `IntoIterator`, this `for` loop syntax can be applied to any
-//! iterator over any type.
+//! Because `Iterator`s implement `IntoIterator`, this `for` loop syntax can be
+//! applied to any iterator over any type.
#![stable(feature = "rust1", since = "1.0.0")]
/// ```
/// let a = [0];
/// let b = [1];
- /// let mut it = a.iter().chain(b.iter());
+ /// let mut it = a.iter().chain(&b);
/// assert_eq!(it.next(), Some(&0));
/// assert_eq!(it.next(), Some(&1));
/// assert!(it.next().is_none());
/// ```
/// let a = [0];
/// let b = [1];
- /// let mut it = a.iter().zip(b.iter());
+ /// let mut it = a.iter().zip(&b);
/// assert_eq!(it.next(), Some((&0, &1)));
/// assert!(it.next().is_none());
/// ```
/// # Examples
///
/// ```
- /// # #![feature(core)]
/// let xs = [100, 200, 300];
/// let mut it = xs.iter().cloned().peekable();
/// assert_eq!(*it.peek().unwrap(), 100);
Scan{iter: self, f: f, state: initial_state}
}
- /// Creates an iterator that maps each element to an iterator,
- /// and yields the elements of the produced iterators.
+ /// Takes a function that maps each element to a new iterator and yields
+ /// all the elements of the produced iterators.
+ ///
+ /// This is useful for unraveling nested structures.
///
/// # Examples
///
/// ```
- /// # #![feature(core)]
- /// let xs = [2, 3];
- /// let ys = [0, 1, 0, 1, 2];
- /// let it = xs.iter().flat_map(|&x| (0..).take(x));
- /// // Check that `it` has the same elements as `ys`
- /// for (i, x) in it.enumerate() {
- /// assert_eq!(x, ys[i]);
- /// }
+ /// let words = ["alpha", "beta", "gamma"];
+ /// let merged: String = words.iter()
+ /// .flat_map(|s| s.chars())
+ /// .collect();
+ /// assert_eq!(merged, "alphabetagamma");
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
/// # Examples
///
/// ```
- /// # #![feature(core)]
- ///
/// let a = [1, 4, 2, 3, 8, 9, 6];
/// let sum: i32 = a.iter()
/// .map(|x| *x)
/// .inspect(|&x| println!("filtering {}", x))
/// .filter(|&x| x % 2 == 0)
/// .inspect(|&x| println!("{} made it through", x))
- /// .sum();
+ /// .fold(0, |sum, i| sum + i);
/// println!("{}", sum);
/// ```
#[inline]
/// do not.
///
/// ```
- /// # #![feature(core)]
/// let vec = vec![1, 2, 3, 4];
/// let (even, odd): (Vec<_>, Vec<_>) = vec.into_iter().partition(|&n| n % 2 == 0);
/// assert_eq!(even, [2, 4]);
for x in self {
if f(&x) {
- left.extend(Some(x).into_iter())
+ left.extend(Some(x))
} else {
- right.extend(Some(x).into_iter())
+ right.extend(Some(x))
}
}
/// # Examples
///
/// ```
- /// # #![feature(core)]
+ /// # #![feature(iter_min_max)]
/// use std::iter::MinMaxResult::{NoElements, OneElement, MinMax};
///
/// let a: [i32; 0] = [];
/// let a = [1, 1, 1, 1];
/// assert_eq!(a.iter().min_max(), MinMax(&1, &1));
/// ```
- #[unstable(feature = "core", reason = "return type may change")]
+ #[unstable(feature = "iter_min_max",
+ reason = "return type may change or may wish to have a closure \
+ based version as well")]
fn min_max(mut self) -> MinMaxResult<Self::Item> where Self: Sized, Self::Item: Ord
{
let (mut min, mut max) = match self.next() {
/// # Examples
///
/// ```
- /// # #![feature(core)]
- ///
+ /// # #![feature(iter_cmp)]
/// let a = [-3_i32, 0, 1, 5, -10];
/// assert_eq!(*a.iter().max_by(|x| x.abs()).unwrap(), -10);
/// ```
#[inline]
- #[unstable(feature = "core",
+ #[unstable(feature = "iter_cmp",
reason = "may want to produce an Ordering directly; see #15311")]
fn max_by<B: Ord, F>(self, f: F) -> Option<Self::Item> where
Self: Sized,
/// # Examples
///
/// ```
- /// # #![feature(core)]
- ///
+ /// # #![feature(iter_cmp)]
/// let a = [-3_i32, 0, 1, 5, -10];
/// assert_eq!(*a.iter().min_by(|x| x.abs()).unwrap(), 0);
/// ```
#[inline]
- #[unstable(feature = "core",
+ #[unstable(feature = "iter_cmp",
reason = "may want to produce an Ordering directly; see #15311")]
fn min_by<B: Ord, F>(self, f: F) -> Option<Self::Item> where
Self: Sized,
/// # Examples
///
/// ```
- /// # #![feature(core)]
/// let a = [(1, 2), (3, 4)];
/// let (left, right): (Vec<_>, Vec<_>) = a.iter().cloned().unzip();
/// assert_eq!(left, [1, 3]);
us.extend(SizeHint(lo, hi, marker::PhantomData));
for (t, u) in self {
- ts.extend(Some(t).into_iter());
- us.extend(Some(u).into_iter());
+ ts.extend(Some(t));
+ us.extend(Some(u));
}
(ts, us)
}
- /// Creates an iterator that clones the elements it yields. Useful for
- /// converting an Iterator<&T> to an Iterator<T>.
+ /// Creates an iterator that clones the elements it yields.
+ ///
+ /// This is useful for converting an Iterator<&T> to an Iterator<T>,
+ /// so it's a more convenient form of `map(|&x| x)`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let a = [0, 1, 2];
+ /// let v_cloned: Vec<_> = a.iter().cloned().collect();
+ /// let v_map: Vec<_> = a.iter().map(|&x| x).collect();
+ /// assert_eq!(v_cloned, v_map);
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
fn cloned<'a, T: 'a>(self) -> Cloned<Self>
where Self: Sized + Iterator<Item=&'a T>, T: Clone
/// Use an iterator to reverse a container in place.
#[unstable(feature = "core",
reason = "uncertain about placement or widespread use")]
+ #[deprecated(since = "1.2.0",
+ reason = "not performant enough to justify inclusion")]
fn reverse_in_place<'a, T: 'a>(&mut self) where
Self: Sized + Iterator<Item=&'a mut T> + DoubleEndedIterator
{
/// # Examples
///
/// ```
- /// # #![feature(core)]
- ///
+ /// # #![feature(iter_arith)]
/// let a = [1, 2, 3, 4, 5];
- /// let mut it = a.iter().cloned();
+ /// let it = a.iter();
/// assert_eq!(it.sum::<i32>(), 15);
/// ```
- #[unstable(feature="core")]
+ #[unstable(feature="iter_arith", reason = "bounds recently changed")]
fn sum<S=<Self as Iterator>::Item>(self) -> S where
S: Add<Self::Item, Output=S> + Zero,
Self: Sized,
/// # Examples
///
/// ```
- /// # #![feature(core)]
- ///
+ /// # #![feature(iter_arith)]
/// fn factorial(n: u32) -> u32 {
/// (1..).take_while(|&i| i <= n).product()
/// }
/// assert_eq!(factorial(1), 1);
/// assert_eq!(factorial(5), 120);
/// ```
- #[unstable(feature="core")]
+ #[unstable(feature="iter_arith", reason = "bounds recently changed")]
fn product<P=<Self as Iterator>::Item>(self) -> P where
P: Mul<Self::Item, Output=P> + One,
Self: Sized,
/// `DoubleEndedIterator`. Calling `next()` or `next_back()` on a
/// `RandomAccessIterator` reduces the indexable range accordingly. That is,
/// `it.idx(1)` will become `it.idx(0)` after `it.next()` is called.
-#[unstable(feature = "core",
+#[unstable(feature = "iter_idx",
reason = "not widely used, may be better decomposed into Index \
and ExactSizeIterator")]
+#[deprecated(since = "1.2.0",
+ reason = "trait has not proven itself as a widely useful \
+ abstraction for iterators, and more time may be needed \
+ for iteration on the design")]
+#[allow(deprecated)]
pub trait RandomAccessIterator: Iterator {
/// Returns the number of indexable elements. At most `std::usize::MAX`
/// elements are indexable, even if the iterator represents a longer range.
fn next_back(&mut self) -> Option<<I as Iterator>::Item> { self.iter.next() }
}
-#[unstable(feature = "core", reason = "trait is experimental")]
+#[unstable(feature = "iter_idx", reason = "trait is experimental")]
+#[allow(deprecated)]
impl<I> RandomAccessIterator for Rev<I>
where I: DoubleEndedIterator + RandomAccessIterator
{
/// `MinMaxResult` is an enum returned by `min_max`. See `Iterator::min_max` for
/// more detail.
#[derive(Clone, PartialEq, Debug)]
-#[unstable(feature = "core",
+#[unstable(feature = "iter_min_max",
reason = "unclear whether such a fine-grained result is widely useful")]
pub enum MinMaxResult<T> {
/// Empty iterator
MinMax(T, T)
}
+#[unstable(feature = "iter_min_max", reason = "type is unstable")]
impl<T: Clone> MinMaxResult<T> {
/// `into_option` creates an `Option` of type `(T,T)`. The returned `Option`
/// has variant `None` if and only if the `MinMaxResult` has variant
/// # Examples
///
/// ```
- /// # #![feature(core)]
+ /// # #![feature(iter_min_max)]
/// use std::iter::MinMaxResult::{self, NoElements, OneElement, MinMax};
///
/// let r: MinMaxResult<i32> = NoElements;
/// let r = MinMax(1, 2);
/// assert_eq!(r.into_option(), Some((1, 2)));
/// ```
- #[unstable(feature = "core", reason = "type is unstable")]
pub fn into_option(self) -> Option<(T,T)> {
match self {
NoElements => None,
where I: ExactSizeIterator<Item=&'a T>, T: Clone
{}
-#[unstable(feature = "core", reason = "trait is experimental")]
+#[unstable(feature = "iter_idx", reason = "trait is experimental")]
+#[allow(deprecated)]
impl<'a, I, T: 'a> RandomAccessIterator for Cloned<I>
where I: RandomAccessIterator<Item=&'a T>, T: Clone
{
}
}
-#[unstable(feature = "core", reason = "trait is experimental")]
+#[unstable(feature = "iter_idx", reason = "trait is experimental")]
+#[allow(deprecated)]
impl<I> RandomAccessIterator for Cycle<I> where
I: Clone + RandomAccessIterator,
{
}
}
-#[unstable(feature = "core", reason = "trait is experimental")]
+#[unstable(feature = "iter_idx", reason = "trait is experimental")]
+#[allow(deprecated)]
impl<A, B> RandomAccessIterator for Chain<A, B> where
A: RandomAccessIterator,
B: RandomAccessIterator<Item = A::Item>,
}
}
-#[unstable(feature = "core", reason = "trait is experimental")]
+#[unstable(feature = "iter_idx", reason = "trait is experimental")]
+#[allow(deprecated)]
impl<A, B> RandomAccessIterator for Zip<A, B> where
A: RandomAccessIterator,
B: RandomAccessIterator
}
}
-#[unstable(feature = "core", reason = "trait is experimental")]
+#[unstable(feature = "iter_idx", reason = "trait is experimental")]
+#[allow(deprecated)]
impl<B, I: RandomAccessIterator, F> RandomAccessIterator for Map<I, F> where
F: FnMut(I::Item) -> B,
{
}
}
-#[unstable(feature = "core", reason = "trait is experimental")]
+#[unstable(feature = "iter_idx", reason = "trait is experimental")]
+#[allow(deprecated)]
impl<I> RandomAccessIterator for Enumerate<I> where I: RandomAccessIterator {
#[inline]
fn indexable(&self) -> usize {
}
}
-#[unstable(feature = "core", reason = "trait is experimental")]
+#[unstable(feature = "iter_idx", reason = "trait is experimental")]
+#[allow(deprecated)]
impl<I> RandomAccessIterator for Skip<I> where I: RandomAccessIterator{
#[inline]
fn indexable(&self) -> usize {
}
}
-#[unstable(feature = "core", reason = "trait is experimental")]
+#[unstable(feature = "iter_idx", reason = "trait is experimental")]
+#[allow(deprecated)]
impl<I> RandomAccessIterator for Take<I> where I: RandomAccessIterator{
#[inline]
fn indexable(&self) -> usize {
f: F,
/// The current internal state to be passed to the closure next.
- #[unstable(feature = "core")]
+ #[unstable(feature = "scan_state",
+ reason = "public fields are otherwise rare in the stdlib")]
pub state: St,
}
}
// Allow RandomAccessIterators to be fused without affecting random-access behavior
-#[unstable(feature = "core", reason = "trait is experimental")]
+#[unstable(feature = "iter_idx", reason = "trait is experimental")]
+#[allow(deprecated)]
impl<I> RandomAccessIterator for Fuse<I> where I: RandomAccessIterator {
#[inline]
fn indexable(&self) -> usize {
/// `.next_back()` will call the underlying iterator again even if it
/// previously returned `None`.
#[inline]
- #[unstable(feature = "core", reason = "seems marginal")]
+ #[unstable(feature = "iter_reset_fuse", reason = "seems marginal")]
pub fn reset_fuse(&mut self) {
self.done = false
}
}
}
-#[unstable(feature = "core", reason = "trait is experimental")]
+#[unstable(feature = "iter_idx", reason = "trait is experimental")]
+#[allow(deprecated)]
impl<I: RandomAccessIterator, F> RandomAccessIterator for Inspect<I, F>
where F: FnMut(&I::Item),
{
/// An iterator that yields sequential Fibonacci numbers, and stops on overflow.
///
/// ```
-/// #![feature(core)]
+/// #![feature(iter_unfold)]
/// use std::iter::Unfold;
///
/// // This iterator will yield up to the last Fibonacci number before the max
/// println!("{}", i);
/// }
/// ```
-#[unstable(feature = "core")]
+#[unstable(feature = "iter_unfold")]
#[derive(Clone)]
+#[deprecated(since = "1.2.0",
+ reason = "has gained enough traction to retain its position \
+ in the standard library")]
+#[allow(deprecated)]
pub struct Unfold<St, F> {
f: F,
/// Internal state that will be passed to the closure on the next iteration
- #[unstable(feature = "core")]
+ #[unstable(feature = "iter_unfold")]
pub state: St,
}
-#[unstable(feature = "core")]
+#[unstable(feature = "iter_unfold")]
+#[deprecated(since = "1.2.0",
+ reason = "has gained enough traction to retain its position \
+ in the standard library")]
+#[allow(deprecated)]
impl<A, St, F> Unfold<St, F> where F: FnMut(&mut St) -> Option<A> {
/// Creates a new iterator with the specified closure as the "iterator
/// function" and an initial state to eventually pass to the closure
}
#[stable(feature = "rust1", since = "1.0.0")]
+#[allow(deprecated)]
impl<A, St, F> Iterator for Unfold<St, F> where F: FnMut(&mut St) -> Option<A> {
type Item = A;
/// # Examples
///
/// ```
- /// # #![feature(step_by, core)]
+ /// # #![feature(step_by)]
/// for i in (0..10).step_by(2) {
/// println!("{}", i);
/// }
/// An iterator over the range [start, stop]
#[derive(Clone)]
-#[unstable(feature = "core",
+#[unstable(feature = "range_inclusive",
reason = "likely to be replaced by range notation and adapters")]
pub struct RangeInclusive<A> {
range: ops::Range<A>,
/// Returns an iterator over the range [start, stop].
#[inline]
-#[unstable(feature = "core",
+#[unstable(feature = "range_inclusive",
reason = "likely to be replaced by range notation and adapters")]
pub fn range_inclusive<A>(start: A, stop: A) -> RangeInclusive<A>
where A: Step + One + Clone
}
}
-#[unstable(feature = "core",
+#[unstable(feature = "range_inclusive",
reason = "likely to be replaced by range notation and adapters")]
impl<A> Iterator for RangeInclusive<A> where
A: PartialEq + Step + One + Clone,
}
}
-#[unstable(feature = "core",
+#[unstable(feature = "range_inclusive",
reason = "likely to be replaced by range notation and adapters")]
impl<A> DoubleEndedIterator for RangeInclusive<A> where
A: PartialEq + Step + One + Clone,
type Item = A;
#[inline]
- fn next(&mut self) -> Option<A> { self.idx(0) }
+ fn next(&mut self) -> Option<A> { Some(self.element.clone()) }
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) { (usize::MAX, None) }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<A: Clone> DoubleEndedIterator for Repeat<A> {
#[inline]
- fn next_back(&mut self) -> Option<A> { self.idx(0) }
+ fn next_back(&mut self) -> Option<A> { Some(self.element.clone()) }
}
-#[unstable(feature = "core", reason = "trait is experimental")]
+#[unstable(feature = "iter_idx", reason = "trait is experimental")]
+#[allow(deprecated)]
impl<A: Clone> RandomAccessIterator for Repeat<A> {
#[inline]
fn indexable(&self) -> usize { usize::MAX }
/// An iterator that repeatedly applies a given function, starting
/// from a given seed value.
-#[unstable(feature = "core")]
+#[unstable(feature = "iter_iterate")]
+#[deprecated(since = "1.2.0",
+ reason = "has gained enough traction to retain its position \
+ in the standard library")]
+#[allow(deprecated)]
pub type Iterate<T, F> = Unfold<IterateState<T, F>, fn(&mut IterateState<T, F>) -> Option<T>>;
/// Creates a new iterator that produces an infinite sequence of
/// repeated applications of the given function `f`.
-#[unstable(feature = "core")]
+#[unstable(feature = "iter_iterate")]
+#[deprecated(since = "1.2.0",
+ reason = "has gained enough traction to retain its position \
+ in the standard library")]
+#[allow(deprecated)]
pub fn iterate<T, F>(seed: T, f: F) -> Iterate<T, F> where
T: Clone,
F: FnMut(T) -> T,
Repeat{element: elt}
}
+/// An iterator that yields nothing.
+#[stable(feature = "iter_empty", since = "1.2.0")]
+pub struct Empty<T>(marker::PhantomData<T>);
+
+#[stable(feature = "iter_empty", since = "1.2.0")]
+impl<T> Iterator for Empty<T> {
+ type Item = T;
+
+ fn next(&mut self) -> Option<T> {
+ None
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>){
+ (0, Some(0))
+ }
+}
+
+#[stable(feature = "iter_empty", since = "1.2.0")]
+impl<T> DoubleEndedIterator for Empty<T> {
+ fn next_back(&mut self) -> Option<T> {
+ None
+ }
+}
+
+#[stable(feature = "iter_empty", since = "1.2.0")]
+impl<T> ExactSizeIterator for Empty<T> {
+ fn len(&self) -> usize {
+ 0
+ }
+}
+
+// not #[derive] because that adds a Clone bound on T,
+// which isn't necessary.
+#[stable(feature = "iter_empty", since = "1.2.0")]
+impl<T> Clone for Empty<T> {
+ fn clone(&self) -> Empty<T> {
+ Empty(marker::PhantomData)
+ }
+}
+
+// not #[derive] because that adds a Default bound on T,
+// which isn't necessary.
+#[stable(feature = "iter_empty", since = "1.2.0")]
+impl<T> Default for Empty<T> {
+ fn default() -> Empty<T> {
+ Empty(marker::PhantomData)
+ }
+}
+
+/// Creates an iterator that yields nothing.
+#[stable(feature = "iter_empty", since = "1.2.0")]
+pub fn empty<T>() -> Empty<T> {
+ Empty(marker::PhantomData)
+}
+
+/// An iterator that yields an element exactly once.
+#[derive(Clone)]
+#[stable(feature = "iter_once", since = "1.2.0")]
+pub struct Once<T> {
+ inner: ::option::IntoIter<T>
+}
+
+#[stable(feature = "iter_once", since = "1.2.0")]
+impl<T> Iterator for Once<T> {
+ type Item = T;
+
+ fn next(&mut self) -> Option<T> {
+ self.inner.next()
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.inner.size_hint()
+ }
+}
+
+#[stable(feature = "iter_once", since = "1.2.0")]
+impl<T> DoubleEndedIterator for Once<T> {
+ fn next_back(&mut self) -> Option<T> {
+ self.inner.next_back()
+ }
+}
+
+#[stable(feature = "iter_once", since = "1.2.0")]
+impl<T> ExactSizeIterator for Once<T> {
+ fn len(&self) -> usize {
+ self.inner.len()
+ }
+}
+
+/// Creates an iterator that yields an element exactly once.
+#[stable(feature = "iter_once", since = "1.2.0")]
+pub fn once<T>(value: T) -> Once<T> {
+ Once { inner: Some(value).into_iter() }
+}
+
/// Functions for lexicographical ordering of sequences.
///
/// Lexicographical ordering through `<`, `<=`, `>=`, `>` requires
///
/// If two sequences are equal up until the point where one ends,
/// the shorter sequence compares less.
-#[unstable(feature = "core", reason = "needs review and revision")]
+#[unstable(feature = "iter_order", reason = "needs review and revision")]
pub mod order {
use cmp;
use cmp::{Eq, Ord, PartialOrd, PartialEq};
}
/// Returns `a` < `b` lexicographically (Using partial order, `PartialOrd`)
- pub fn lt<R: Iterator, L: Iterator>(mut a: L, mut b: R) -> bool where
+ pub fn lt<L: Iterator, R: Iterator>(mut a: L, mut b: R) -> bool where
L::Item: PartialOrd<R::Item>,
{
loop {
// Do not remove on snapshot creation. Needed for bootstrap. (Issue #22364)
#![cfg_attr(stage0, feature(custom_attribute))]
#![crate_name = "core"]
-#![unstable(feature = "core")]
+#![unstable(feature = "core",
+ reason = "the libcore library has not yet been scrutinized for \
+ stabilization in terms of structure and naming")]
#![staged_api]
#![crate_type = "rlib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
- html_favicon_url = "http://www.rust-lang.org/favicon.ico",
+ html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/",
html_playground_url = "http://play.rust-lang.org/")]
#![doc(test(no_crate_inject))]
#![allow(raw_pointer_derive)]
#![deny(missing_docs)]
-#![feature(intrinsics, lang_items)]
+#![feature(associated_type_defaults)]
+#![feature(intrinsics)]
+#![feature(lang_items)]
#![feature(on_unimplemented)]
#![feature(simd)]
#![feature(staged_api)]
#![feature(concat_idents)]
#![feature(reflect)]
#![feature(custom_attribute)]
+#![feature(const_fn)]
+#![feature(allow_internal_unstable)]
#[macro_use]
mod macros;
/// Entry point of thread panic, for details, see std::macros
#[macro_export]
+#[allow_internal_unstable]
macro_rules! panic {
() => (
panic!("explicit panic")
/// # Examples
///
/// ```
-/// # #![allow(unused_must_use)]
/// use std::io::Write;
///
/// let mut w = Vec::new();
-/// write!(&mut w, "test");
-/// write!(&mut w, "formatted {}", "arguments");
+/// write!(&mut w, "test").unwrap();
+/// write!(&mut w, "formatted {}", "arguments").unwrap();
/// ```
#[macro_export]
macro_rules! write {
}
/// Types that can be "unsized" to a dynamically sized type.
-#[unstable(feature = "core")]
-#[cfg(not(stage0))]
+#[unstable(feature = "unsize")]
#[lang="unsize"]
pub trait Unsize<T> {
// Empty.
/// ```
///
/// The `PointList` `struct` cannot implement `Copy`, because `Vec<T>` is not `Copy`. If we
-/// attempt to derive a `Copy` implementation, we'll get an error.
+/// attempt to derive a `Copy` implementation, we'll get an error:
///
/// ```text
-/// error: the trait `Copy` may not be implemented for this type; field `points` does not implement
-/// `Copy`
+/// the trait `Copy` may not be implemented for this type; field `points` does not implement `Copy`
/// ```
///
/// ## How can I implement `Copy`?
/// ensure that they are never copied, even if they lack a destructor.
#[unstable(feature = "core",
reason = "likely to change with new variance strategy")]
+#[deprecated(since = "1.2.0",
+ reason = "structs are by default not copyable")]
#[lang = "no_copy_bound"]
+#[allow(deprecated)]
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct NoCopy;
/// struct is dropped, it may in turn drop one or more instances of
/// the type `T`, though that may not be apparent from the other
/// structure of the type itself. This is commonly necessary if the
-/// structure is using an unsafe pointer like `*mut T` whose referent
+/// structure is using a raw pointer like `*mut T` whose referent
/// may be dropped when the type is dropped, as a `*mut T` is
/// otherwise not treated as owned.
///
/// that function. Here is an example:
///
/// ```
-/// #![feature(core)]
+/// #![feature(reflect_marker)]
/// use std::marker::Reflect;
/// use std::any::Any;
/// fn foo<T:Reflect+'static>(x: &T) {
///
/// [1]: http://en.wikipedia.org/wiki/Parametricity
#[rustc_reflect_like]
-#[unstable(feature = "core", reason = "requires RFC and more experience")]
+#[unstable(feature = "reflect_marker",
+ reason = "requires RFC and more experience")]
#[allow(deprecated)]
#[rustc_on_unimplemented = "`{Self}` does not implement `Any`; \
ensure all type parameters are bounded by `Any`"]
/// * `mpsc::{Sender, Receiver}` cycles (they use `Arc` internally)
/// * Panicking destructors are likely to leak local resources
///
+/// # When To Use
+///
+/// There's only a few reasons to use this function. They mainly come
+/// up in unsafe code or FFI code.
+///
+/// * You have an uninitialized value, perhaps for performance reasons, and
+/// need to prevent the destructor from running on it.
+/// * You have two copies of a value (like `std::mem::swap`), but need the
+/// destructor to only run once to prevent a double free.
+/// * Transferring resources across FFI boundries.
+///
/// # Example
///
-/// ```rust,no_run
+/// Leak some heap memory by never deallocating it.
+///
+/// ```rust
/// use std::mem;
-/// use std::fs::File;
///
-/// // Leak some heap memory by never deallocating it
/// let heap_memory = Box::new(3);
/// mem::forget(heap_memory);
+/// ```
+///
+/// Leak an I/O object, never closing the file.
+///
+/// ```rust,no_run
+/// use std::mem;
+/// use std::fs::File;
///
-/// // Leak an I/O object, never closing the file
/// let file = File::open("foo.txt").unwrap();
/// mem::forget(file);
/// ```
+///
+/// The swap function uses forget to good effect.
+///
+/// ```rust
+/// use std::mem;
+/// use std::ptr;
+///
+/// fn swap<T>(x: &mut T, y: &mut T) {
+/// unsafe {
+/// // Give ourselves some scratch space to work with
+/// let mut t: T = mem::uninitialized();
+///
+/// // Perform the swap, `&mut` pointers never alias
+/// ptr::copy_nonoverlapping(&*x, &mut t, 1);
+/// ptr::copy_nonoverlapping(&*y, x, 1);
+/// ptr::copy_nonoverlapping(&t, y, 1);
+///
+/// // y and t now point to the same thing, but we need to completely
+/// // forget `t` because we do not want to run the destructor for `T`
+/// // on its value, which is still owned somewhere outside this function.
+/// mem::forget(t);
+/// }
+/// }
+/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn forget<T>(t: T) {
unsafe { intrinsics::forget(t) }
///
/// assert_eq!(4, mem::size_of_val(&5i32));
/// ```
-#[cfg(not(stage0))]
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn size_of_val<T: ?Sized>(val: &T) -> usize {
unsafe { intrinsics::size_of_val(val) }
}
-/// Returns the size of the type that `_val` points to in bytes.
-///
-/// # Examples
-///
-/// ```
-/// use std::mem;
-///
-/// assert_eq!(4, mem::size_of_val(&5i32));
-/// ```
-#[cfg(stage0)]
-#[inline]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub fn size_of_val<T>(_val: &T) -> usize {
- size_of::<T>()
-}
-
/// Returns the ABI-required minimum alignment of a type
///
/// This is the alignment used for struct fields. It may be smaller than the preferred alignment.
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
+#[deprecated(reason = "use `align_of` instead", since = "1.2.0")]
pub fn min_align_of<T>() -> usize {
unsafe { intrinsics::min_align_of::<T>() }
}
///
/// assert_eq!(4, mem::min_align_of_val(&5i32));
/// ```
-#[cfg(not(stage0))]
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
+#[deprecated(reason = "use `align_of_val` instead", since = "1.2.0")]
pub fn min_align_of_val<T: ?Sized>(val: &T) -> usize {
unsafe { intrinsics::min_align_of_val(val) }
}
-/// Returns the ABI-required minimum alignment of the type of the value that `_val` points to
-///
-/// # Examples
-///
-/// ```
-/// use std::mem;
-///
-/// assert_eq!(4, mem::min_align_of_val(&5i32));
-/// ```
-#[cfg(stage0)]
-#[inline]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub fn min_align_of_val<T>(_val: &T) -> usize {
- min_align_of::<T>()
-}
-
/// Returns the alignment in memory for a type.
///
-/// This function will return the alignment, in bytes, of a type in memory. If the alignment
-/// returned is adhered to, then the type is guaranteed to function properly.
+/// This is the alignment used for struct fields. It may be smaller than the preferred alignment.
///
/// # Examples
///
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn align_of<T>() -> usize {
- // We use the preferred alignment as the default alignment for a type. This
- // appears to be what clang migrated towards as well:
- //
- // http://lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20110725/044411.html
- unsafe { intrinsics::pref_align_of::<T>() }
+ unsafe { intrinsics::min_align_of::<T>() }
}
-/// Returns the alignment of the type of the value that `_val` points to.
-///
-/// This is similar to `align_of`, but function will properly handle types such as trait objects
-/// (in the future), returning the alignment for an arbitrary value at runtime.
+/// Returns the ABI-required minimum alignment of the type of the value that `val` points to
///
/// # Examples
///
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
-pub fn align_of_val<T>(_val: &T) -> usize {
- align_of::<T>()
+pub fn align_of_val<T: ?Sized>(val: &T) -> usize {
+ unsafe { intrinsics::min_align_of_val(val) }
}
/// Creates a value initialized to zero.
ptr::copy_nonoverlapping(&*y, x, 1);
ptr::copy_nonoverlapping(&t, y, 1);
- // y and t now point to the same thing, but we need to completely forget `t`
- // because it's no longer relevant.
+ // y and t now point to the same thing, but we need to completely
+ // forget `t` because we do not want to run the destructor for `T`
+ // on its value, which is still owned somewhere outside this function.
forget(t);
}
}
/// Transforms lifetime of the second pointer to match the first.
#[inline]
-#[unstable(feature = "core",
+#[unstable(feature = "copy_lifetime",
reason = "this function may be removed in the future due to its \
questionable utility")]
+#[deprecated(since = "1.2.0",
+ reason = "unclear that this function buys more safety and \
+ lifetimes are generally not handled as such in unsafe \
+ code today")]
pub unsafe fn copy_lifetime<'a, S: ?Sized, T: ?Sized + 'a>(_ptr: &'a S,
ptr: &T) -> &'a T {
transmute(ptr)
/// Transforms lifetime of the second mutable pointer to match the first.
#[inline]
-#[unstable(feature = "core",
+#[unstable(feature = "copy_lifetime",
reason = "this function may be removed in the future due to its \
questionable utility")]
+#[deprecated(since = "1.2.0",
+ reason = "unclear that this function buys more safety and \
+ lifetimes are generally not handled as such in unsafe \
+ code today")]
pub unsafe fn copy_mut_lifetime<'a, S: ?Sized, T: ?Sized + 'a>(_ptr: &'a S,
ptr: &mut T)
-> &'a mut T
// except according to those terms.
//! Exposes the NonZero lang item which provides optimization hints.
+#![unstable(feature = "nonzero",
+ reason = "needs an RFC to flesh out the design")]
use marker::Sized;
-use ops::Deref;
-#[cfg(not(stage0))]
-use ops::CoerceUnsized;
+use ops::{CoerceUnsized, Deref};
/// Unsafe trait to indicate what types are usable with the NonZero struct
pub unsafe trait Zeroable {}
/// NULL or 0 that might allow certain optimizations.
#[lang = "non_zero"]
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)]
-#[unstable(feature = "core")]
pub struct NonZero<T: Zeroable>(T);
impl<T: Zeroable> NonZero<T> {
}
}
-#[cfg(not(stage0))]
impl<T: Zeroable+CoerceUnsized<U>, U: Zeroable> CoerceUnsized<NonZero<U>> for NonZero<T> {}
pub const PI: f32 = 3.14159265358979323846264338327950288_f32;
/// pi * 2.0
- #[unstable(feature = "core", reason = "unclear naming convention/usefulness")]
+ #[unstable(feature = "float_consts",
+ reason = "unclear naming convention/usefulness")]
+ #[deprecated(since = "1.2.0", reason = "unclear on usefulness")]
pub const PI_2: f32 = 6.28318530717958647692528676655900576_f32;
/// pi/2.0
pub const LN_10: f32 = 2.30258509299404568401799145468436421_f32;
}
-#[unstable(feature = "core", reason = "trait is unstable")]
impl Float for f32 {
#[inline]
fn nan() -> f32 { NAN }
pub const PI: f64 = 3.14159265358979323846264338327950288_f64;
/// pi * 2.0
- #[unstable(feature = "core", reason = "unclear naming convention/usefulness")]
+ #[unstable(feature = "float_consts",
+ reason = "unclear naming convention/usefulness")]
+ #[deprecated(since = "1.2.0", reason = "unclear on usefulness")]
pub const PI_2: f64 = 6.28318530717958647692528676655900576_f64;
/// pi/2.0
pub const LN_10: f64 = 2.30258509299404568401799145468436421_f64;
}
-#[unstable(feature = "core", reason = "trait is unstable")]
impl Float for f64 {
#[inline]
fn nan() -> f64 { NAN }
let mut sz = cmp::max(self.size, other.size);
let mut carry = false;
- for (a, b) in self.base[..sz].iter_mut().zip(other.base[..sz].iter()) {
+ for (a, b) in self.base[..sz].iter_mut().zip(&other.base[..sz]) {
let (c, v) = (*a).full_add(*b, carry);
*a = v;
carry = c;
let sz = cmp::max(self.size, other.size);
let mut noborrow = true;
- for (a, b) in self.base[..sz].iter_mut().zip(other.base[..sz].iter()) {
+ for (a, b) in self.base[..sz].iter_mut().zip(&other.base[..sz]) {
let (c, v) = (*a).full_add(!*b, noborrow);
*a = v;
noborrow = c;
let mut sz = self.size;
let mut carry = 0;
- for a in self.base[..sz].iter_mut() {
+ for a in &mut self.base[..sz] {
let (c, v) = (*a).full_mul(other, carry);
*a = v;
carry = c;
// while this is extensively documented, this is in principle private which is
// only made public for testing. do not expose us.
#![doc(hidden)]
+#![unstable(feature = "flt2dec",
+ reason = "internal routines only exposed for testing")]
use prelude::*;
use i16;
use num::flt2dec::bignum::Digit32 as Digit;
use num::flt2dec::bignum::Big32x36 as Big;
-// FIXME(#22540) const ref to static array seems to ICE
static POW10: [Digit; 10] = [1, 10, 100, 1000, 10000, 100000,
1000000, 10000000, 100000000, 1000000000];
static TWOPOW10: [Digit; 10] = [2, 20, 200, 2000, 20000, 200000,
(len, k)
}
-
f = ((f << 64 >> (l-1)) + 1) >> 1; e += l - 64
print ' (%#018x, %5d, %4d),' % (f, e, i)
*/
-// FIXME(#22540) const ref to static array seems to ICE
+
#[doc(hidden)]
pub static CACHED_POW10: [(u64, i16, i16); 81] = [ // (f, e, k)
(0xe61acf033d1a45df, -1087, -308),
None => fallback(d, buf, limit),
}
}
-
// FIXME(#11621): Should be deprecated once CTFE is implemented in favour of
// calling the `mem::size_of` function.
-#[unstable(feature = "core")]
+#[unstable(feature = "num_bits_bytes",
+ reason = "may want to be an associated function")]
pub const BITS : usize = $bits;
// FIXME(#11621): Should be deprecated once CTFE is implemented in favour of
// calling the `mem::size_of` function.
-#[unstable(feature = "core")]
+#[unstable(feature = "num_bits_bytes",
+ reason = "may want to be an associated function")]
pub const BYTES : usize = ($bits / 8);
// FIXME(#11621): Should be deprecated once CTFE is implemented in favour of
// except according to those terms.
//! Operations and constants for pointer-sized signed integers (`isize` type)
-//!
-//! This type was recently added to replace `int`. The rollout of the
-//! new type will gradually take place over the alpha cycle along with
-//! the development of clearer conventions around integer types.
#![stable(feature = "rust1", since = "1.0.0")]
#![doc(primitive = "isize")]
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)]
pub struct Wrapping<T>(#[stable(feature = "rust1", since = "1.0.0")] pub T);
-#[unstable(feature = "core", reason = "may be removed or relocated")]
pub mod wrapping;
-
-#[unstable(feature = "core", reason = "internal routines only exposed for testing")]
pub mod flt2dec;
/// Types that have a "zero" value.
($($t:ty)*) => ($(
impl Zero for $t {
#[inline]
- fn zero() -> $t { 0 }
+ fn zero() -> Self { 0 }
}
impl One for $t {
#[inline]
- fn one() -> $t { 1 }
+ fn one() -> Self { 1 }
}
)*)
}
($($t:ty)*) => ($(
impl Zero for $t {
#[inline]
- fn zero() -> $t { 0.0 }
+ fn zero() -> Self { 0.0 }
}
impl One for $t {
#[inline]
- fn one() -> $t { 1.0 }
+ fn one() -> Self { 1.0 }
}
)*)
}
zero_one_impl_float! { f32 f64 }
macro_rules! checked_op {
- ($T:ty, $U:ty, $op:path, $x:expr, $y:expr) => {{
+ ($U:ty, $op:path, $x:expr, $y:expr) => {{
let (result, overflowed) = unsafe { $op($x as $U, $y as $U) };
- if overflowed { None } else { Some(result as $T) }
+ if overflowed { None } else { Some(result as Self) }
}}
}
// `Int` + `SignedInt` implemented for signed integers
macro_rules! int_impl {
- ($T:ident = $ActualT:ty, $UnsignedT:ty, $BITS:expr,
+ ($ActualT:ty, $UnsignedT:ty, $BITS:expr,
$add_with_overflow:path,
$sub_with_overflow:path,
$mul_with_overflow:path) => {
/// Returns the smallest value that can be represented by this integer type.
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn min_value() -> $T {
- (-1 as $T) << ($BITS - 1)
+ pub fn min_value() -> Self {
+ (-1 as Self) << ($BITS - 1)
}
/// Returns the largest value that can be represented by this integer type.
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn max_value() -> $T {
- let min = $T::min_value(); !min
+ pub fn max_value() -> Self {
+ let min = Self::min_value(); !min
}
/// Converts a string slice in a given base to an integer.
///
/// Leading and trailing whitespace represent an error.
///
- /// # Arguments
- ///
- /// * src - A string slice
- /// * radix - The base to use. Must lie in the range [2 .. 36]
- ///
- /// # Return value
+ /// # Examples
///
- /// `Err(ParseIntError)` if the string did not represent a valid number.
- /// Otherwise, `Ok(n)` where `n` is the integer represented by `src`.
+ /// ```
+ /// assert_eq!(u32::from_str_radix("A", 16), Ok(10));
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated)]
- pub fn from_str_radix(src: &str, radix: u32) -> Result<$T, ParseIntError> {
+ pub fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseIntError> {
from_str_radix(src, radix)
}
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn rotate_left(self, n: u32) -> $T {
- (self as $UnsignedT).rotate_left(n) as $T
+ pub fn rotate_left(self, n: u32) -> Self {
+ (self as $UnsignedT).rotate_left(n) as Self
}
/// Shifts the bits to the right by a specified amount, `n`,
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn rotate_right(self, n: u32) -> $T {
- (self as $UnsignedT).rotate_right(n) as $T
+ pub fn rotate_right(self, n: u32) -> Self {
+ (self as $UnsignedT).rotate_right(n) as Self
}
/// Reverses the byte order of the integer.
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn swap_bytes(self) -> $T {
- (self as $UnsignedT).swap_bytes() as $T
+ pub fn swap_bytes(self) -> Self {
+ (self as $UnsignedT).swap_bytes() as Self
}
/// Converts an integer from big endian to the target's endianness.
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn from_be(x: $T) -> $T {
+ pub fn from_be(x: Self) -> Self {
if cfg!(target_endian = "big") { x } else { x.swap_bytes() }
}
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn from_le(x: $T) -> $T {
+ pub fn from_le(x: Self) -> Self {
if cfg!(target_endian = "little") { x } else { x.swap_bytes() }
}
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn to_be(self) -> $T { // or not to be?
+ pub fn to_be(self) -> Self { // or not to be?
if cfg!(target_endian = "big") { self } else { self.swap_bytes() }
}
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn to_le(self) -> $T {
+ pub fn to_le(self) -> Self {
if cfg!(target_endian = "little") { self } else { self.swap_bytes() }
}
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn checked_add(self, other: $T) -> Option<$T> {
- checked_op!($T, $ActualT, $add_with_overflow, self, other)
+ pub fn checked_add(self, other: Self) -> Option<Self> {
+ checked_op!($ActualT, $add_with_overflow, self, other)
}
/// Checked integer subtraction. Computes `self - other`, returning
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn checked_sub(self, other: $T) -> Option<$T> {
- checked_op!($T, $ActualT, $sub_with_overflow, self, other)
+ pub fn checked_sub(self, other: Self) -> Option<Self> {
+ checked_op!($ActualT, $sub_with_overflow, self, other)
}
/// Checked integer multiplication. Computes `self * other`, returning
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn checked_mul(self, other: $T) -> Option<$T> {
- checked_op!($T, $ActualT, $mul_with_overflow, self, other)
+ pub fn checked_mul(self, other: Self) -> Option<Self> {
+ checked_op!($ActualT, $mul_with_overflow, self, other)
}
/// Checked integer division. Computes `self / other`, returning `None`
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn checked_div(self, v: $T) -> Option<$T> {
+ pub fn checked_div(self, v: Self) -> Option<Self> {
match v {
0 => None,
- -1 if self == <$T>::min_value()
+ -1 if self == Self::min_value()
=> None,
v => Some(self / v),
}
/// the numeric bounds instead of overflowing.
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn saturating_add(self, other: $T) -> $T {
+ pub fn saturating_add(self, other: Self) -> Self {
match self.checked_add(other) {
Some(x) => x,
- None if other >= <$T as Zero>::zero() => <$T>::max_value(),
- None => <$T>::min_value(),
+ None if other >= Self::zero() => Self::max_value(),
+ None => Self::min_value(),
}
}
/// at the numeric bounds instead of overflowing.
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn saturating_sub(self, other: $T) -> $T {
+ pub fn saturating_sub(self, other: Self) -> Self {
match self.checked_sub(other) {
Some(x) => x,
- None if other >= <$T as Zero>::zero() => <$T>::min_value(),
- None => <$T>::max_value(),
+ None if other >= Self::zero() => Self::min_value(),
+ None => Self::max_value(),
}
}
/// wrapping around at the boundary of the type.
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn wrapping_add(self, rhs: $T) -> $T {
+ pub fn wrapping_add(self, rhs: Self) -> Self {
unsafe {
intrinsics::overflowing_add(self, rhs)
}
/// wrapping around at the boundary of the type.
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn wrapping_sub(self, rhs: $T) -> $T {
+ pub fn wrapping_sub(self, rhs: Self) -> Self {
unsafe {
intrinsics::overflowing_sub(self, rhs)
}
/// other`, wrapping around at the boundary of the type.
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn wrapping_mul(self, rhs: $T) -> $T {
+ pub fn wrapping_mul(self, rhs: Self) -> Self {
unsafe {
intrinsics::overflowing_mul(self, rhs)
}
/// to `-MIN`, a positive value that is too large to represent
/// in the type. In such a case, this function returns `MIN`
/// itself..
- #[unstable(feature = "core", since = "1.0.0")]
+ #[stable(feature = "num_wrapping", since = "1.2.0")]
#[inline(always)]
- pub fn wrapping_div(self, rhs: $T) -> $T {
+ pub fn wrapping_div(self, rhs: Self) -> Self {
self.overflowing_div(rhs).0
}
/// implementation artifacts make `x % y` illegal for `MIN /
/// -1` on a signed type illegal (where `MIN` is the negative
/// minimal value). In such a case, this function returns `0`.
- #[unstable(feature = "core", since = "1.0.0")]
+ #[stable(feature = "num_wrapping", since = "1.2.0")]
#[inline(always)]
- pub fn wrapping_rem(self, rhs: $T) -> $T {
+ pub fn wrapping_rem(self, rhs: Self) -> Self {
self.overflowing_rem(rhs).0
}
/// negative minimal value for the type); this is a positive
/// value that is too large to represent in the type. In such
/// a case, this function returns `MIN` itself.
- #[unstable(feature = "core", since = "1.0.0")]
+ #[stable(feature = "num_wrapping", since = "1.2.0")]
#[inline(always)]
- pub fn wrapping_neg(self) -> $T {
+ pub fn wrapping_neg(self) -> Self {
self.overflowing_neg().0
}
/// Panic-free bitwise shift-left; yields `self << mask(rhs)`,
/// where `mask` removes any high-order bits of `rhs` that
/// would cause the shift to exceed the bitwidth of the type.
- #[unstable(feature = "core", since = "1.0.0")]
+ #[stable(feature = "num_wrapping", since = "1.2.0")]
#[inline(always)]
- pub fn wrapping_shl(self, rhs: u32) -> $T {
+ pub fn wrapping_shl(self, rhs: u32) -> Self {
self.overflowing_shl(rhs).0
}
/// Panic-free bitwise shift-left; yields `self >> mask(rhs)`,
/// where `mask` removes any high-order bits of `rhs` that
/// would cause the shift to exceed the bitwidth of the type.
- #[unstable(feature = "core", since = "1.0.0")]
+ #[stable(feature = "num_wrapping", since = "1.2.0")]
#[inline(always)]
- pub fn wrapping_shr(self, rhs: u32) -> $T {
+ pub fn wrapping_shr(self, rhs: u32) -> Self {
self.overflowing_shr(rhs).0
}
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn pow(self, mut exp: u32) -> $T {
+ pub fn pow(self, mut exp: u32) -> Self {
let mut base = self;
- let mut acc = <$T as One>::one();
+ let mut acc = Self::one();
let mut prev_base = self;
let mut base_oflo = false;
/// optimized code will return `i32::min_value()` without a panic.
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn abs(self) -> $T {
+ pub fn abs(self) -> Self {
if self.is_negative() {
// Note that the #[inline] above means that the overflow
// semantics of this negation depend on the crate we're being
/// - `-1` if the number is negative
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn signum(self) -> $T {
+ pub fn signum(self) -> Self {
match self {
n if n > 0 => 1,
0 => 0,
#[lang = "i8"]
impl i8 {
- int_impl! { i8 = i8, u8, 8,
+ int_impl! { i8, u8, 8,
intrinsics::i8_add_with_overflow,
intrinsics::i8_sub_with_overflow,
intrinsics::i8_mul_with_overflow }
#[lang = "i16"]
impl i16 {
- int_impl! { i16 = i16, u16, 16,
+ int_impl! { i16, u16, 16,
intrinsics::i16_add_with_overflow,
intrinsics::i16_sub_with_overflow,
intrinsics::i16_mul_with_overflow }
#[lang = "i32"]
impl i32 {
- int_impl! { i32 = i32, u32, 32,
+ int_impl! { i32, u32, 32,
intrinsics::i32_add_with_overflow,
intrinsics::i32_sub_with_overflow,
intrinsics::i32_mul_with_overflow }
#[lang = "i64"]
impl i64 {
- int_impl! { i64 = i64, u64, 64,
+ int_impl! { i64, u64, 64,
intrinsics::i64_add_with_overflow,
intrinsics::i64_sub_with_overflow,
intrinsics::i64_mul_with_overflow }
#[cfg(target_pointer_width = "32")]
#[lang = "isize"]
impl isize {
- int_impl! { isize = i32, u32, 32,
+ int_impl! { i32, u32, 32,
intrinsics::i32_add_with_overflow,
intrinsics::i32_sub_with_overflow,
intrinsics::i32_mul_with_overflow }
#[cfg(target_pointer_width = "64")]
#[lang = "isize"]
impl isize {
- int_impl! { isize = i64, u64, 64,
+ int_impl! { i64, u64, 64,
intrinsics::i64_add_with_overflow,
intrinsics::i64_sub_with_overflow,
intrinsics::i64_mul_with_overflow }
// `Int` + `UnsignedInt` implemented for signed integers
macro_rules! uint_impl {
- ($T:ty = $ActualT:ty, $BITS:expr,
+ ($ActualT:ty, $BITS:expr,
$ctpop:path,
$ctlz:path,
$cttz:path,
$mul_with_overflow:path) => {
/// Returns the smallest value that can be represented by this integer type.
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn min_value() -> $T { 0 }
+ pub fn min_value() -> Self { 0 }
/// Returns the largest value that can be represented by this integer type.
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn max_value() -> $T { !0 }
+ pub fn max_value() -> Self { !0 }
/// Converts a string slice in a given base to an integer.
///
/// Otherwise, `Ok(n)` where `n` is the integer represented by `src`.
#[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated)]
- pub fn from_str_radix(src: &str, radix: u32) -> Result<$T, ParseIntError> {
+ pub fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseIntError> {
from_str_radix(src, radix)
}
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn rotate_left(self, n: u32) -> $T {
+ pub fn rotate_left(self, n: u32) -> Self {
// Protect against undefined behaviour for over-long bit shifts
let n = n % $BITS;
(self << n) | (self >> (($BITS - n) % $BITS))
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn rotate_right(self, n: u32) -> $T {
+ pub fn rotate_right(self, n: u32) -> Self {
// Protect against undefined behaviour for over-long bit shifts
let n = n % $BITS;
(self >> n) | (self << (($BITS - n) % $BITS))
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn swap_bytes(self) -> $T {
- unsafe { $bswap(self as $ActualT) as $T }
+ pub fn swap_bytes(self) -> Self {
+ unsafe { $bswap(self as $ActualT) as Self }
}
/// Converts an integer from big endian to the target's endianness.
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn from_be(x: $T) -> $T {
+ pub fn from_be(x: Self) -> Self {
if cfg!(target_endian = "big") { x } else { x.swap_bytes() }
}
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn from_le(x: $T) -> $T {
+ pub fn from_le(x: Self) -> Self {
if cfg!(target_endian = "little") { x } else { x.swap_bytes() }
}
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn to_be(self) -> $T { // or not to be?
+ pub fn to_be(self) -> Self { // or not to be?
if cfg!(target_endian = "big") { self } else { self.swap_bytes() }
}
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn to_le(self) -> $T {
+ pub fn to_le(self) -> Self {
if cfg!(target_endian = "little") { self } else { self.swap_bytes() }
}
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn checked_add(self, other: $T) -> Option<$T> {
- checked_op!($T, $ActualT, $add_with_overflow, self, other)
+ pub fn checked_add(self, other: Self) -> Option<Self> {
+ checked_op!($ActualT, $add_with_overflow, self, other)
}
/// Checked integer subtraction. Computes `self - other`, returning
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn checked_sub(self, other: $T) -> Option<$T> {
- checked_op!($T, $ActualT, $sub_with_overflow, self, other)
+ pub fn checked_sub(self, other: Self) -> Option<Self> {
+ checked_op!($ActualT, $sub_with_overflow, self, other)
}
/// Checked integer multiplication. Computes `self * other`, returning
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn checked_mul(self, other: $T) -> Option<$T> {
- checked_op!($T, $ActualT, $mul_with_overflow, self, other)
+ pub fn checked_mul(self, other: Self) -> Option<Self> {
+ checked_op!($ActualT, $mul_with_overflow, self, other)
}
/// Checked integer division. Computes `self / other`, returning `None`
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn checked_div(self, v: $T) -> Option<$T> {
+ pub fn checked_div(self, v: Self) -> Option<Self> {
match v {
0 => None,
v => Some(self / v),
/// the numeric bounds instead of overflowing.
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn saturating_add(self, other: $T) -> $T {
+ pub fn saturating_add(self, other: Self) -> Self {
match self.checked_add(other) {
Some(x) => x,
- None if other >= <$T as Zero>::zero() => <$T>::max_value(),
- None => <$T>::min_value(),
+ None if other >= Self::zero() => Self::max_value(),
+ None => Self::min_value(),
}
}
/// at the numeric bounds instead of overflowing.
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn saturating_sub(self, other: $T) -> $T {
+ pub fn saturating_sub(self, other: Self) -> Self {
match self.checked_sub(other) {
Some(x) => x,
- None if other >= <$T as Zero>::zero() => <$T>::min_value(),
- None => <$T>::max_value(),
+ None if other >= Self::zero() => Self::min_value(),
+ None => Self::max_value(),
}
}
/// wrapping around at the boundary of the type.
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn wrapping_add(self, rhs: $T) -> $T {
+ pub fn wrapping_add(self, rhs: Self) -> Self {
unsafe {
intrinsics::overflowing_add(self, rhs)
}
/// wrapping around at the boundary of the type.
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn wrapping_sub(self, rhs: $T) -> $T {
+ pub fn wrapping_sub(self, rhs: Self) -> Self {
unsafe {
intrinsics::overflowing_sub(self, rhs)
}
/// other`, wrapping around at the boundary of the type.
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn wrapping_mul(self, rhs: $T) -> $T {
+ pub fn wrapping_mul(self, rhs: Self) -> Self {
unsafe {
intrinsics::overflowing_mul(self, rhs)
}
/// to `-MIN`, a positive value that is too large to represent
/// in the type. In such a case, this function returns `MIN`
/// itself..
- #[unstable(feature = "core", since = "1.0.0")]
+ #[stable(feature = "num_wrapping", since = "1.2.0")]
#[inline(always)]
- pub fn wrapping_div(self, rhs: $T) -> $T {
+ pub fn wrapping_div(self, rhs: Self) -> Self {
self.overflowing_div(rhs).0
}
/// implementation artifacts make `x % y` illegal for `MIN /
/// -1` on a signed type illegal (where `MIN` is the negative
/// minimal value). In such a case, this function returns `0`.
- #[unstable(feature = "core", since = "1.0.0")]
+ #[stable(feature = "num_wrapping", since = "1.2.0")]
#[inline(always)]
- pub fn wrapping_rem(self, rhs: $T) -> $T {
+ pub fn wrapping_rem(self, rhs: Self) -> Self {
self.overflowing_rem(rhs).0
}
/// negative minimal value for the type); this is a positive
/// value that is too large to represent in the type. In such
/// a case, this function returns `MIN` itself.
- #[unstable(feature = "core", since = "1.0.0")]
+ #[stable(feature = "num_wrapping", since = "1.2.0")]
#[inline(always)]
- pub fn wrapping_neg(self) -> $T {
+ pub fn wrapping_neg(self) -> Self {
self.overflowing_neg().0
}
/// Panic-free bitwise shift-left; yields `self << mask(rhs)`,
/// where `mask` removes any high-order bits of `rhs` that
/// would cause the shift to exceed the bitwidth of the type.
- #[unstable(feature = "core", since = "1.0.0")]
+ #[stable(feature = "num_wrapping", since = "1.2.0")]
#[inline(always)]
- pub fn wrapping_shl(self, rhs: u32) -> $T {
+ pub fn wrapping_shl(self, rhs: u32) -> Self {
self.overflowing_shl(rhs).0
}
/// Panic-free bitwise shift-left; yields `self >> mask(rhs)`,
/// where `mask` removes any high-order bits of `rhs` that
/// would cause the shift to exceed the bitwidth of the type.
- #[unstable(feature = "core", since = "1.0.0")]
+ #[stable(feature = "num_wrapping", since = "1.2.0")]
#[inline(always)]
- pub fn wrapping_shr(self, rhs: u32) -> $T {
+ pub fn wrapping_shr(self, rhs: u32) -> Self {
self.overflowing_shr(rhs).0
}
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn pow(self, mut exp: u32) -> $T {
+ pub fn pow(self, mut exp: u32) -> Self {
let mut base = self;
- let mut acc = <$T as One>::one();
+ let mut acc = Self::one();
let mut prev_base = self;
let mut base_oflo = false;
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn is_power_of_two(self) -> bool {
- (self.wrapping_sub(<$T as One>::one())) & self == <$T as Zero>::zero() &&
- !(self == <$T as Zero>::zero())
+ (self.wrapping_sub(Self::one())) & self == Self::zero() &&
+ !(self == Self::zero())
}
/// Returns the smallest power of two greater than or equal to `self`.
/// Unspecified behavior on overflow.
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn next_power_of_two(self) -> $T {
- let bits = size_of::<$T>() * 8;
- let one: $T = <$T as One>::one();
+ pub fn next_power_of_two(self) -> Self {
+ let bits = size_of::<Self>() * 8;
+ let one: Self = Self::one();
one << ((bits - self.wrapping_sub(one).leading_zeros() as usize) % bits)
}
/// the next power of two is greater than the type's maximum value,
/// `None` is returned, otherwise the power of two is wrapped in `Some`.
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn checked_next_power_of_two(self) -> Option<$T> {
+ pub fn checked_next_power_of_two(self) -> Option<Self> {
let npot = self.next_power_of_two();
if npot >= self {
Some(npot)
#[lang = "u8"]
impl u8 {
- uint_impl! { u8 = u8, 8,
+ uint_impl! { u8, 8,
intrinsics::ctpop8,
intrinsics::ctlz8,
intrinsics::cttz8,
#[lang = "u16"]
impl u16 {
- uint_impl! { u16 = u16, 16,
+ uint_impl! { u16, 16,
intrinsics::ctpop16,
intrinsics::ctlz16,
intrinsics::cttz16,
#[lang = "u32"]
impl u32 {
- uint_impl! { u32 = u32, 32,
+ uint_impl! { u32, 32,
intrinsics::ctpop32,
intrinsics::ctlz32,
intrinsics::cttz32,
#[lang = "u64"]
impl u64 {
- uint_impl! { u64 = u64, 64,
+ uint_impl! { u64, 64,
intrinsics::ctpop64,
intrinsics::ctlz64,
intrinsics::cttz64,
#[cfg(target_pointer_width = "32")]
#[lang = "usize"]
impl usize {
- uint_impl! { usize = u32, 32,
+ uint_impl! { u32, 32,
intrinsics::ctpop32,
intrinsics::ctlz32,
intrinsics::cttz32,
#[cfg(target_pointer_width = "64")]
#[lang = "usize"]
impl usize {
- uint_impl! { usize = u64, 64,
+ uint_impl! { u64, 64,
intrinsics::ctpop64,
intrinsics::ctlz64,
intrinsics::cttz64,
/// A built-in floating point number.
#[doc(hidden)]
+#[unstable(feature = "core_float",
+ reason = "stable interface is via `impl f{32,64}` in later crates")]
pub trait Float {
/// Returns the NaN value.
fn nan() -> Self;
}
macro_rules! from_str_float_impl {
- ($T:ident) => {
+ ($t:ty) => {
#[stable(feature = "rust1", since = "1.0.0")]
- impl FromStr for $T {
+ impl FromStr for $t {
type Err = ParseFloatError;
/// Converts a string in base 10 to a float.
/// This function accepts strings such as
///
/// * '3.14'
- /// * '+3.14', equivalent to '3.14'
/// * '-3.14'
/// * '2.5E10', or equivalently, '2.5e10'
/// * '2.5E-10'
/// * '.' (understood as 0)
/// * '5.'
/// * '.5', or, equivalently, '0.5'
- /// * '+inf', 'inf', '-inf', 'NaN'
+ /// * 'inf', '-inf', 'NaN'
///
/// Leading and trailing whitespace represent an error.
///
/// number represented by `src`.
#[inline]
#[allow(deprecated)]
- fn from_str(src: &str) -> Result<$T, ParseFloatError> {
- $T::from_str_radix(src, 10)
+ fn from_str(src: &str) -> Result<Self, ParseFloatError> {
+ Self::from_str_radix(src, 10)
}
}
}
from_str_float_impl!(f64);
macro_rules! from_str_radix_int_impl {
- ($($T:ident)*) => {$(
+ ($($t:ty)*) => {$(
#[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated)]
- impl FromStr for $T {
+ impl FromStr for $t {
type Err = ParseIntError;
- fn from_str(src: &str) -> Result<$T, ParseIntError> {
+ fn from_str(src: &str) -> Result<Self, ParseIntError> {
from_str_radix(src, 10)
}
}
}
macro_rules! doit {
- ($($t:ident)*) => ($(impl FromStrRadixHelper for $t {
- fn min_value() -> Self { <$t>::min_value() }
- fn from_u32(u: u32) -> Self { u as $t }
+ ($($t:ty)*) => ($(impl FromStrRadixHelper for $t {
+ fn min_value() -> Self { Self::min_value() }
+ fn from_u32(u: u32) -> Self { u as Self }
fn checked_mul(&self, other: u32) -> Option<Self> {
- <$t>::checked_mul(*self, other as $t)
+ Self::checked_mul(*self, other as Self)
}
fn checked_sub(&self, other: u32) -> Option<Self> {
- <$t>::checked_sub(*self, other as $t)
+ Self::checked_sub(*self, other as Self)
}
fn checked_add(&self, other: u32) -> Option<Self> {
- <$t>::checked_add(*self, other as $t)
+ Self::checked_add(*self, other as Self)
}
})*)
}
}
impl ParseIntError {
- #[unstable(feature = "core", reason = "available through Error trait")]
- pub fn description(&self) -> &str {
+ #[unstable(feature = "int_error_internals",
+ reason = "available through Error trait and this method should \
+ not be exposed publicly")]
+ #[doc(hidden)]
+ pub fn __description(&self) -> &str {
match self.kind {
IntErrorKind::Empty => "cannot parse integer from empty string",
IntErrorKind::InvalidDigit => "invalid digit found in string",
#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Display for ParseIntError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- self.description().fmt(f)
+ self.__description().fmt(f)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
pub struct ParseFloatError {
#[doc(hidden)]
+ #[unstable(feature = "float_error_internals",
+ reason = "should not be exposed publicly")]
pub __kind: FloatErrorKind
}
#[derive(Debug, Clone, PartialEq)]
+#[unstable(feature = "float_error_internals",
+ reason = "should not be exposed publicly")]
+#[doc(hidden)]
pub enum FloatErrorKind {
Empty,
Invalid,
macro_rules! uint_module { ($T:ty, $T_SIGNED:ty, $bits:expr) => (
-#[unstable(feature = "core")]
+#[unstable(feature = "num_bits_bytes",
+ reason = "may want to be an associated function")]
pub const BITS : usize = $bits;
-#[unstable(feature = "core")]
+#[unstable(feature = "num_bits_bytes",
+ reason = "may want to be an associated function")]
pub const BYTES : usize = ($bits / 8);
#[stable(feature = "rust1", since = "1.0.0")]
// except according to those terms.
//! Operations and constants for pointer-sized unsigned integers (`usize` type)
-//!
-//! This type was recently added to replace `uint`. The rollout of the
-//! new type will gradually take place over the alpha cycle along with
-//! the development of clearer conventions around integer types.
#![stable(feature = "rust1", since = "1.0.0")]
#![doc(primitive = "usize")]
#![allow(missing_docs)]
#![allow(deprecated)]
+#![unstable(feature = "wrapping", reason = "may be removed or relocated")]
use super::Wrapping;
use ::{i8,i16,i32,i64};
-#[unstable(feature = "core", reason = "may be removed, renamed, or relocated")]
pub trait OverflowingOps {
fn overflowing_add(self, rhs: Self) -> (Self, bool);
fn overflowing_sub(self, rhs: Self) -> (Self, bool);
//!
//! # Examples
//!
-//! This example creates a `Point` struct that implements `Add` and `Sub`, and then
-//! demonstrates adding and subtracting two `Point`s.
+//! This example creates a `Point` struct that implements `Add` and `Sub`, and
+//! then demonstrates adding and subtracting two `Point`s.
//!
//! ```rust
//! use std::ops::{Add, Sub};
//! }
//! ```
//!
-//! See the documentation for each trait for a minimum implementation that prints
-//! something to the screen.
+//! See the documentation for each trait for a minimum implementation that
+//! prints something to the screen.
#![stable(feature = "rust1", since = "1.0.0")]
-use marker::Sized;
+use marker::{Sized, Unsize};
use fmt;
-#[cfg(not(stage0))]
-use marker::Unsize;
-
-/// The `Drop` trait is used to run some code when a value goes out of scope. This
-/// is sometimes called a 'destructor'.
+/// The `Drop` trait is used to run some code when a value goes out of scope.
+/// This is sometimes called a 'destructor'.
///
/// # Examples
///
-/// A trivial implementation of `Drop`. The `drop` method is called when `_x` goes
-/// out of scope, and therefore `main` prints `Dropping!`.
+/// A trivial implementation of `Drop`. The `drop` method is called when `_x`
+/// goes out of scope, and therefore `main` prints `Dropping!`.
///
/// ```
/// struct HasDrop;
// based on "op T" where T is expected to be `Copy`able
macro_rules! forward_ref_unop {
(impl $imp:ident, $method:ident for $t:ty) => {
- #[unstable(feature = "core",
- reason = "recently added, waiting for dust to settle")]
+ #[stable(feature = "rust1", since = "1.0.0")]
impl<'a> $imp for &'a $t {
type Output = <$t as $imp>::Output;
// based on "T op U" where T and U are expected to be `Copy`able
macro_rules! forward_ref_binop {
(impl $imp:ident, $method:ident for $t:ty, $u:ty) => {
- #[unstable(feature = "core",
- reason = "recently added, waiting for dust to settle")]
+ #[stable(feature = "rust1", since = "1.0.0")]
impl<'a> $imp<$u> for &'a $t {
type Output = <$t as $imp<$u>>::Output;
}
}
- #[unstable(feature = "core",
- reason = "recently added, waiting for dust to settle")]
+ #[stable(feature = "rust1", since = "1.0.0")]
impl<'a> $imp<&'a $u> for $t {
type Output = <$t as $imp<$u>>::Output;
}
}
- #[unstable(feature = "core",
- reason = "recently added, waiting for dust to settle")]
+ #[stable(feature = "rust1", since = "1.0.0")]
impl<'a, 'b> $imp<&'a $u> for &'b $t {
type Output = <$t as $imp<$u>>::Output;
/// Trait that indicates that this is a pointer or a wrapper for one,
/// where unsizing can be performed on the pointee.
-#[unstable(feature = "core")]
-#[cfg(not(stage0))]
+#[unstable(feature = "coerce_unsized")]
#[lang="coerce_unsized"]
pub trait CoerceUnsized<T> {
// Empty.
}
// &mut T -> &mut U
-#[cfg(not(stage0))]
impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {}
// &mut T -> &U
-#[cfg(not(stage0))]
impl<'a, 'b: 'a, T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b mut T {}
// &mut T -> *mut U
-#[cfg(not(stage0))]
impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for &'a mut T {}
// &mut T -> *const U
-#[cfg(not(stage0))]
impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for &'a mut T {}
// &T -> &U
-#[cfg(not(stage0))]
impl<'a, 'b: 'a, T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
// &T -> *const U
-#[cfg(not(stage0))]
impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for &'a T {}
// *mut T -> *mut U
-#[cfg(not(stage0))]
impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
// *mut T -> *const U
-#[cfg(not(stage0))]
impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *mut T {}
// *const T -> *const U
-#[cfg(not(stage0))]
impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}
//! // but to start with we've just got `None`.
//! let mut name_of_biggest_animal = None;
//! let mut size_of_biggest_animal = 0;
-//! for big_thing in all_the_big_things.iter() {
+//! for big_thing in &all_the_big_things {
//! match *big_thing {
//! Kingdom::Animal(size, name) if size > size_of_biggest_animal => {
//! // Now we've found the name of some big animal
/// # Examples
///
/// ```
- /// # #![feature(core)]
+ /// # #![feature(as_slice)]
/// let mut x = Some("Diamonds");
/// {
/// let v = x.as_mut_slice();
/// assert_eq!(x, Some("Dirt"));
/// ```
#[inline]
- #[unstable(feature = "core",
+ #[unstable(feature = "as_slice",
reason = "waiting for mut conventions")]
pub fn as_mut_slice<'r>(&'r mut self) -> &'r mut [T] {
match *self {
///
/// ```{.should_panic}
/// let x: Option<&str> = None;
- /// x.expect("the world is ending"); // panics with `world is ending`
+ /// x.expect("the world is ending"); // panics with `the world is ending`
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
/// Convert an `Option<String>` into an `Option<usize>`, consuming the original:
///
/// ```
- /// let num_as_str: Option<String> = Some("10".to_string());
- /// // `Option::map` takes self *by value*, consuming `num_as_str`
- /// let num_as_int: Option<usize> = num_as_str.map(|n| n.len());
+ /// let maybe_some_string = Some(String::from("Hello, World!"));
+ /// // `Option::map` takes self *by value*, consuming `maybe_some_string`
+ /// let maybe_some_len = maybe_some_string.map(|s| s.len());
+ ///
+ /// assert_eq!(maybe_some_len, Some(13));
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
}
}
- /// Applies a function to the contained value or returns a default.
+ /// Applies a function to the contained value (if any),
+ /// or returns a `default` (if not).
///
/// # Examples
///
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn map_or<U, F: FnOnce(T) -> U>(self, def: U, f: F) -> U {
+ pub fn map_or<U, F: FnOnce(T) -> U>(self, default: U, f: F) -> U {
match self {
Some(t) => f(t),
- None => def
+ None => default,
}
}
- /// Applies a function to the contained value or computes a default.
+ /// Applies a function to the contained value (if any),
+ /// or computes a `default` (if not).
///
/// # Examples
///
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn map_or_else<U, D: FnOnce() -> U, F: FnOnce(T) -> U>(self, def: D, f: F) -> U {
+ pub fn map_or_else<U, D: FnOnce() -> U, F: FnOnce(T) -> U>(self, default: D, f: F) -> U {
match self {
Some(t) => f(t),
- None => def()
+ None => default()
}
}
/// # Examples
///
/// ```
- /// # #![feature(core)]
/// let x = Some("foo");
/// assert_eq!(x.ok_or(0), Ok("foo"));
///
/// # Examples
///
/// ```
- /// # #![feature(core)]
/// let x = Some("foo");
/// assert_eq!(x.ok_or_else(|| 0), Ok("foo"));
///
/// # Examples
///
/// ```
- /// # #![feature(core)]
/// let mut x = Some(4);
/// match x.iter_mut().next() {
/// Some(&mut ref mut v) => *v = 42,
impl<'a, A> ExactSizeIterator for IterMut<'a, A> {}
/// An iterator over the item contained inside an Option.
+#[derive(Clone)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct IntoIter<A> { inner: Item<A> }
//! library, but the location of this may change over time.
#![allow(dead_code, missing_docs)]
+#![unstable(feature = "core_panic",
+ reason = "internal details of the implementation of the `panic!` \
+ and related macros")]
use fmt;
//! use core::prelude::*;
//! ```
+#![unstable(feature = "core_prelude",
+ reason = "the libcore prelude has not been scrutinized and \
+ stabilized yet")]
+
// Reexported core operators
pub use marker::{Copy, Send, Sized, Sync};
pub use ops::{Drop, Fn, FnMut, FnOnce};
pub use mem::drop;
// Reexported types and traits
-
pub use char::CharExt;
pub use clone::Clone;
pub use cmp::{PartialEq, PartialOrd, Eq, Ord};
// FIXME: talk about offset, copy_memory, copy_nonoverlapping_memory
-//! Operations on unsafe pointers, `*const T`, and `*mut T`.
+//! Operations on raw pointers, `*const T`, and `*mut T`.
//!
-//! Working with unsafe pointers in Rust is uncommon,
+//! Working with raw pointers in Rust is uncommon,
//! typically limited to a few patterns.
//!
//! Use the `null` function to create null pointers, and the `is_null` method
//! of the `*const T` type to check for null. The `*const T` type also defines
//! the `offset` method, for pointer math.
//!
-//! # Common ways to create unsafe pointers
+//! # Common ways to create raw pointers
//!
//! ## 1. Coerce a reference (`&T`) or mutable reference (`&mut T`).
//!
//! the raw pointer. It doesn't destroy `T` or deallocate any memory.
//!
//! ```
-//! # #![feature(alloc)]
+//! # #![feature(box_raw)]
//! use std::boxed;
//!
//! unsafe {
//!
//! Usually you wouldn't literally use `malloc` and `free` from Rust,
//! but C APIs hand out a lot of pointers generally, so are a common source
-//! of unsafe pointers in Rust.
+//! of raw pointers in Rust.
#![stable(feature = "rust1", since = "1.0.0")]
#![doc(primitive = "pointer")]
///
/// This is unsafe for the same reasons that `read` is unsafe.
#[inline(always)]
-#[unstable(feature = "core",
+#[unstable(feature = "read_and_zero",
reason = "may play a larger role in std::ptr future extensions")]
pub unsafe fn read_and_zero<T>(dest: *mut T) -> T {
// Copy the data out from `dest`:
/// Variant of read_and_zero that writes the specific drop-flag byte
/// (which may be more appropriate than zero).
#[inline(always)]
-#[unstable(feature = "core",
+#[unstable(feature = "filling_drop",
reason = "may play a larger role in std::ptr future extensions")]
pub unsafe fn read_and_drop<T>(dest: *mut T) -> T {
// Copy the data out from `dest`:
/// null-safety, it is important to note that this is still an unsafe
/// operation because the returned value could be pointing to invalid
/// memory.
- #[unstable(feature = "core",
- reason = "Option is not clearly the right return type, and we may want \
- to tie the return lifetime to a borrow of the raw pointer")]
+ #[unstable(feature = "ptr_as_ref",
+ reason = "Option is not clearly the right return type, and we \
+ may want to tie the return lifetime to a borrow of \
+ the raw pointer")]
#[inline]
pub unsafe fn as_ref<'a>(&self) -> Option<&'a T> where T: Sized {
if self.is_null() {
/// null-safety, it is important to note that this is still an unsafe
/// operation because the returned value could be pointing to invalid
/// memory.
- #[unstable(feature = "core",
- reason = "Option is not clearly the right return type, and we may want \
- to tie the return lifetime to a borrow of the raw pointer")]
+ #[unstable(feature = "ptr_as_ref",
+ reason = "Option is not clearly the right return type, and we \
+ may want to tie the return lifetime to a borrow of \
+ the raw pointer")]
#[inline]
pub unsafe fn as_ref<'a>(&self) -> Option<&'a T> where T: Sized {
if self.is_null() {
///
/// As with `as_ref`, this is unsafe because it cannot verify the validity
/// of the returned pointer.
- #[unstable(feature = "core",
+ #[unstable(feature = "ptr_as_ref",
reason = "return value does not necessarily convey all possible \
information")]
#[inline]
/// modified without a unique path to the `Unique` reference. Useful
/// for building abstractions like `Vec<T>` or `Box<T>`, which
/// internally use raw pointers to manage the memory that they own.
-#[unstable(feature = "unique")]
+#[unstable(feature = "unique", reason = "needs an RFC to flesh out design")]
pub struct Unique<T: ?Sized> {
pointer: NonZero<*const T>,
+ // NOTE: this marker has no consequences for variance, but is necessary
+ // for dropck to understand that we logically own a `T`.
+ //
+ // For details, see:
+ // https://github.com/rust-lang/rfcs/blob/master/text/0769-sound-generic-drop.md#phantom-data
_marker: PhantomData<T>,
}
#[unstable(feature = "unique")]
unsafe impl<T: Sync + ?Sized> Sync for Unique<T> { }
+#[unstable(feature = "unique")]
impl<T: ?Sized> Unique<T> {
/// Creates a new `Unique`.
- #[unstable(feature = "unique")]
pub unsafe fn new(ptr: *mut T) -> Unique<T> {
Unique { pointer: NonZero::new(ptr), _marker: PhantomData }
}
/// Dereferences the content.
- #[unstable(feature = "unique")]
pub unsafe fn get(&self) -> &T {
&**self.pointer
}
/// Mutably dereferences the content.
- #[unstable(feature = "unique")]
pub unsafe fn get_mut(&mut self) -> &mut T {
&mut ***self
}
// except according to those terms.
#![allow(missing_docs)]
-#![unstable(feature = "core")]
+#![unstable(feature = "raw")]
//! Contains struct definitions for the layout of compiler built-in types.
//!
/// # Examples
///
/// ```
-/// # #![feature(core)]
+/// # #![feature(raw)]
/// use std::raw::{self, Repr};
///
/// let slice: &[u16] = &[1, 2, 3, 4];
/// # Examples
///
/// ```
-/// # #![feature(core)]
+/// # #![feature(raw)]
/// use std::mem;
/// use std::raw;
///
//! }
//! ```
//!
-//! `try!` is imported by the prelude, and is available everywhere.
+//! `try!` is imported by the prelude and is available everywhere, but it can only
+//! be used in functions that return `Result` because of the early return of
+//! `Err` that it provides.
#![stable(feature = "rust1", since = "1.0.0")]
/// Converts from `Result<T, E>` to `&mut [T]` (without copying)
///
/// ```
- /// # #![feature(core)]
+ /// # #![feature(as_slice)]
/// let mut x: Result<&str, u32> = Ok("Gold");
/// {
/// let v = x.as_mut_slice();
/// assert!(x.as_mut_slice().is_empty());
/// ```
#[inline]
- #[unstable(feature = "core",
+ #[unstable(feature = "as_slice",
reason = "waiting for mut conventions")]
pub fn as_mut_slice(&mut self) -> &mut [T] {
match *self {
panic!("called `Result::unwrap()` on an `Err` value: {:?}", e)
}
}
+
+ /// Unwraps a result, yielding the content of an `Ok`.
+ ///
+ /// Panics if the value is an `Err`, with a panic message including the
+ /// passed message, and the content of the `Err`.
+ ///
+ /// # Examples
+ /// ```{.should_panic}
+ /// #![feature(result_expect)]
+ /// let x: Result<u32, &str> = Err("emergency failure");
+ /// x.expect("Testing expect"); // panics with `Testing expect: emergency failure`
+ /// ```
+ #[inline]
+ #[unstable(feature = "result_expect", reason = "newly introduced")]
+ pub fn expect(self, msg: &str) -> T {
+ match self {
+ Ok(t) => t,
+ Err(e) => panic!("{}: {:?}", msg, e),
+ }
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
/// If an `Err` is encountered, it is immediately returned.
/// Otherwise, the folded value is returned.
#[inline]
-#[unstable(feature = "core")]
+#[unstable(feature = "result_fold",
+ reason = "unclear if this function should exist")]
+#[deprecated(since = "1.2.0",
+ reason = "has not seen enough usage to justify its position in \
+ the standard library")]
pub fn fold<T,
V,
E,
//! provided beyond this module.
//!
//! ```rust
-//! # #![feature(core)]
+//! # #![feature(core_simd)]
//! fn main() {
//! use std::simd::f32x4;
//! let a = f32x4(40.0, 41.0, 42.0, 43.0);
//! These are all experimental. The interface may change entirely, without
//! warning.
+#![unstable(feature = "core_simd",
+ reason = "needs an RFC to flesh out the design")]
+
#![allow(non_camel_case_types)]
#![allow(missing_docs)]
-#[unstable(feature = "core")]
#[simd]
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub i8, pub i8, pub i8, pub i8,
pub i8, pub i8, pub i8, pub i8);
-#[unstable(feature = "core")]
#[simd]
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct i16x8(pub i16, pub i16, pub i16, pub i16,
pub i16, pub i16, pub i16, pub i16);
-#[unstable(feature = "core")]
#[simd]
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct i32x4(pub i32, pub i32, pub i32, pub i32);
-#[unstable(feature = "core")]
#[simd]
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct i64x2(pub i64, pub i64);
-#[unstable(feature = "core")]
#[simd]
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub u8, pub u8, pub u8, pub u8,
pub u8, pub u8, pub u8, pub u8);
-#[unstable(feature = "core")]
#[simd]
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct u16x8(pub u16, pub u16, pub u16, pub u16,
pub u16, pub u16, pub u16, pub u16);
-#[unstable(feature = "core")]
#[simd]
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct u32x4(pub u32, pub u32, pub u32, pub u32);
-#[unstable(feature = "core")]
#[simd]
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct u64x2(pub u64, pub u64);
-#[unstable(feature = "core")]
#[simd]
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct f32x4(pub f32, pub f32, pub f32, pub f32);
-#[unstable(feature = "core")]
#[simd]
#[derive(Copy, Clone, Debug)]
#[repr(C)]
/// Extension methods for slices.
#[allow(missing_docs)] // docs in libcollections
#[doc(hidden)]
+#[unstable(feature = "core_slice_ext",
+ reason = "stable interface provided by `impl [T]` in later crates")]
pub trait SliceExt {
type Item;
fn clone_from_slice(&mut self, &[Self::Item]) -> usize where Self::Item: Clone;
}
-#[unstable(feature = "core")]
+// Use macros to be generic over const/mut
+macro_rules! slice_offset {
+ ($ptr:expr, $by:expr) => {{
+ let ptr = $ptr;
+ if size_from_ptr(ptr) == 0 {
+ ::intrinsics::arith_offset(ptr as *mut i8, $by) as *mut _
+ } else {
+ ptr.offset($by)
+ }
+ }};
+}
+
+macro_rules! slice_ref {
+ ($ptr:expr) => {{
+ let ptr = $ptr;
+ if size_from_ptr(ptr) == 0 {
+ // Use a non-null pointer value
+ &mut *(1 as *mut _)
+ } else {
+ transmute(ptr)
+ }
+ }};
+}
+
impl<T> SliceExt for [T] {
type Item = T;
#[inline]
fn iter<'a>(&'a self) -> Iter<'a, T> {
unsafe {
- let p = self.as_ptr();
- assume(!p.is_null());
- if mem::size_of::<T>() == 0 {
- Iter {ptr: p,
- end: ((p as usize).wrapping_add(self.len())) as *const T,
- _marker: marker::PhantomData}
+ let p = if mem::size_of::<T>() == 0 {
+ 1 as *const _
} else {
- Iter {ptr: p,
- end: p.offset(self.len() as isize),
- _marker: marker::PhantomData}
+ let p = self.as_ptr();
+ assume(!p.is_null());
+ p
+ };
+
+ Iter {
+ ptr: p,
+ end: slice_offset!(p, self.len() as isize),
+ _marker: marker::PhantomData
}
}
}
self.repr().data
}
- #[unstable(feature = "core")]
fn binary_search_by<F>(&self, mut f: F) -> Result<usize, usize> where
F: FnMut(&T) -> Ordering
{
#[inline]
fn iter_mut<'a>(&'a mut self) -> IterMut<'a, T> {
unsafe {
- let p = self.as_mut_ptr();
- assume(!p.is_null());
- if mem::size_of::<T>() == 0 {
- IterMut {ptr: p,
- end: ((p as usize).wrapping_add(self.len())) as *mut T,
- _marker: marker::PhantomData}
+ let p = if mem::size_of::<T>() == 0 {
+ 1 as *mut _
} else {
- IterMut {ptr: p,
- end: p.offset(self.len() as isize),
- _marker: marker::PhantomData}
+ let p = self.as_mut_ptr();
+ assume(!p.is_null());
+ p
+ };
+
+ IterMut {
+ ptr: p,
+ end: slice_offset!(p, self.len() as isize),
+ _marker: marker::PhantomData
}
}
}
m >= n && needle == &self[m-n..]
}
- #[unstable(feature = "core")]
fn binary_search(&self, x: &T) -> Result<usize, usize> where T: Ord {
self.binary_search_by(|p| p.cmp(x))
}
- #[unstable(feature = "core")]
fn next_permutation(&mut self) -> bool where T: Ord {
// These cases only have 1 permutation each, so we can't do anything.
if self.len() < 2 { return false; }
true
}
- #[unstable(feature = "core")]
fn prev_permutation(&mut self) -> bool where T: Ord {
// These cases only have 1 permutation each, so we can't do anything.
if self.len() < 2 { return false; }
mem::size_of::<T>()
}
-
-// Use macros to be generic over const/mut
-macro_rules! slice_offset {
- ($ptr:expr, $by:expr) => {{
- let ptr = $ptr;
- if size_from_ptr(ptr) == 0 {
- transmute((ptr as isize).wrapping_add($by))
- } else {
- ptr.offset($by)
- }
- }};
-}
-
-macro_rules! slice_ref {
- ($ptr:expr) => {{
- let ptr = $ptr;
- if size_from_ptr(ptr) == 0 {
- // Use a non-null pointer value
- &mut *(1 as *mut _)
- } else {
- transmute(ptr)
- }
- }};
-}
-
// The shared definition of the `Iter` and `IterMut` iterators
macro_rules! iterator {
(struct $name:ident -> $ptr:ty, $elem:ty) => {
///
/// This has the same lifetime as the original slice, and so the
/// iterator can continue to be used while this exists.
- #[unstable(feature = "core")]
+ #[unstable(feature = "iter_to_slice")]
pub fn as_slice(&self) -> &'a [T] {
make_slice!(self.ptr, self.end)
}
match self.as_slice().get(n) {
Some(elem_ref) => unsafe {
self.ptr = slice_offset!(self.ptr, (n as isize).wrapping_add(1));
- Some(slice_ref!(elem_ref))
+ Some(elem_ref)
},
None => {
self.ptr = self.end;
fn clone(&self) -> Iter<'a, T> { Iter { ptr: self.ptr, end: self.end, _marker: self._marker } }
}
-#[unstable(feature = "core", reason = "trait is experimental")]
+#[unstable(feature = "iter_idx", reason = "trait is experimental")]
+#[allow(deprecated)]
impl<'a, T> RandomAccessIterator for Iter<'a, T> {
#[inline]
fn indexable(&self) -> usize {
/// to consume the iterator. Consider using the `Slice` and
/// `SliceMut` implementations for obtaining slices with more
/// restricted lifetimes that do not consume the iterator.
- #[unstable(feature = "core")]
+ #[unstable(feature = "iter_to_slice")]
pub fn into_slice(self) -> &'a mut [T] {
make_mut_slice!(self.ptr, self.end)
}
match make_mut_slice!(self.ptr, self.end).get_mut(n) {
Some(elem_ref) => unsafe {
self.ptr = slice_offset!(self.ptr, (n as isize).wrapping_add(1));
- Some(slice_ref!(elem_ref))
+ Some(elem_ref)
},
None => {
self.ptr = self.end;
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> ExactSizeIterator for Windows<'a, T> {}
-#[unstable(feature = "core", reason = "trait is experimental")]
+#[unstable(feature = "iter_idx", reason = "trait is experimental")]
+#[allow(deprecated)]
impl<'a, T> RandomAccessIterator for Windows<'a, T> {
#[inline]
fn indexable(&self) -> usize {
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> ExactSizeIterator for Chunks<'a, T> {}
-#[unstable(feature = "core", reason = "trait is experimental")]
+#[unstable(feature = "iter_idx", reason = "trait is experimental")]
+#[allow(deprecated)]
impl<'a, T> RandomAccessIterator for Chunks<'a, T> {
#[inline]
fn indexable(&self) -> usize {
//
/// Converts a pointer to A into a slice of length 1 (without copying).
-#[unstable(feature = "core")]
+#[unstable(feature = "ref_slice")]
pub fn ref_slice<'a, A>(s: &'a A) -> &'a [A] {
unsafe {
from_raw_parts(s, 1)
}
/// Converts a pointer to A into a slice of length 1 (without copying).
-#[unstable(feature = "core")]
+#[unstable(feature = "ref_slice")]
pub fn mut_ref_slice<'a, A>(s: &'a mut A) -> &'a mut [A] {
unsafe {
from_raw_parts_mut(s, 1)
//
/// Operations on `[u8]`.
-#[unstable(feature = "core", reason = "needs review")]
+#[unstable(feature = "slice_bytes", reason = "needs review")]
pub mod bytes {
use ptr;
use slice::SliceExt;
}
/// Extension methods for slices containing integers.
-#[unstable(feature = "core")]
+#[unstable(feature = "int_slice")]
+#[deprecated(since = "1.2.0",
+ reason = "has not seen much usage and may want to live in the \
+ standard library now that most slice methods are \
+ on an inherent implementation block")]
pub trait IntSliceExt<U, S> {
/// Converts the slice to an immutable slice of unsigned integers with the same width.
fn as_unsigned<'a>(&'a self) -> &'a [U];
macro_rules! impl_int_slice {
($u:ty, $s:ty, $t:ty) => {
- #[unstable(feature = "core")]
+ #[unstable(feature = "int_slice")]
+ #[allow(deprecated)]
impl IntSliceExt<$u, $s> for [$t] {
#[inline]
fn as_unsigned(&self) -> &[$u] { unsafe { transmute(self) } }
//! For more details, see std::str
#![doc(primitive = "str")]
+#![stable(feature = "rust1", since = "1.0.0")]
use self::OldSearcher::{TwoWay, TwoWayLong};
use self::pattern::Pattern;
/// Reads the next code point out of a byte iterator (assuming a
/// UTF-8-like encoding).
-#[unstable(feature = "core")]
+#[unstable(feature = "str_internals")]
#[inline]
pub fn next_code_point(bytes: &mut slice::Iter<u8>) -> Option<u32> {
// Decode UTF-8
/// Reads the last code point out of a byte iterator (assuming a
/// UTF-8-like encoding).
-#[unstable(feature = "core")]
#[inline]
-pub fn next_code_point_reverse(bytes: &mut slice::Iter<u8>) -> Option<u32> {
+fn next_code_point_reverse(bytes: &mut slice::Iter<u8>) -> Option<u32> {
// Decode UTF-8
let w = match bytes.next_back() {
None => return None,
generate_pattern_iterators! {
forward:
- /// Created with the method `.split()`.
+ #[doc="Created with the method `.split()`."]
struct Split;
reverse:
- /// Created with the method `.rsplit()`.
+ #[doc="Created with the method `.rsplit()`."]
struct RSplit;
stability:
#[stable(feature = "rust1", since = "1.0.0")]
generate_pattern_iterators! {
forward:
- /// Created with the method `.split_terminator()`.
+ #[doc="Created with the method `.split_terminator()`."]
struct SplitTerminator;
reverse:
- /// Created with the method `.rsplit_terminator()`.
+ #[doc="Created with the method `.rsplit_terminator()`."]
struct RSplitTerminator;
stability:
#[stable(feature = "rust1", since = "1.0.0")]
generate_pattern_iterators! {
forward:
- /// Created with the method `.splitn()`.
+ #[doc="Created with the method `.splitn()`."]
struct SplitN;
reverse:
- /// Created with the method `.rsplitn()`.
+ #[doc="Created with the method `.rsplitn()`."]
struct RSplitN;
stability:
#[stable(feature = "rust1", since = "1.0.0")]
generate_pattern_iterators! {
forward:
- /// Created with the method `.match_indices()`.
+ #[doc="Created with the method `.match_indices()`."]
struct MatchIndices;
reverse:
- /// Created with the method `.rmatch_indices()`.
+ #[doc="Created with the method `.rmatch_indices()`."]
struct RMatchIndices;
stability:
- #[unstable(feature = "core",
+ #[unstable(feature = "str_match_indices",
reason = "type may be removed or have its iterator impl changed")]
internal:
MatchIndicesInternal yielding ((usize, usize));
generate_pattern_iterators! {
forward:
- /// Created with the method `.matches()`.
+ #[doc="Created with the method `.matches()`."]
struct Matches;
reverse:
- /// Created with the method `.rmatches()`.
+ #[doc="Created with the method `.rmatches()`."]
struct RMatches;
stability:
- #[unstable(feature = "core", reason = "type got recently added")]
+ #[stable(feature = "str_matches", since = "1.2.0")]
internal:
MatchesInternal yielding (&'a str);
delegate double ended;
/// Methods for string slices
#[allow(missing_docs)]
#[doc(hidden)]
+#[unstable(feature = "core_str_ext",
+ reason = "stable interface provided by `impl str` in later crates")]
pub trait StrExt {
// NB there are no docs here are they're all located on the StrExt trait in
// libcollections, not here.
fn rfind<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize>
where P::Searcher: ReverseSearcher<'a>;
fn find_str<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize>;
+ fn split_at(&self, mid: usize) -> (&str, &str);
fn slice_shift_char<'a>(&'a self) -> Option<(char, &'a str)>;
fn subslice_offset(&self, inner: &str) -> usize;
fn as_ptr(&self) -> *const u8;
self.find(pat)
}
+ fn split_at(&self, mid: usize) -> (&str, &str) {
+ // is_char_boundary checks that the index is in [0, .len()]
+ if self.is_char_boundary(mid) {
+ unsafe {
+ (self.slice_unchecked(0, mid),
+ self.slice_unchecked(mid, self.len()))
+ }
+ } else {
+ slice_error_fail(self, 0, mid)
+ }
+ }
+
#[inline]
fn slice_shift_char(&self) -> Option<(char, &str)> {
if self.is_empty() {
/// Pluck a code point out of a UTF-8-like byte slice and return the
/// index of the next code point.
#[inline]
-#[unstable(feature = "core")]
-pub fn char_range_at_raw(bytes: &[u8], i: usize) -> (u32, usize) {
+fn char_range_at_raw(bytes: &[u8], i: usize) -> (u32, usize) {
if bytes[i] < 128 {
return (bytes[i] as u32, i + 1);
}
//! For more details, see the traits `Pattern`, `Searcher`,
//! `ReverseSearcher` and `DoubleEndedSearcher`.
+#![unstable(feature = "pattern",
+ reason = "API not fully fleshed out and ready to be stabilized")]
+
use prelude::*;
// Pattern
+++ /dev/null
-// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Types dealing with unsafe actions.
-
-use marker;
assert_eq!(x.load(SeqCst), 0xf731 ^ 0x137f);
}
-static S_BOOL : AtomicBool = ATOMIC_BOOL_INIT;
-static S_INT : AtomicIsize = ATOMIC_ISIZE_INIT;
-static S_UINT : AtomicUsize = ATOMIC_USIZE_INIT;
+static S_FALSE: AtomicBool = AtomicBool::new(false);
+static S_TRUE: AtomicBool = AtomicBool::new(true);
+static S_INT: AtomicIsize = AtomicIsize::new(0);
+static S_UINT: AtomicUsize = AtomicUsize::new(0);
#[test]
fn static_init() {
- assert!(!S_BOOL.load(SeqCst));
+ assert!(!S_FALSE.load(SeqCst));
+ assert!(S_TRUE.load(SeqCst));
assert!(S_INT.load(SeqCst) == 0);
assert!(S_UINT.load(SeqCst) == 0);
}
}
#[test]
-fn clone_ref_updates_flag() {
+fn ref_clone_updates_flag() {
let x = RefCell::new(0);
{
let b1 = x.borrow();
assert_eq!(x.borrow_state(), BorrowState::Reading);
{
- let _b2 = clone_ref(&b1);
+ let _b2 = Ref::clone(&b1);
assert_eq!(x.borrow_state(), BorrowState::Reading);
}
assert_eq!(x.borrow_state(), BorrowState::Reading);
assert_eq!(x.borrow_state(), BorrowState::Unused);
}
+#[test]
+fn ref_map_does_not_update_flag() {
+ let x = RefCell::new(Some(5));
+ {
+ let b1: Ref<Option<u32>> = x.borrow();
+ assert_eq!(x.borrow_state(), BorrowState::Reading);
+ {
+ let b2: Ref<u32> = Ref::map(b1, |o| o.as_ref().unwrap());
+ assert_eq!(*b2, 5);
+ assert_eq!(x.borrow_state(), BorrowState::Reading);
+ }
+ assert_eq!(x.borrow_state(), BorrowState::Unused);
+ }
+ assert_eq!(x.borrow_state(), BorrowState::Unused);
+}
+
+#[test]
+fn ref_map_accessor() {
+ struct X(RefCell<(u32, char)>);
+ impl X {
+ fn accessor(&self) -> Ref<u32> {
+ Ref::map(self.0.borrow(), |tuple| &tuple.0)
+ }
+ }
+ let x = X(RefCell::new((7, 'z')));
+ let d: Ref<u32> = x.accessor();
+ assert_eq!(*d, 7);
+}
+
+#[test]
+fn ref_filter_map_accessor() {
+ struct X(RefCell<Result<u32, ()>>);
+ impl X {
+ fn accessor(&self) -> Option<Ref<u32>> {
+ Ref::filter_map(self.0.borrow(), |r| r.as_ref().ok())
+ }
+ }
+ let x = X(RefCell::new(Ok(7)));
+ let d: Ref<u32> = x.accessor().unwrap();
+ assert_eq!(*d, 7);
+}
+
+#[test]
+fn ref_mut_map_accessor() {
+ struct X(RefCell<(u32, char)>);
+ impl X {
+ fn accessor(&self) -> RefMut<u32> {
+ RefMut::map(self.0.borrow_mut(), |tuple| &mut tuple.0)
+ }
+ }
+ let x = X(RefCell::new((7, 'z')));
+ {
+ let mut d: RefMut<u32> = x.accessor();
+ assert_eq!(*d, 7);
+ *d += 1;
+ }
+ assert_eq!(*x.0.borrow(), (8, 'z'));
+}
+
+#[test]
+fn ref_mut_filter_map_accessor() {
+ struct X(RefCell<Result<u32, ()>>);
+ impl X {
+ fn accessor(&self) -> Option<RefMut<u32>> {
+ RefMut::filter_map(self.0.borrow_mut(), |r| r.as_mut().ok())
+ }
+ }
+ let x = X(RefCell::new(Ok(7)));
+ {
+ let mut d: RefMut<u32> = x.accessor().unwrap();
+ assert_eq!(*d, 7);
+ *d += 1;
+ }
+ assert_eq!(*x.0.borrow(), Ok(8));
+}
+
#[test]
fn as_unsafe_cell() {
let c1: Cell<usize> = Cell::new(0);
fn lower(c: char) -> char {
let mut it = c.to_lowercase();
let c = it.next().unwrap();
+ // As of Unicode version 7.0.0, `SpecialCasing.txt` has no lower-case mapping
+ // to multiple code points.
assert!(it.next().is_none());
c
}
assert_eq!(lower('Μ'), 'μ');
assert_eq!(lower('Α'), 'α');
assert_eq!(lower('Σ'), 'σ');
+ assert_eq!(lower('Dž'), 'dž');
+ assert_eq!(lower('fi'), 'fi');
}
#[test]
fn test_to_uppercase() {
- fn upper(c: char) -> char {
- let mut it = c.to_uppercase();
- let c = it.next().unwrap();
- assert!(it.next().is_none());
- c
+ fn upper(c: char) -> Vec<char> {
+ c.to_uppercase().collect()
}
- assert_eq!(upper('a'), 'A');
- assert_eq!(upper('ö'), 'Ö');
- assert_eq!(upper('ß'), 'ß'); // not ẞ: Latin capital letter sharp s
- assert_eq!(upper('ü'), 'Ü');
- assert_eq!(upper('💩'), '💩');
-
- assert_eq!(upper('σ'), 'Σ');
- assert_eq!(upper('τ'), 'Τ');
- assert_eq!(upper('ι'), 'Ι');
- assert_eq!(upper('γ'), 'Γ');
- assert_eq!(upper('μ'), 'Μ');
- assert_eq!(upper('α'), 'Α');
- assert_eq!(upper('ς'), 'Σ');
+ assert_eq!(upper('a'), ['A']);
+ assert_eq!(upper('ö'), ['Ö']);
+ assert_eq!(upper('ß'), ['S', 'S']); // not ẞ: Latin capital letter sharp s
+ assert_eq!(upper('ü'), ['Ü']);
+ assert_eq!(upper('💩'), ['💩']);
+
+ assert_eq!(upper('σ'), ['Σ']);
+ assert_eq!(upper('τ'), ['Τ']);
+ assert_eq!(upper('ι'), ['Ι']);
+ assert_eq!(upper('γ'), ['Γ']);
+ assert_eq!(upper('μ'), ['Μ']);
+ assert_eq!(upper('α'), ['Α']);
+ assert_eq!(upper('ς'), ['Σ']);
+ assert_eq!(upper('Dž'), ['DŽ']);
+ assert_eq!(upper('fi'), ['F', 'I']);
+ assert_eq!(upper('ᾀ'), ['Ἀ', 'Ι']);
+}
+
+#[test]
+fn test_to_titlecase() {
+ fn title(c: char) -> Vec<char> {
+ c.to_titlecase().collect()
+ }
+ assert_eq!(title('a'), ['A']);
+ assert_eq!(title('ö'), ['Ö']);
+ assert_eq!(title('ß'), ['S', 's']); // not ẞ: Latin capital letter sharp s
+ assert_eq!(title('ü'), ['Ü']);
+ assert_eq!(title('💩'), ['💩']);
+
+ assert_eq!(title('σ'), ['Σ']);
+ assert_eq!(title('τ'), ['Τ']);
+ assert_eq!(title('ι'), ['Ι']);
+ assert_eq!(title('γ'), ['Γ']);
+ assert_eq!(title('μ'), ['Μ']);
+ assert_eq!(title('α'), ['Α']);
+ assert_eq!(title('ς'), ['Σ']);
+ assert_eq!(title('DŽ'), ['Dž']);
+ assert_eq!(title('fi'), ['F', 'i']);
+ assert_eq!(title('ᾀ'), ['ᾈ']);
}
#[test]
// No residual flags left by pointer formatting
let p = "".as_ptr();
assert_eq!(format!("{:p} {:x}", p, 16), format!("{:p} 10", p));
+
+ assert_eq!(format!("{: >3}", 'a'), " a");
}
let xs = [0, 1, 2, 3, 4, 5];
let ys = [30, 40, 50, 60];
let expected = [0, 1, 2, 3, 4, 5, 30, 40, 50, 60];
- let it = xs.iter().chain(ys.iter());
+ let it = xs.iter().chain(&ys);
let mut i = 0;
for &x in it {
assert_eq!(x, expected[i]);
let zs = [];
let expected = [0, 1, 2, 3, 4, 5, 30, 40, 50, 60];
for (i, x) in expected.iter().enumerate() {
- assert_eq!(Some(x), xs.iter().chain(ys.iter()).nth(i));
+ assert_eq!(Some(x), xs.iter().chain(&ys).nth(i));
}
- assert_eq!(zs.iter().chain(xs.iter()).nth(0), Some(&0));
+ assert_eq!(zs.iter().chain(&xs).nth(0), Some(&0));
- let mut it = xs.iter().chain(zs.iter());
+ let mut it = xs.iter().chain(&zs);
assert_eq!(it.nth(5), Some(&5));
assert_eq!(it.next(), None);
}
let xs = [0, 1, 2, 3, 4, 5];
let ys = [30, 40, 50, 60];
let zs = [];
- assert_eq!(xs.iter().chain(ys.iter()).last(), Some(&60));
- assert_eq!(zs.iter().chain(ys.iter()).last(), Some(&60));
- assert_eq!(ys.iter().chain(zs.iter()).last(), Some(&60));
- assert_eq!(zs.iter().chain(zs.iter()).last(), None);
+ assert_eq!(xs.iter().chain(&ys).last(), Some(&60));
+ assert_eq!(zs.iter().chain(&ys).last(), Some(&60));
+ assert_eq!(ys.iter().chain(&zs).last(), Some(&60));
+ assert_eq!(zs.iter().chain(&zs).last(), None);
}
#[test]
let xs = [0, 1, 2, 3, 4, 5];
let ys = [30, 40, 50, 60];
let zs = [];
- assert_eq!(xs.iter().chain(ys.iter()).count(), 10);
- assert_eq!(zs.iter().chain(ys.iter()).count(), 4);
+ assert_eq!(xs.iter().chain(&ys).count(), 10);
+ assert_eq!(zs.iter().chain(&ys).count(), 4);
}
#[test]
assert_eq!(vi.clone().take_while(|_| false).size_hint(), (0, Some(10)));
assert_eq!(vi.clone().skip_while(|_| false).size_hint(), (0, Some(10)));
assert_eq!(vi.clone().enumerate().size_hint(), (10, Some(10)));
- assert_eq!(vi.clone().chain(v2.iter()).size_hint(), (13, Some(13)));
- assert_eq!(vi.clone().zip(v2.iter()).size_hint(), (3, Some(3)));
+ assert_eq!(vi.clone().chain(v2).size_hint(), (13, Some(13)));
+ assert_eq!(vi.clone().zip(v2).size_hint(), (3, Some(3)));
assert_eq!(vi.clone().scan(0, |_,_| Some(0)).size_hint(), (0, Some(10)));
assert_eq!(vi.clone().filter(|_| false).size_hint(), (0, Some(10)));
assert_eq!(vi.clone().map(|&i| i+1).size_hint(), (10, Some(10)));
fn test_double_ended_chain() {
let xs = [1, 2, 3, 4, 5];
let ys = [7, 9, 11];
- let mut it = xs.iter().chain(ys.iter()).rev();
+ let mut it = xs.iter().chain(&ys).rev();
assert_eq!(it.next().unwrap(), &11);
assert_eq!(it.next().unwrap(), &9);
assert_eq!(it.next_back().unwrap(), &1);
fn test_double_ended_flat_map() {
let u = [0,1];
let v = [5,6,7,8];
- let mut it = u.iter().flat_map(|x| v[*x..v.len()].iter());
+ let mut it = u.iter().flat_map(|x| &v[*x..v.len()]);
assert_eq!(it.next_back().unwrap(), &8);
assert_eq!(it.next().unwrap(), &5);
assert_eq!(it.next_back().unwrap(), &7);
fn test_random_access_chain() {
let xs = [1, 2, 3, 4, 5];
let ys = [7, 9, 11];
- let mut it = xs.iter().chain(ys.iter());
+ let mut it = xs.iter().chain(&ys);
assert_eq!(it.idx(0).unwrap(), &1);
assert_eq!(it.idx(5).unwrap(), &7);
assert_eq!(it.idx(7).unwrap(), &11);
fn test_random_access_zip() {
let xs = [1, 2, 3, 4, 5];
let ys = [7, 9, 11];
- check_randacc_iter(xs.iter().zip(ys.iter()), cmp::min(xs.len(), ys.len()));
+ check_randacc_iter(xs.iter().zip(&ys), cmp::min(xs.len(), ys.len()));
}
#[test]
// Can't check len now because count consumes.
}
+#[test]
+fn test_once() {
+ let mut it = once(42);
+ assert_eq!(it.next(), Some(42));
+ assert_eq!(it.next(), None);
+}
+
+#[test]
+fn test_empty() {
+ let mut it = empty::<i32>();
+ assert_eq!(it.next(), None);
+}
+
#[bench]
fn bench_rposition(b: &mut Bencher) {
let it: Vec<usize> = (0..300).collect();
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// Do not remove on snapshot creation. Needed for bootstrap. (Issue #22364)
-#![cfg_attr(stage0, feature(custom_attribute))]
-
+#![feature(as_unsafe_cell)]
+#![feature(borrow_state)]
#![feature(box_syntax)]
-#![feature(unboxed_closures)]
+#![feature(cell_extras)]
+#![feature(cmp_partial)]
+#![feature(const_fn)]
#![feature(core)]
-#![feature(test)]
+#![feature(core_float)]
+#![feature(float_extras)]
+#![feature(float_from_str_radix)]
+#![feature(flt2dec)]
+#![feature(fmt_radix)]
+#![feature(hash_default)]
+#![feature(hasher_write)]
+#![feature(iter_arith)]
+#![feature(iter_arith)]
+#![feature(iter_cmp)]
+#![feature(iter_empty)]
+#![feature(iter_idx)]
+#![feature(iter_iterate)]
+#![feature(iter_min_max)]
+#![feature(iter_once)]
+#![feature(iter_order)]
+#![feature(iter_unfold)]
+#![feature(libc)]
+#![feature(nonzero)]
+#![feature(num_bits_bytes)]
+#![feature(ptr_as_ref)]
#![feature(rand)]
+#![feature(range_inclusive)]
+#![feature(raw)]
+#![feature(result_expect)]
+#![feature(slice_bytes)]
+#![feature(slice_patterns)]
+#![feature(step_by)]
+#![feature(test)]
+#![feature(unboxed_closures)]
#![feature(unicode)]
-#![feature(std_misc)]
-#![feature(libc)]
-#![feature(hash)]
-#![feature(debug_builders)]
#![feature(unique)]
-#![feature(step_by)]
-#![feature(slice_patterns)]
-#![feature(float_from_str_radix)]
extern crate core;
extern crate test;
// except according to those terms.
use core::option::*;
-use core::marker;
use core::mem;
use core::clone::Clone;
let x = Some(());
let mut y = Some(5);
let mut y2 = 0;
- for _x in x.iter() {
+ for _x in x {
y2 = y.take().unwrap();
}
assert_eq!(y2, 5);
#[test] #[should_panic]
fn test_option_too_much_dance() {
- let mut y = Some(marker::NoCopy);
+ struct A;
+ let mut y = Some(A);
let _y2 = y.take().unwrap();
let _y3 = y.take().unwrap();
}
let bad_err: Result<isize, &'static str> = Err("Unrecoverable mess.");
let _ : isize = bad_err.unwrap_or_else(handler);
}
+
+
+#[test]
+pub fn test_expect_ok() {
+ let ok: Result<isize, &'static str> = Ok(100);
+ assert_eq!(ok.expect("Unexpected error"), 100);
+}
+#[test]
+#[should_panic(expected="Got expected error: \"All good\"")]
+pub fn test_expect_err() {
+ let err: Result<isize, &'static str> = Err("All good");
+ err.expect("Got expected error");
+}
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
- html_favicon_url = "http://www.rust-lang.org/favicon.ico",
+ html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/")]
#![feature(libc)]
#![feature(staged_api)]
#![feature(unique)]
-#![cfg_attr(test, feature(rustc_private, rand, collections))]
+#![cfg_attr(test, feature(rustc_private, rand, vec_push_all))]
#[cfg(test)] #[macro_use] extern crate log;
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
- html_favicon_url = "http://www.rust-lang.org/favicon.ico",
+ html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/",
html_playground_url = "http://play.rust-lang.org/")]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
- html_favicon_url = "http://www.rust-lang.org/favicon.ico",
+ html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/",
html_playground_url = "http://play.rust-lang.org/")]
fn t(s: &str, i: usize, u: &[String]) {
let mut v = Vec::new();
each_split_within(s, i, |s| { v.push(s.to_string()); true });
- assert!(v.iter().zip(u.iter()).all(|(a,b)| a == b));
+ assert!(v.iter().zip(u).all(|(a,b)| a == b));
}
t("", 0, &[]);
t("", 15, &[]);
//! // (assumes that |N| \approxeq |E|)
//! let &Edges(ref v) = self;
//! let mut nodes = Vec::with_capacity(v.len());
-//! for &(s,t) in v.iter() {
+//! for &(s,t) in v {
//! nodes.push(s); nodes.push(t);
//! }
//! nodes.sort();
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
- html_favicon_url = "http://www.rust-lang.org/favicon.ico",
+ html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/")]
-#![feature(collections)]
+
#![feature(into_cow)]
+#![feature(str_escape)]
use self::LabelText::*;
}
try!(writeln(w, &["digraph ", g.graph_id().as_slice(), " {"]));
- for n in &*g.nodes() {
+ for n in g.nodes().iter() {
try!(indent(w));
let id = g.node_id(n);
if options.contains(&RenderOption::NoNodeLabels) {
}
}
- for e in &*g.edges() {
+ for e in g.edges().iter() {
let escaped_label = g.edge_label(e).escape();
try!(indent(w));
let source = g.source(e);
#![cfg_attr(not(feature = "cargo-build"), staged_api)]
#![cfg_attr(not(feature = "cargo-build"), no_std)]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
- html_favicon_url = "http://www.rust-lang.org/favicon.ico",
+ html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/",
html_playground_url = "http://play.rust-lang.org/")]
#![cfg_attr(test, feature(test))]
#[link(name = "m")]
extern {}
-#[cfg(all(target_env = "musl", not(test)))]
+// When compiling rust with musl, statically include libc.a in liblibc.rlib.
+// A cargo build of the libc crate will therefore automatically pick up the
+// libc.a symbols because liblibc is transitively linked to by the stdlib.
+#[cfg(all(target_env = "musl", not(feature = "cargo-build"), not(test)))]
#[link(name = "c", kind = "static")]
extern {}
+#[cfg(all(windows, target_env = "msvc"))]
+#[link(name = "kernel32")]
+#[link(name = "shell32")]
+#[link(name = "msvcrt")]
+extern {}
+
// libnacl provides functions that require a trip through the IRT to work.
// ie: _exit, mmap, nanosleep, etc. Anything that would otherwise require a trip
// to the kernel.
pub fn dup2(src: c_int, dst: c_int) -> c_int;
#[link_name = "_execv"]
pub fn execv(prog: *const c_char,
- argv: *mut *const c_char) -> intptr_t;
+ argv: *const *const c_char) -> intptr_t;
#[link_name = "_execve"]
- pub fn execve(prog: *const c_char, argv: *mut *const c_char,
- envp: *mut *const c_char)
+ pub fn execve(prog: *const c_char, argv: *const *const c_char,
+ envp: *const *const c_char)
-> c_int;
#[link_name = "_execvp"]
pub fn execvp(c: *const c_char,
- argv: *mut *const c_char) -> c_int;
+ argv: *const *const c_char) -> c_int;
#[link_name = "_execvpe"]
- pub fn execvpe(c: *const c_char, argv: *mut *const c_char,
- envp: *mut *const c_char) -> c_int;
+ pub fn execvpe(c: *const c_char, argv: *const *const c_char,
+ envp: *const *const c_char) -> c_int;
#[link_name = "_getcwd"]
pub fn getcwd(buf: *mut c_char, size: size_t) -> *mut c_char;
#[link_name = "_getpid"]
pub fn dup(fd: c_int) -> c_int;
pub fn dup2(src: c_int, dst: c_int) -> c_int;
pub fn execv(prog: *const c_char,
- argv: *mut *const c_char) -> c_int;
- pub fn execve(prog: *const c_char, argv: *mut *const c_char,
- envp: *mut *const c_char)
+ argv: *const *const c_char) -> c_int;
+ pub fn execve(prog: *const c_char, argv: *const *const c_char,
+ envp: *const *const c_char)
-> c_int;
pub fn execvp(c: *const c_char,
- argv: *mut *const c_char) -> c_int;
+ argv: *const *const c_char) -> c_int;
pub fn fork() -> pid_t;
pub fn fpathconf(filedes: c_int, name: c_int) -> c_long;
pub fn getcwd(buf: *mut c_char, size: size_t) -> *mut c_char;
pub fn getgroups(ngroups_max: c_int, groups: *mut gid_t)
-> c_int;
pub fn getlogin() -> *mut c_char;
- pub fn getopt(argc: c_int, argv: *mut *const c_char,
+ // GNU getopt(3) modifies its arguments despite the
+ // char * const [] prototype; see the manpage.
+ pub fn getopt(argc: c_int, argv: *mut *mut c_char,
optstr: *const c_char) -> c_int;
pub fn getpgrp() -> pid_t;
pub fn getpid() -> pid_t;
pub fn dup(fd: c_int) -> c_int;
pub fn dup2(src: c_int, dst: c_int) -> c_int;
pub fn execv(prog: *const c_char,
- argv: *mut *const c_char) -> c_int;
- pub fn execve(prog: *const c_char, argv: *mut *const c_char,
- envp: *mut *const c_char)
+ argv: *const *const c_char) -> c_int;
+ pub fn execve(prog: *const c_char, argv: *const *const c_char,
+ envp: *const *const c_char)
-> c_int;
pub fn execvp(c: *const c_char,
- argv: *mut *const c_char) -> c_int;
+ argv: *const *const c_char) -> c_int;
pub fn fork() -> pid_t;
pub fn getcwd(buf: *mut c_char, size: size_t) -> *mut c_char;
pub fn getegid() -> gid_t;
pub fn geteuid() -> uid_t;
pub fn getgid() -> gid_t;
pub fn getlogin() -> *mut c_char;
- pub fn getopt(argc: c_int, argv: *mut *const c_char,
+ pub fn getopt(argc: c_int, argv: *const *const c_char,
optstr: *const c_char) -> c_int;
pub fn getuid() -> uid_t;
pub fn getsid(pid: pid_t) -> pid_t;
lpOverlapped: LPOVERLAPPED) -> BOOL;
pub fn WriteFile(hFile: HANDLE,
lpBuffer: LPVOID,
- nNumberOfBytesToRead: DWORD,
- lpNumberOfBytesRead: LPDWORD,
+ nNumberOfBytesToWrite: DWORD,
+ lpNumberOfBytesWritten: LPDWORD,
lpOverlapped: LPOVERLAPPED) -> BOOL;
pub fn SetFilePointerEx(hFile: HANDLE,
liDistanceToMove: LARGE_INTEGER,
pub level: u32,
}
-pub static LOG_LEVEL_NAMES: [&'static str; 4] = ["ERROR", "WARN", "INFO",
+pub const LOG_LEVEL_NAMES: [&'static str; 4] = ["ERROR", "WARN", "INFO",
"DEBUG"];
/// Parse an individual log level that is either a number or a symbolic log level
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
- html_favicon_url = "http://www.rust-lang.org/favicon.ico",
+ html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/",
html_playground_url = "http://play.rust-lang.org/")]
#![deny(missing_docs)]
-#![feature(alloc)]
-#![feature(staged_api)]
+#![feature(box_raw)]
#![feature(box_syntax)]
-#![feature(core)]
-#![feature(std_misc)]
+#![feature(const_fn)]
+#![feature(iter_cmp)]
+#![feature(rt)]
+#![feature(staged_api)]
+#![feature(static_mutex)]
-use std::boxed;
use std::cell::RefCell;
use std::fmt;
use std::io::{self, Stderr};
use std::env;
use std::rt;
use std::slice;
-use std::sync::{Once, ONCE_INIT, StaticMutex, MUTEX_INIT};
+use std::sync::{Once, StaticMutex};
use directive::LOG_LEVEL_NAMES;
/// The default logging level of a crate if no other is specified.
const DEFAULT_LOG_LEVEL: u32 = 1;
-static LOCK: StaticMutex = MUTEX_INIT;
+static LOCK: StaticMutex = StaticMutex::new();
/// An unsafe constant that is the maximum logging level of any module
/// specified. This is the first line of defense to determining whether a
/// module's log statement should be emitted or not.
#[doc(hidden)]
pub fn mod_enabled(level: u32, module: &str) -> bool {
- static INIT: Once = ONCE_INIT;
+ static INIT: Once = Once::new();
INIT.call_once(init);
// It's possible for many threads are in this function, only one of them
assert!(FILTER.is_null());
match filter {
- Some(f) => FILTER = boxed::into_raw(box f),
+ Some(f) => FILTER = Box::into_raw(box f),
None => {}
}
assert!(DIRECTIVES.is_null());
- DIRECTIVES = boxed::into_raw(box directives);
+ DIRECTIVES = Box::into_raw(box directives);
// Schedule the cleanup for the globals for when the runtime exits.
let _ = rt::at_exit(move || {
self.init(&[0; KEY_WORDS]);
// set key in place
let key = &mut self.state[4 .. 4+KEY_WORDS];
- for (k, s) in key.iter_mut().zip(seed.iter()) {
+ for (k, s) in key.iter_mut().zip(seed) {
*k = *s;
}
}
// algorithm. Autogenerated by `ziggurat_tables.py`.
pub type ZigTable = &'static [f64; 257];
-pub static ZIG_NORM_R: f64 = 3.654152885361008796;
+pub const ZIG_NORM_R: f64 = 3.654152885361008796;
pub static ZIG_NORM_X: [f64; 257] =
[3.910757959537090045, 3.654152885361008796, 3.449278298560964462, 3.320244733839166074,
3.224575052047029100, 3.147889289517149969, 3.083526132001233044, 3.027837791768635434,
0.887984660763399880, 0.898095921906304051, 0.908726440060562912, 0.919991505048360247,
0.932060075968990209, 0.945198953453078028, 0.959879091812415930, 0.977101701282731328,
1.000000000000000000];
-pub static ZIG_EXP_R: f64 = 7.697117470131050077;
+pub const ZIG_EXP_R: f64 = 7.697117470131050077;
pub static ZIG_EXP_X: [f64; 257] =
[8.697117470131052741, 7.697117470131050077, 6.941033629377212577, 6.478378493832569696,
6.144164665772472667, 5.882144315795399869, 5.666410167454033697, 5.482890627526062488,
}
let r = [(0, MIDPOINT), (MIDPOINT, 0)];
- for &(mr_offset, m2_offset) in r.iter() {
+ for &(mr_offset, m2_offset) in &r {
macro_rules! rngstepp {
($j:expr, $shift:expr) => {{
}
}
- for &(mr_offset, m2_offset) in MP_VEC.iter() {
+ for &(mr_offset, m2_offset) in &MP_VEC {
for base in (0..MIDPOINT / 4).map(|i| i * 4) {
macro_rules! rngstepp {
#![crate_name = "rand"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
- html_favicon_url = "http://www.rust-lang.org/favicon.ico",
+ html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/",
html_playground_url = "http://play.rust-lang.org/")]
#![no_std]
#![unstable(feature = "rand",
reason = "use `rand` from crates.io")]
#![feature(core)]
+#![feature(core_float)]
+#![feature(core_prelude)]
+#![feature(core_slice_ext)]
#![feature(no_std)]
+#![feature(num_bits_bytes)]
#![feature(staged_api)]
#![feature(step_by)]
-#![cfg_attr(test, feature(test, rand, rustc_private))]
+#![cfg_attr(test, feature(test, rand, rustc_private, iter_order))]
#![allow(deprecated)]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
- html_favicon_url = "http://www.rust-lang.org/favicon.ico",
+ html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/",
html_playground_url = "http://play.rust-lang.org/")]
-#![feature(core)]
#![feature(rustc_private)]
#![feature(staged_api)]
+#![feature(slice_bytes)]
#![cfg_attr(test, feature(test))]
}
}
- pub fn docs<F>(d: Doc, mut it: F) -> bool where
- F: FnMut(usize, Doc) -> bool,
- {
- let mut pos = d.start;
- while pos < d.end {
- let elt_tag = try_or!(tag_at(d.data, pos), false);
- let elt_size = try_or!(tag_len_at(d.data, elt_tag), false);
- pos = elt_size.next + elt_size.val;
- let doc = Doc { data: d.data, start: elt_size.next, end: pos };
- if !it(elt_tag.val, doc) {
- return false;
+ pub fn docs<'a>(d: Doc<'a>) -> DocsIterator<'a> {
+ DocsIterator {
+ d: d
+ }
+ }
+
+ pub struct DocsIterator<'a> {
+ d: Doc<'a>,
+ }
+
+ impl<'a> Iterator for DocsIterator<'a> {
+ type Item = (usize, Doc<'a>);
+
+ fn next(&mut self) -> Option<(usize, Doc<'a>)> {
+ if self.d.start >= self.d.end {
+ return None;
}
+
+ let elt_tag = try_or!(tag_at(self.d.data, self.d.start), {
+ self.d.start = self.d.end;
+ None
+ });
+ let elt_size = try_or!(tag_len_at(self.d.data, elt_tag), {
+ self.d.start = self.d.end;
+ None
+ });
+
+ let end = elt_size.next + elt_size.val;
+ let doc = Doc {
+ data: self.d.data,
+ start: elt_size.next,
+ end: end,
+ };
+
+ self.d.start = end;
+ return Some((elt_tag.val, doc));
}
- return true;
}
- pub fn tagged_docs<F>(d: Doc, tg: usize, mut it: F) -> bool where
- F: FnMut(Doc) -> bool,
- {
- let mut pos = d.start;
- while pos < d.end {
- let elt_tag = try_or!(tag_at(d.data, pos), false);
- let elt_size = try_or!(tag_len_at(d.data, elt_tag), false);
- pos = elt_size.next + elt_size.val;
- if elt_tag.val == tg {
- let doc = Doc { data: d.data, start: elt_size.next,
- end: pos };
- if !it(doc) {
- return false;
+ pub fn tagged_docs<'a>(d: Doc<'a>, tag: usize) -> TaggedDocsIterator<'a> {
+ TaggedDocsIterator {
+ iter: docs(d),
+ tag: tag,
+ }
+ }
+
+ pub struct TaggedDocsIterator<'a> {
+ iter: DocsIterator<'a>,
+ tag: usize,
+ }
+
+ impl<'a> Iterator for TaggedDocsIterator<'a> {
+ type Item = Doc<'a>;
+
+ fn next(&mut self) -> Option<Doc<'a>> {
+ while let Some((tag, doc)) = self.iter.next() {
+ if tag == self.tag {
+ return Some(doc);
}
}
+ None
}
- return true;
}
pub fn with_doc_data<T, F>(d: Doc, f: F) -> T where
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! This module provides a simplified abstraction for working with
+//! code blocks identified by their integer node-id. In particular,
+//! it captures a common set of attributes that all "function-like
+//! things" (represented by `FnLike` instances) share. For example,
+//! all `FnLike` instances have a type signature (be it explicit or
+//! inferred). And all `FnLike` instances have a body, i.e. the code
+//! that is run when the function-like thing it represents is invoked.
+//!
+//! With the above abstraction in place, one can treat the program
+//! text as a collection of blocks of code (and most such blocks are
+//! nested within a uniquely determined `FnLike`), and users can ask
+//! for the `Code` associated with a particular NodeId.
+
+pub use self::Code::*;
+
+use ast_map::{self, Node};
+use syntax::abi;
+use syntax::ast::{Block, FnDecl, NodeId};
+use syntax::ast;
+use syntax::codemap::Span;
+use syntax::visit;
+
+/// An FnLikeNode is a Node that is like a fn, in that it has a decl
+/// and a body (as well as a NodeId, a span, etc).
+///
+/// More specifically, it is one of either:
+/// - A function item,
+/// - A closure expr (i.e. an ExprClosure), or
+/// - The default implementation for a trait method.
+///
+/// To construct one, use the `Code::from_node` function.
+#[derive(Copy, Clone)]
+pub struct FnLikeNode<'a> { node: ast_map::Node<'a> }
+
+/// MaybeFnLike wraps a method that indicates if an object
+/// corresponds to some FnLikeNode.
+pub trait MaybeFnLike { fn is_fn_like(&self) -> bool; }
+
+/// Components shared by fn-like things (fn items, methods, closures).
+pub struct FnParts<'a> {
+ pub decl: &'a FnDecl,
+ pub body: &'a Block,
+ pub kind: visit::FnKind<'a>,
+ pub span: Span,
+ pub id: NodeId,
+}
+
+impl MaybeFnLike for ast::Item {
+ fn is_fn_like(&self) -> bool {
+ match self.node { ast::ItemFn(..) => true, _ => false, }
+ }
+}
+
+impl MaybeFnLike for ast::TraitItem {
+ fn is_fn_like(&self) -> bool {
+ match self.node { ast::MethodTraitItem(_, Some(_)) => true, _ => false, }
+ }
+}
+
+impl MaybeFnLike for ast::Expr {
+ fn is_fn_like(&self) -> bool {
+ match self.node {
+ ast::ExprClosure(..) => true,
+ _ => false,
+ }
+ }
+}
+
+/// Carries either an FnLikeNode or a Block, as these are the two
+/// constructs that correspond to "code" (as in, something from which
+/// we can construct a control-flow graph).
+#[derive(Copy, Clone)]
+pub enum Code<'a> {
+ FnLikeCode(FnLikeNode<'a>),
+ BlockCode(&'a Block),
+}
+
+impl<'a> Code<'a> {
+ pub fn id(&self) -> ast::NodeId {
+ match *self {
+ FnLikeCode(node) => node.id(),
+ BlockCode(block) => block.id,
+ }
+ }
+
+ /// Attempts to construct a Code from presumed FnLike or Block node input.
+ pub fn from_node(node: Node) -> Option<Code> {
+ if let ast_map::NodeBlock(block) = node {
+ Some(BlockCode(block))
+ } else {
+ FnLikeNode::from_node(node).map(|fn_like| FnLikeCode(fn_like))
+ }
+ }
+}
+
+/// These are all the components one can extract from a fn item for
+/// use when implementing FnLikeNode operations.
+struct ItemFnParts<'a> {
+ ident: ast::Ident,
+ decl: &'a ast::FnDecl,
+ unsafety: ast::Unsafety,
+ constness: ast::Constness,
+ abi: abi::Abi,
+ vis: ast::Visibility,
+ generics: &'a ast::Generics,
+ body: &'a Block,
+ id: ast::NodeId,
+ span: Span
+}
+
+/// These are all the components one can extract from a closure expr
+/// for use when implementing FnLikeNode operations.
+struct ClosureParts<'a> {
+ decl: &'a FnDecl,
+ body: &'a Block,
+ id: NodeId,
+ span: Span
+}
+
+impl<'a> ClosureParts<'a> {
+ fn new(d: &'a FnDecl, b: &'a Block, id: NodeId, s: Span) -> ClosureParts<'a> {
+ ClosureParts { decl: d, body: b, id: id, span: s }
+ }
+}
+
+impl<'a> FnLikeNode<'a> {
+ /// Attempts to construct a FnLikeNode from presumed FnLike node input.
+ pub fn from_node(node: Node) -> Option<FnLikeNode> {
+ let fn_like = match node {
+ ast_map::NodeItem(item) => item.is_fn_like(),
+ ast_map::NodeTraitItem(tm) => tm.is_fn_like(),
+ ast_map::NodeImplItem(_) => true,
+ ast_map::NodeExpr(e) => e.is_fn_like(),
+ _ => false
+ };
+ if fn_like {
+ Some(FnLikeNode {
+ node: node
+ })
+ } else {
+ None
+ }
+ }
+
+ pub fn to_fn_parts(self) -> FnParts<'a> {
+ FnParts {
+ decl: self.decl(),
+ body: self.body(),
+ kind: self.kind(),
+ span: self.span(),
+ id: self.id(),
+ }
+ }
+
+ pub fn body(self) -> &'a Block {
+ self.handle(|i: ItemFnParts<'a>| &*i.body,
+ |_, _, _: &'a ast::MethodSig, _, body: &'a ast::Block, _| body,
+ |c: ClosureParts<'a>| c.body)
+ }
+
+ pub fn decl(self) -> &'a FnDecl {
+ self.handle(|i: ItemFnParts<'a>| &*i.decl,
+ |_, _, sig: &'a ast::MethodSig, _, _, _| &sig.decl,
+ |c: ClosureParts<'a>| c.decl)
+ }
+
+ pub fn span(self) -> Span {
+ self.handle(|i: ItemFnParts| i.span,
+ |_, _, _: &'a ast::MethodSig, _, _, span| span,
+ |c: ClosureParts| c.span)
+ }
+
+ pub fn id(self) -> NodeId {
+ self.handle(|i: ItemFnParts| i.id,
+ |id, _, _: &'a ast::MethodSig, _, _, _| id,
+ |c: ClosureParts| c.id)
+ }
+
+ pub fn kind(self) -> visit::FnKind<'a> {
+ let item = |p: ItemFnParts<'a>| -> visit::FnKind<'a> {
+ visit::FkItemFn(p.ident, p.generics, p.unsafety, p.constness, p.abi, p.vis)
+ };
+ let closure = |_: ClosureParts| {
+ visit::FkFnBlock
+ };
+ let method = |_, ident, sig: &'a ast::MethodSig, vis, _, _| {
+ visit::FkMethod(ident, sig, vis)
+ };
+ self.handle(item, method, closure)
+ }
+
+ fn handle<A, I, M, C>(self, item_fn: I, method: M, closure: C) -> A where
+ I: FnOnce(ItemFnParts<'a>) -> A,
+ M: FnOnce(NodeId,
+ ast::Ident,
+ &'a ast::MethodSig,
+ Option<ast::Visibility>,
+ &'a ast::Block,
+ Span)
+ -> A,
+ C: FnOnce(ClosureParts<'a>) -> A,
+ {
+ match self.node {
+ ast_map::NodeItem(i) => match i.node {
+ ast::ItemFn(ref decl, unsafety, constness, abi, ref generics, ref block) =>
+ item_fn(ItemFnParts {
+ id: i.id,
+ ident: i.ident,
+ decl: &**decl,
+ unsafety: unsafety,
+ body: &**block,
+ generics: generics,
+ abi: abi,
+ vis: i.vis,
+ constness: constness,
+ span: i.span
+ }),
+ _ => panic!("item FnLikeNode that is not fn-like"),
+ },
+ ast_map::NodeTraitItem(ti) => match ti.node {
+ ast::MethodTraitItem(ref sig, Some(ref body)) => {
+ method(ti.id, ti.ident, sig, None, body, ti.span)
+ }
+ _ => panic!("trait method FnLikeNode that is not fn-like"),
+ },
+ ast_map::NodeImplItem(ii) => {
+ match ii.node {
+ ast::MethodImplItem(ref sig, ref body) => {
+ method(ii.id, ii.ident, sig, Some(ii.vis), body, ii.span)
+ }
+ _ => {
+ panic!("impl method FnLikeNode that is not fn-like")
+ }
+ }
+ }
+ ast_map::NodeExpr(e) => match e.node {
+ ast::ExprClosure(_, ref decl, ref block) =>
+ closure(ClosureParts::new(&**decl, &**block, e.id, e.span)),
+ _ => panic!("expr FnLikeNode that is not fn-like"),
+ },
+ _ => panic!("other FnLikeNode that is not fn-like"),
+ }
+ }
+}
--- /dev/null
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub use self::Node::*;
+pub use self::PathElem::*;
+use self::MapEntry::*;
+
+use syntax::abi;
+use syntax::ast::*;
+use syntax::ast_util;
+use syntax::codemap::{DUMMY_SP, Span, Spanned};
+use syntax::fold::Folder;
+use syntax::parse::token;
+use syntax::print::pprust;
+use syntax::visit::{self, Visitor};
+
+use arena::TypedArena;
+use std::cell::RefCell;
+use std::fmt;
+use std::io;
+use std::iter::{self, repeat};
+use std::mem;
+use std::slice;
+
+pub mod blocks;
+
+#[derive(Clone, Copy, PartialEq, Debug)]
+pub enum PathElem {
+ PathMod(Name),
+ PathName(Name)
+}
+
+impl PathElem {
+ pub fn name(&self) -> Name {
+ match *self {
+ PathMod(name) | PathName(name) => name
+ }
+ }
+}
+
+impl fmt::Display for PathElem {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let slot = token::get_name(self.name());
+ write!(f, "{}", slot)
+ }
+}
+
+#[derive(Clone)]
+pub struct LinkedPathNode<'a> {
+ node: PathElem,
+ next: LinkedPath<'a>,
+}
+
+#[derive(Copy, Clone)]
+pub struct LinkedPath<'a>(Option<&'a LinkedPathNode<'a>>);
+
+impl<'a> LinkedPath<'a> {
+ pub fn empty() -> LinkedPath<'a> {
+ LinkedPath(None)
+ }
+
+ pub fn from(node: &'a LinkedPathNode) -> LinkedPath<'a> {
+ LinkedPath(Some(node))
+ }
+}
+
+impl<'a> Iterator for LinkedPath<'a> {
+ type Item = PathElem;
+
+ fn next(&mut self) -> Option<PathElem> {
+ match self.0 {
+ Some(node) => {
+ *self = node.next;
+ Some(node.node)
+ }
+ None => None
+ }
+ }
+}
+
+/// The type of the iterator used by with_path.
+pub type PathElems<'a, 'b> = iter::Chain<iter::Cloned<slice::Iter<'a, PathElem>>, LinkedPath<'b>>;
+
+pub fn path_to_string<PI: Iterator<Item=PathElem>>(path: PI) -> String {
+ let itr = token::get_ident_interner();
+
+ path.fold(String::new(), |mut s, e| {
+ let e = itr.get(e.name());
+ if !s.is_empty() {
+ s.push_str("::");
+ }
+ s.push_str(&e[..]);
+ s
+ })
+}
+
+#[derive(Copy, Clone, Debug)]
+pub enum Node<'ast> {
+ NodeItem(&'ast Item),
+ NodeForeignItem(&'ast ForeignItem),
+ NodeTraitItem(&'ast TraitItem),
+ NodeImplItem(&'ast ImplItem),
+ NodeVariant(&'ast Variant),
+ NodeExpr(&'ast Expr),
+ NodeStmt(&'ast Stmt),
+ NodeArg(&'ast Pat),
+ NodeLocal(&'ast Pat),
+ NodePat(&'ast Pat),
+ NodeBlock(&'ast Block),
+
+ /// NodeStructCtor represents a tuple struct.
+ NodeStructCtor(&'ast StructDef),
+
+ NodeLifetime(&'ast Lifetime),
+}
+
+/// Represents an entry and its parent Node ID
+/// The odd layout is to bring down the total size.
+#[derive(Copy, Debug)]
+enum MapEntry<'ast> {
+ /// Placeholder for holes in the map.
+ NotPresent,
+
+ /// All the node types, with a parent ID.
+ EntryItem(NodeId, &'ast Item),
+ EntryForeignItem(NodeId, &'ast ForeignItem),
+ EntryTraitItem(NodeId, &'ast TraitItem),
+ EntryImplItem(NodeId, &'ast ImplItem),
+ EntryVariant(NodeId, &'ast Variant),
+ EntryExpr(NodeId, &'ast Expr),
+ EntryStmt(NodeId, &'ast Stmt),
+ EntryArg(NodeId, &'ast Pat),
+ EntryLocal(NodeId, &'ast Pat),
+ EntryPat(NodeId, &'ast Pat),
+ EntryBlock(NodeId, &'ast Block),
+ EntryStructCtor(NodeId, &'ast StructDef),
+ EntryLifetime(NodeId, &'ast Lifetime),
+
+ /// Roots for node trees.
+ RootCrate,
+ RootInlinedParent(&'ast InlinedParent)
+}
+
+impl<'ast> Clone for MapEntry<'ast> {
+ fn clone(&self) -> MapEntry<'ast> {
+ *self
+ }
+}
+
+#[derive(Debug)]
+struct InlinedParent {
+ path: Vec<PathElem>,
+ ii: InlinedItem
+}
+
+impl<'ast> MapEntry<'ast> {
+ fn from_node(p: NodeId, node: Node<'ast>) -> MapEntry<'ast> {
+ match node {
+ NodeItem(n) => EntryItem(p, n),
+ NodeForeignItem(n) => EntryForeignItem(p, n),
+ NodeTraitItem(n) => EntryTraitItem(p, n),
+ NodeImplItem(n) => EntryImplItem(p, n),
+ NodeVariant(n) => EntryVariant(p, n),
+ NodeExpr(n) => EntryExpr(p, n),
+ NodeStmt(n) => EntryStmt(p, n),
+ NodeArg(n) => EntryArg(p, n),
+ NodeLocal(n) => EntryLocal(p, n),
+ NodePat(n) => EntryPat(p, n),
+ NodeBlock(n) => EntryBlock(p, n),
+ NodeStructCtor(n) => EntryStructCtor(p, n),
+ NodeLifetime(n) => EntryLifetime(p, n)
+ }
+ }
+
+ fn parent(self) -> Option<NodeId> {
+ Some(match self {
+ EntryItem(id, _) => id,
+ EntryForeignItem(id, _) => id,
+ EntryTraitItem(id, _) => id,
+ EntryImplItem(id, _) => id,
+ EntryVariant(id, _) => id,
+ EntryExpr(id, _) => id,
+ EntryStmt(id, _) => id,
+ EntryArg(id, _) => id,
+ EntryLocal(id, _) => id,
+ EntryPat(id, _) => id,
+ EntryBlock(id, _) => id,
+ EntryStructCtor(id, _) => id,
+ EntryLifetime(id, _) => id,
+ _ => return None
+ })
+ }
+
+ fn to_node(self) -> Option<Node<'ast>> {
+ Some(match self {
+ EntryItem(_, n) => NodeItem(n),
+ EntryForeignItem(_, n) => NodeForeignItem(n),
+ EntryTraitItem(_, n) => NodeTraitItem(n),
+ EntryImplItem(_, n) => NodeImplItem(n),
+ EntryVariant(_, n) => NodeVariant(n),
+ EntryExpr(_, n) => NodeExpr(n),
+ EntryStmt(_, n) => NodeStmt(n),
+ EntryArg(_, n) => NodeArg(n),
+ EntryLocal(_, n) => NodeLocal(n),
+ EntryPat(_, n) => NodePat(n),
+ EntryBlock(_, n) => NodeBlock(n),
+ EntryStructCtor(_, n) => NodeStructCtor(n),
+ EntryLifetime(_, n) => NodeLifetime(n),
+ _ => return None
+ })
+ }
+}
+
+/// Stores a crate and any number of inlined items from other crates.
+pub struct Forest {
+ krate: Crate,
+ inlined_items: TypedArena<InlinedParent>
+}
+
+impl Forest {
+ pub fn new(krate: Crate) -> Forest {
+ Forest {
+ krate: krate,
+ inlined_items: TypedArena::new()
+ }
+ }
+
+ pub fn krate<'ast>(&'ast self) -> &'ast Crate {
+ &self.krate
+ }
+}
+
+/// Represents a mapping from Node IDs to AST elements and their parent
+/// Node IDs
+pub struct Map<'ast> {
+ /// The backing storage for all the AST nodes.
+ forest: &'ast Forest,
+
+ /// NodeIds are sequential integers from 0, so we can be
+ /// super-compact by storing them in a vector. Not everything with
+ /// a NodeId is in the map, but empirically the occupancy is about
+ /// 75-80%, so there's not too much overhead (certainly less than
+ /// a hashmap, since they (at the time of writing) have a maximum
+ /// of 75% occupancy).
+ ///
+ /// Also, indexing is pretty quick when you've got a vector and
+ /// plain old integers.
+ map: RefCell<Vec<MapEntry<'ast>>>
+}
+
+impl<'ast> Map<'ast> {
+ fn entry_count(&self) -> usize {
+ self.map.borrow().len()
+ }
+
+ fn find_entry(&self, id: NodeId) -> Option<MapEntry<'ast>> {
+ self.map.borrow().get(id as usize).cloned()
+ }
+
+ pub fn krate(&self) -> &'ast Crate {
+ &self.forest.krate
+ }
+
+ /// Retrieve the Node corresponding to `id`, panicking if it cannot
+ /// be found.
+ pub fn get(&self, id: NodeId) -> Node<'ast> {
+ match self.find(id) {
+ Some(node) => node,
+ None => panic!("couldn't find node id {} in the AST map", id)
+ }
+ }
+
+ /// Retrieve the Node corresponding to `id`, returning None if
+ /// cannot be found.
+ pub fn find(&self, id: NodeId) -> Option<Node<'ast>> {
+ self.find_entry(id).and_then(|x| x.to_node())
+ }
+
+ /// Retrieve the parent NodeId for `id`, or `id` itself if no
+ /// parent is registered in this map.
+ pub fn get_parent(&self, id: NodeId) -> NodeId {
+ self.find_entry(id).and_then(|x| x.parent()).unwrap_or(id)
+ }
+
+ pub fn get_parent_did(&self, id: NodeId) -> DefId {
+ let parent = self.get_parent(id);
+ match self.find_entry(parent) {
+ Some(RootInlinedParent(&InlinedParent {ii: IITraitItem(did, _), ..})) => did,
+ Some(RootInlinedParent(&InlinedParent {ii: IIImplItem(did, _), ..})) => did,
+ _ => ast_util::local_def(parent)
+ }
+ }
+
+ pub fn get_foreign_abi(&self, id: NodeId) -> abi::Abi {
+ let parent = self.get_parent(id);
+ let abi = match self.find_entry(parent) {
+ Some(EntryItem(_, i)) => {
+ match i.node {
+ ItemForeignMod(ref nm) => Some(nm.abi),
+ _ => None
+ }
+ }
+ /// Wrong but OK, because the only inlined foreign items are intrinsics.
+ Some(RootInlinedParent(_)) => Some(abi::RustIntrinsic),
+ _ => None
+ };
+ match abi {
+ Some(abi) => abi,
+ None => panic!("expected foreign mod or inlined parent, found {}",
+ self.node_to_string(parent))
+ }
+ }
+
+ pub fn get_foreign_vis(&self, id: NodeId) -> Visibility {
+ let vis = self.expect_foreign_item(id).vis;
+ match self.find(self.get_parent(id)) {
+ Some(NodeItem(i)) => vis.inherit_from(i.vis),
+ _ => vis
+ }
+ }
+
+ pub fn expect_item(&self, id: NodeId) -> &'ast Item {
+ match self.find(id) {
+ Some(NodeItem(item)) => item,
+ _ => panic!("expected item, found {}", self.node_to_string(id))
+ }
+ }
+
+ pub fn expect_struct(&self, id: NodeId) -> &'ast StructDef {
+ match self.find(id) {
+ Some(NodeItem(i)) => {
+ match i.node {
+ ItemStruct(ref struct_def, _) => &**struct_def,
+ _ => panic!("struct ID bound to non-struct")
+ }
+ }
+ Some(NodeVariant(variant)) => {
+ match variant.node.kind {
+ StructVariantKind(ref struct_def) => &**struct_def,
+ _ => panic!("struct ID bound to enum variant that isn't struct-like"),
+ }
+ }
+ _ => panic!(format!("expected struct, found {}", self.node_to_string(id))),
+ }
+ }
+
+ pub fn expect_variant(&self, id: NodeId) -> &'ast Variant {
+ match self.find(id) {
+ Some(NodeVariant(variant)) => variant,
+ _ => panic!(format!("expected variant, found {}", self.node_to_string(id))),
+ }
+ }
+
+ pub fn expect_foreign_item(&self, id: NodeId) -> &'ast ForeignItem {
+ match self.find(id) {
+ Some(NodeForeignItem(item)) => item,
+ _ => panic!("expected foreign item, found {}", self.node_to_string(id))
+ }
+ }
+
+ pub fn expect_expr(&self, id: NodeId) -> &'ast Expr {
+ match self.find(id) {
+ Some(NodeExpr(expr)) => expr,
+ _ => panic!("expected expr, found {}", self.node_to_string(id))
+ }
+ }
+
+ /// returns the name associated with the given NodeId's AST
+ pub fn get_path_elem(&self, id: NodeId) -> PathElem {
+ let node = self.get(id);
+ match node {
+ NodeItem(item) => {
+ match item.node {
+ ItemMod(_) | ItemForeignMod(_) => {
+ PathMod(item.ident.name)
+ }
+ _ => PathName(item.ident.name)
+ }
+ }
+ NodeForeignItem(i) => PathName(i.ident.name),
+ NodeImplItem(ii) => PathName(ii.ident.name),
+ NodeTraitItem(ti) => PathName(ti.ident.name),
+ NodeVariant(v) => PathName(v.node.name.name),
+ _ => panic!("no path elem for {:?}", node)
+ }
+ }
+
+ pub fn with_path<T, F>(&self, id: NodeId, f: F) -> T where
+ F: FnOnce(PathElems) -> T,
+ {
+ self.with_path_next(id, LinkedPath::empty(), f)
+ }
+
+ pub fn path_to_string(&self, id: NodeId) -> String {
+ self.with_path(id, |path| path_to_string(path))
+ }
+
+ fn path_to_str_with_ident(&self, id: NodeId, i: Ident) -> String {
+ self.with_path(id, |path| {
+ path_to_string(path.chain(Some(PathName(i.name))))
+ })
+ }
+
+ fn with_path_next<T, F>(&self, id: NodeId, next: LinkedPath, f: F) -> T where
+ F: FnOnce(PathElems) -> T,
+ {
+ let parent = self.get_parent(id);
+ let parent = match self.find_entry(id) {
+ Some(EntryForeignItem(..)) | Some(EntryVariant(..)) => {
+ // Anonymous extern items, enum variants and struct ctors
+ // go in the parent scope.
+ self.get_parent(parent)
+ }
+ // But tuple struct ctors don't have names, so use the path of its
+ // parent, the struct item. Similarly with closure expressions.
+ Some(EntryStructCtor(..)) | Some(EntryExpr(..)) => {
+ return self.with_path_next(parent, next, f);
+ }
+ _ => parent
+ };
+ if parent == id {
+ match self.find_entry(id) {
+ Some(RootInlinedParent(data)) => {
+ f(data.path.iter().cloned().chain(next))
+ }
+ _ => f([].iter().cloned().chain(next))
+ }
+ } else {
+ self.with_path_next(parent, LinkedPath::from(&LinkedPathNode {
+ node: self.get_path_elem(id),
+ next: next
+ }), f)
+ }
+ }
+
+ /// Given a node ID, get a list of of attributes associated with the AST
+ /// corresponding to the Node ID
+ pub fn attrs(&self, id: NodeId) -> &'ast [Attribute] {
+ let attrs = match self.find(id) {
+ Some(NodeItem(i)) => Some(&i.attrs[..]),
+ Some(NodeForeignItem(fi)) => Some(&fi.attrs[..]),
+ Some(NodeTraitItem(ref ti)) => Some(&ti.attrs[..]),
+ Some(NodeImplItem(ref ii)) => Some(&ii.attrs[..]),
+ Some(NodeVariant(ref v)) => Some(&v.node.attrs[..]),
+ // unit/tuple structs take the attributes straight from
+ // the struct definition.
+ Some(NodeStructCtor(_)) => {
+ return self.attrs(self.get_parent(id));
+ }
+ _ => None
+ };
+ attrs.unwrap_or(&[])
+ }
+
+ /// Returns an iterator that yields the node id's with paths that
+ /// match `parts`. (Requires `parts` is non-empty.)
+ ///
+ /// For example, if given `parts` equal to `["bar", "quux"]`, then
+ /// the iterator will produce node id's for items with paths
+ /// such as `foo::bar::quux`, `bar::quux`, `other::bar::quux`, and
+ /// any other such items it can find in the map.
+ pub fn nodes_matching_suffix<'a>(&'a self, parts: &'a [String])
+ -> NodesMatchingSuffix<'a, 'ast> {
+ NodesMatchingSuffix {
+ map: self,
+ item_name: parts.last().unwrap(),
+ in_which: &parts[..parts.len() - 1],
+ idx: 0,
+ }
+ }
+
+ pub fn opt_span(&self, id: NodeId) -> Option<Span> {
+ let sp = match self.find(id) {
+ Some(NodeItem(item)) => item.span,
+ Some(NodeForeignItem(foreign_item)) => foreign_item.span,
+ Some(NodeTraitItem(trait_method)) => trait_method.span,
+ Some(NodeImplItem(ref impl_item)) => impl_item.span,
+ Some(NodeVariant(variant)) => variant.span,
+ Some(NodeExpr(expr)) => expr.span,
+ Some(NodeStmt(stmt)) => stmt.span,
+ Some(NodeArg(pat)) | Some(NodeLocal(pat)) => pat.span,
+ Some(NodePat(pat)) => pat.span,
+ Some(NodeBlock(block)) => block.span,
+ Some(NodeStructCtor(_)) => self.expect_item(self.get_parent(id)).span,
+ _ => return None,
+ };
+ Some(sp)
+ }
+
+ pub fn span(&self, id: NodeId) -> Span {
+ self.opt_span(id)
+ .unwrap_or_else(|| panic!("AstMap.span: could not find span for id {:?}", id))
+ }
+
+ pub fn def_id_span(&self, def_id: DefId, fallback: Span) -> Span {
+ if def_id.krate == LOCAL_CRATE {
+ self.opt_span(def_id.node).unwrap_or(fallback)
+ } else {
+ fallback
+ }
+ }
+
+ pub fn node_to_string(&self, id: NodeId) -> String {
+ node_id_to_string(self, id, true)
+ }
+
+ pub fn node_to_user_string(&self, id: NodeId) -> String {
+ node_id_to_string(self, id, false)
+ }
+}
+
+pub struct NodesMatchingSuffix<'a, 'ast:'a> {
+ map: &'a Map<'ast>,
+ item_name: &'a String,
+ in_which: &'a [String],
+ idx: NodeId,
+}
+
+impl<'a, 'ast> NodesMatchingSuffix<'a, 'ast> {
+ /// Returns true only if some suffix of the module path for parent
+ /// matches `self.in_which`.
+ ///
+ /// In other words: let `[x_0,x_1,...,x_k]` be `self.in_which`;
+ /// returns true if parent's path ends with the suffix
+ /// `x_0::x_1::...::x_k`.
+ fn suffix_matches(&self, parent: NodeId) -> bool {
+ let mut cursor = parent;
+ for part in self.in_which.iter().rev() {
+ let (mod_id, mod_name) = match find_first_mod_parent(self.map, cursor) {
+ None => return false,
+ Some((node_id, name)) => (node_id, name),
+ };
+ if &part[..] != mod_name.as_str() {
+ return false;
+ }
+ cursor = self.map.get_parent(mod_id);
+ }
+ return true;
+
+ // Finds the first mod in parent chain for `id`, along with
+ // that mod's name.
+ //
+ // If `id` itself is a mod named `m` with parent `p`, then
+ // returns `Some(id, m, p)`. If `id` has no mod in its parent
+ // chain, then returns `None`.
+ fn find_first_mod_parent<'a>(map: &'a Map, mut id: NodeId) -> Option<(NodeId, Name)> {
+ loop {
+ match map.find(id) {
+ None => return None,
+ Some(NodeItem(item)) if item_is_mod(&*item) =>
+ return Some((id, item.ident.name)),
+ _ => {}
+ }
+ let parent = map.get_parent(id);
+ if parent == id { return None }
+ id = parent;
+ }
+
+ fn item_is_mod(item: &Item) -> bool {
+ match item.node {
+ ItemMod(_) => true,
+ _ => false,
+ }
+ }
+ }
+ }
+
+ // We are looking at some node `n` with a given name and parent
+ // id; do their names match what I am seeking?
+ fn matches_names(&self, parent_of_n: NodeId, name: Name) -> bool {
+ name.as_str() == &self.item_name[..] &&
+ self.suffix_matches(parent_of_n)
+ }
+}
+
+impl<'a, 'ast> Iterator for NodesMatchingSuffix<'a, 'ast> {
+ type Item = NodeId;
+
+ fn next(&mut self) -> Option<NodeId> {
+ loop {
+ let idx = self.idx;
+ if idx as usize >= self.map.entry_count() {
+ return None;
+ }
+ self.idx += 1;
+ let (p, name) = match self.map.find_entry(idx) {
+ Some(EntryItem(p, n)) => (p, n.name()),
+ Some(EntryForeignItem(p, n))=> (p, n.name()),
+ Some(EntryTraitItem(p, n)) => (p, n.name()),
+ Some(EntryImplItem(p, n)) => (p, n.name()),
+ Some(EntryVariant(p, n)) => (p, n.name()),
+ _ => continue,
+ };
+ if self.matches_names(p, name) {
+ return Some(idx)
+ }
+ }
+ }
+}
+
+trait Named {
+ fn name(&self) -> Name;
+}
+
+impl<T:Named> Named for Spanned<T> { fn name(&self) -> Name { self.node.name() } }
+
+impl Named for Item { fn name(&self) -> Name { self.ident.name } }
+impl Named for ForeignItem { fn name(&self) -> Name { self.ident.name } }
+impl Named for Variant_ { fn name(&self) -> Name { self.name.name } }
+impl Named for TraitItem { fn name(&self) -> Name { self.ident.name } }
+impl Named for ImplItem { fn name(&self) -> Name { self.ident.name } }
+
+pub trait FoldOps {
+ fn new_id(&self, id: NodeId) -> NodeId {
+ id
+ }
+ fn new_def_id(&self, def_id: DefId) -> DefId {
+ def_id
+ }
+ fn new_span(&self, span: Span) -> Span {
+ span
+ }
+}
+
+/// A Folder that updates IDs and Span's according to fold_ops.
+struct IdAndSpanUpdater<F> {
+ fold_ops: F
+}
+
+impl<F: FoldOps> Folder for IdAndSpanUpdater<F> {
+ fn new_id(&mut self, id: NodeId) -> NodeId {
+ self.fold_ops.new_id(id)
+ }
+
+ fn new_span(&mut self, span: Span) -> Span {
+ self.fold_ops.new_span(span)
+ }
+}
+
+/// A Visitor that walks over an AST and collects Node's into an AST Map.
+struct NodeCollector<'ast> {
+ map: Vec<MapEntry<'ast>>,
+ /// The node in which we are currently mapping (an item or a method).
+ parent: NodeId
+}
+
+impl<'ast> NodeCollector<'ast> {
+ fn insert_entry(&mut self, id: NodeId, entry: MapEntry<'ast>) {
+ debug!("ast_map: {:?} => {:?}", id, entry);
+ let len = self.map.len();
+ if id as usize >= len {
+ self.map.extend(repeat(NotPresent).take(id as usize - len + 1));
+ }
+ self.map[id as usize] = entry;
+ }
+
+ fn insert(&mut self, id: NodeId, node: Node<'ast>) {
+ let entry = MapEntry::from_node(self.parent, node);
+ self.insert_entry(id, entry);
+ }
+
+ fn visit_fn_decl(&mut self, decl: &'ast FnDecl) {
+ for a in &decl.inputs {
+ self.insert(a.id, NodeArg(&*a.pat));
+ }
+ }
+}
+
+impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
+ fn visit_item(&mut self, i: &'ast Item) {
+ self.insert(i.id, NodeItem(i));
+ let parent = self.parent;
+ self.parent = i.id;
+ match i.node {
+ ItemImpl(_, _, _, _, _, ref impl_items) => {
+ for ii in impl_items {
+ self.insert(ii.id, NodeImplItem(ii));
+ }
+ }
+ ItemEnum(ref enum_definition, _) => {
+ for v in &enum_definition.variants {
+ self.insert(v.node.id, NodeVariant(&**v));
+ }
+ }
+ ItemForeignMod(ref nm) => {
+ for nitem in &nm.items {
+ self.insert(nitem.id, NodeForeignItem(&**nitem));
+ }
+ }
+ ItemStruct(ref struct_def, _) => {
+ // If this is a tuple-like struct, register the constructor.
+ match struct_def.ctor_id {
+ Some(ctor_id) => {
+ self.insert(ctor_id, NodeStructCtor(&**struct_def));
+ }
+ None => {}
+ }
+ }
+ ItemTrait(_, _, ref bounds, ref trait_items) => {
+ for b in bounds.iter() {
+ if let TraitTyParamBound(ref t, TraitBoundModifier::None) = *b {
+ self.insert(t.trait_ref.ref_id, NodeItem(i));
+ }
+ }
+
+ for ti in trait_items {
+ self.insert(ti.id, NodeTraitItem(ti));
+ }
+ }
+ ItemUse(ref view_path) => {
+ match view_path.node {
+ ViewPathList(_, ref paths) => {
+ for path in paths {
+ self.insert(path.node.id(), NodeItem(i));
+ }
+ }
+ _ => ()
+ }
+ }
+ _ => {}
+ }
+ visit::walk_item(self, i);
+ self.parent = parent;
+ }
+
+ fn visit_trait_item(&mut self, ti: &'ast TraitItem) {
+ let parent = self.parent;
+ self.parent = ti.id;
+ visit::walk_trait_item(self, ti);
+ self.parent = parent;
+ }
+
+ fn visit_impl_item(&mut self, ii: &'ast ImplItem) {
+ let parent = self.parent;
+ self.parent = ii.id;
+ visit::walk_impl_item(self, ii);
+ self.parent = parent;
+ }
+
+ fn visit_pat(&mut self, pat: &'ast Pat) {
+ self.insert(pat.id, match pat.node {
+ // Note: this is at least *potentially* a pattern...
+ PatIdent(..) => NodeLocal(pat),
+ _ => NodePat(pat)
+ });
+ visit::walk_pat(self, pat);
+ }
+
+ fn visit_expr(&mut self, expr: &'ast Expr) {
+ self.insert(expr.id, NodeExpr(expr));
+ visit::walk_expr(self, expr);
+ }
+
+ fn visit_stmt(&mut self, stmt: &'ast Stmt) {
+ self.insert(ast_util::stmt_id(stmt), NodeStmt(stmt));
+ visit::walk_stmt(self, stmt);
+ }
+
+ fn visit_fn(&mut self, fk: visit::FnKind<'ast>, fd: &'ast FnDecl,
+ b: &'ast Block, s: Span, _: NodeId) {
+ self.visit_fn_decl(fd);
+ visit::walk_fn(self, fk, fd, b, s);
+ }
+
+ fn visit_ty(&mut self, ty: &'ast Ty) {
+ match ty.node {
+ TyBareFn(ref fd) => {
+ self.visit_fn_decl(&*fd.decl);
+ }
+ _ => {}
+ }
+ visit::walk_ty(self, ty);
+ }
+
+ fn visit_block(&mut self, block: &'ast Block) {
+ self.insert(block.id, NodeBlock(block));
+ visit::walk_block(self, block);
+ }
+
+ fn visit_lifetime_ref(&mut self, lifetime: &'ast Lifetime) {
+ self.insert(lifetime.id, NodeLifetime(lifetime));
+ }
+
+ fn visit_lifetime_def(&mut self, def: &'ast LifetimeDef) {
+ self.visit_lifetime_ref(&def.lifetime);
+ }
+}
+
+pub fn map_crate<'ast, F: FoldOps>(forest: &'ast mut Forest, fold_ops: F) -> Map<'ast> {
+ // Replace the crate with an empty one to take it out.
+ let krate = mem::replace(&mut forest.krate, Crate {
+ module: Mod {
+ inner: DUMMY_SP,
+ items: vec![],
+ },
+ attrs: vec![],
+ config: vec![],
+ exported_macros: vec![],
+ span: DUMMY_SP
+ });
+ forest.krate = IdAndSpanUpdater { fold_ops: fold_ops }.fold_crate(krate);
+
+ let mut collector = NodeCollector {
+ map: vec![],
+ parent: CRATE_NODE_ID
+ };
+ collector.insert_entry(CRATE_NODE_ID, RootCrate);
+ visit::walk_crate(&mut collector, &forest.krate);
+ let map = collector.map;
+
+ if log_enabled!(::log::DEBUG) {
+ // This only makes sense for ordered stores; note the
+ // enumerate to count the number of entries.
+ let (entries_less_1, _) = map.iter().filter(|&x| {
+ match *x {
+ NotPresent => false,
+ _ => true
+ }
+ }).enumerate().last().expect("AST map was empty after folding?");
+
+ let entries = entries_less_1 + 1;
+ let vector_length = map.len();
+ debug!("The AST map has {} entries with a maximum of {}: occupancy {:.1}%",
+ entries, vector_length, (entries as f64 / vector_length as f64) * 100.);
+ }
+
+ Map {
+ forest: forest,
+ map: RefCell::new(map)
+ }
+}
+
+/// Used for items loaded from external crate that are being inlined into this
+/// crate. The `path` should be the path to the item but should not include
+/// the item itself.
+pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>,
+ path: Vec<PathElem>,
+ ii: InlinedItem,
+ fold_ops: F)
+ -> &'ast InlinedItem {
+ let mut fld = IdAndSpanUpdater { fold_ops: fold_ops };
+ let ii = match ii {
+ IIItem(i) => IIItem(fld.fold_item(i).expect_one("expected one item")),
+ IITraitItem(d, ti) => {
+ IITraitItem(fld.fold_ops.new_def_id(d),
+ fld.fold_trait_item(ti).expect_one("expected one trait item"))
+ }
+ IIImplItem(d, ii) => {
+ IIImplItem(fld.fold_ops.new_def_id(d),
+ fld.fold_impl_item(ii).expect_one("expected one impl item"))
+ }
+ IIForeign(i) => IIForeign(fld.fold_foreign_item(i))
+ };
+
+ let ii_parent = map.forest.inlined_items.alloc(InlinedParent {
+ path: path,
+ ii: ii
+ });
+
+ let mut collector = NodeCollector {
+ map: mem::replace(&mut *map.map.borrow_mut(), vec![]),
+ parent: fld.new_id(DUMMY_NODE_ID)
+ };
+ let ii_parent_id = collector.parent;
+ collector.insert_entry(ii_parent_id, RootInlinedParent(ii_parent));
+ visit::walk_inlined_item(&mut collector, &ii_parent.ii);
+
+ // Methods get added to the AST map when their impl is visited. Since we
+ // don't decode and instantiate the impl, but just the method, we have to
+ // add it to the table now. Likewise with foreign items.
+ match ii_parent.ii {
+ IIItem(_) => {}
+ IITraitItem(_, ref ti) => {
+ collector.insert(ti.id, NodeTraitItem(ti));
+ }
+ IIImplItem(_, ref ii) => {
+ collector.insert(ii.id, NodeImplItem(ii));
+ }
+ IIForeign(ref i) => {
+ collector.insert(i.id, NodeForeignItem(i));
+ }
+ }
+ *map.map.borrow_mut() = collector.map;
+ &ii_parent.ii
+}
+
+pub trait NodePrinter {
+ fn print_node(&mut self, node: &Node) -> io::Result<()>;
+}
+
+impl<'a> NodePrinter for pprust::State<'a> {
+ fn print_node(&mut self, node: &Node) -> io::Result<()> {
+ match *node {
+ NodeItem(a) => self.print_item(&*a),
+ NodeForeignItem(a) => self.print_foreign_item(&*a),
+ NodeTraitItem(a) => self.print_trait_item(a),
+ NodeImplItem(a) => self.print_impl_item(a),
+ NodeVariant(a) => self.print_variant(&*a),
+ NodeExpr(a) => self.print_expr(&*a),
+ NodeStmt(a) => self.print_stmt(&*a),
+ NodePat(a) => self.print_pat(&*a),
+ NodeBlock(a) => self.print_block(&*a),
+ NodeLifetime(a) => self.print_lifetime(&*a),
+
+ // these cases do not carry enough information in the
+ // ast_map to reconstruct their full structure for pretty
+ // printing.
+ NodeLocal(_) => panic!("cannot print isolated Local"),
+ NodeArg(_) => panic!("cannot print isolated Arg"),
+ NodeStructCtor(_) => panic!("cannot print isolated StructCtor"),
+ }
+ }
+}
+
+fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String {
+ let id_str = format!(" (id={})", id);
+ let id_str = if include_id { &id_str[..] } else { "" };
+
+ match map.find(id) {
+ Some(NodeItem(item)) => {
+ let path_str = map.path_to_str_with_ident(id, item.ident);
+ let item_str = match item.node {
+ ItemExternCrate(..) => "extern crate",
+ ItemUse(..) => "use",
+ ItemStatic(..) => "static",
+ ItemConst(..) => "const",
+ ItemFn(..) => "fn",
+ ItemMod(..) => "mod",
+ ItemForeignMod(..) => "foreign mod",
+ ItemTy(..) => "ty",
+ ItemEnum(..) => "enum",
+ ItemStruct(..) => "struct",
+ ItemTrait(..) => "trait",
+ ItemImpl(..) => "impl",
+ ItemDefaultImpl(..) => "default impl",
+ ItemMac(..) => "macro"
+ };
+ format!("{} {}{}", item_str, path_str, id_str)
+ }
+ Some(NodeForeignItem(item)) => {
+ let path_str = map.path_to_str_with_ident(id, item.ident);
+ format!("foreign item {}{}", path_str, id_str)
+ }
+ Some(NodeImplItem(ii)) => {
+ match ii.node {
+ ConstImplItem(..) => {
+ format!("assoc const {} in {}{}",
+ token::get_ident(ii.ident),
+ map.path_to_string(id),
+ id_str)
+ }
+ MethodImplItem(..) => {
+ format!("method {} in {}{}",
+ token::get_ident(ii.ident),
+ map.path_to_string(id), id_str)
+ }
+ TypeImplItem(_) => {
+ format!("assoc type {} in {}{}",
+ token::get_ident(ii.ident),
+ map.path_to_string(id),
+ id_str)
+ }
+ MacImplItem(ref mac) => {
+ format!("method macro {}{}",
+ pprust::mac_to_string(mac), id_str)
+ }
+ }
+ }
+ Some(NodeTraitItem(ti)) => {
+ let kind = match ti.node {
+ ConstTraitItem(..) => "assoc constant",
+ MethodTraitItem(..) => "trait method",
+ TypeTraitItem(..) => "assoc type",
+ };
+
+ format!("{} {} in {}{}",
+ kind,
+ token::get_ident(ti.ident),
+ map.path_to_string(id),
+ id_str)
+ }
+ Some(NodeVariant(ref variant)) => {
+ format!("variant {} in {}{}",
+ token::get_ident(variant.node.name),
+ map.path_to_string(id), id_str)
+ }
+ Some(NodeExpr(ref expr)) => {
+ format!("expr {}{}", pprust::expr_to_string(&**expr), id_str)
+ }
+ Some(NodeStmt(ref stmt)) => {
+ format!("stmt {}{}", pprust::stmt_to_string(&**stmt), id_str)
+ }
+ Some(NodeArg(ref pat)) => {
+ format!("arg {}{}", pprust::pat_to_string(&**pat), id_str)
+ }
+ Some(NodeLocal(ref pat)) => {
+ format!("local {}{}", pprust::pat_to_string(&**pat), id_str)
+ }
+ Some(NodePat(ref pat)) => {
+ format!("pat {}{}", pprust::pat_to_string(&**pat), id_str)
+ }
+ Some(NodeBlock(ref block)) => {
+ format!("block {}{}", pprust::block_to_string(&**block), id_str)
+ }
+ Some(NodeStructCtor(_)) => {
+ format!("struct_ctor {}{}", map.path_to_string(id), id_str)
+ }
+ Some(NodeLifetime(ref l)) => {
+ format!("lifetime {}{}",
+ pprust::lifetime_to_string(&**l), id_str)
+ }
+ None => {
+ format!("unknown node{}", id_str)
+ }
+ }
+}
the heap at runtime, and therefore cannot be done at compile time.
"##,
+E0011: r##"
+Initializers for constants and statics are evaluated at compile time.
+User-defined operators rely on user-defined functions, which cannot be evaluated
+at compile time.
+
+Bad example:
+
+```
+use std::ops::Index;
+
+struct Foo { a: u8 }
+
+impl Index<u8> for Foo {
+ type Output = u8;
+
+ fn index<'a>(&'a self, idx: u8) -> &'a u8 { &self.a }
+}
+
+const a: Foo = Foo { a: 0u8 };
+const b: u8 = a[0]; // Index trait is defined by the user, bad!
+```
+
+Only operators on builtin types are allowed.
+
+Example:
+
+```
+const a: &'static [i32] = &[1, 2, 3];
+const b: i32 = a[0]; // Good!
+```
+"##,
+
E0013: r##"
Static and const variables can refer to other const variables. But a const
variable cannot refer to a static variable. For example, `Y` cannot refer to `X`
```
"##,
+E0014: r##"
+Constants can only be initialized by a constant value or, in a future
+version of Rust, a call to a const function. This error indicates the use
+of a path (like a::b, or x) denoting something other than one of these
+allowed items. Example:
+
+```
+const FOO: i32 = { let x = 0; x }; // 'x' isn't a constant nor a function!
+```
+
+To avoid it, you have to replace the non-constant value:
+
+```
+const FOO: i32 = { const X : i32 = 0; X };
+// or even:
+const FOO: i32 = { 0 }; // but brackets are useless here
+```
+"##,
+
E0015: r##"
-The only function calls allowed in static or constant expressions are enum
-variant constructors or struct constructors (for unit or tuple structs). This
-is because Rust currently does not support compile-time function execution.
+The only functions that can be called in static or constant expressions are
+`const` functions. Rust currently does not support more general compile-time
+function execution.
+
+See [RFC 911] for more details on the design of `const fn`s.
+
+[RFC 911]: https://github.com/rust-lang/rfcs/blob/master/text/0911-const-fn.md
+"##,
+
+E0016: r##"
+Blocks in constants may only contain items (such as constant, function
+definition, etc...) and a tail expression. Example:
+
+```
+const FOO: i32 = { let x = 0; x }; // 'x' isn't an item!
+```
+
+To avoid it, you have to replace the non-item object:
+
+```
+const FOO: i32 = { const X : i32 = 0; X };
+```
"##,
E0018: r##"
in a non-constant integer which lead to this error. Example:
```
-const X: u32 = 50;
-const Y: *const u32 = &X;
-println!("{:?}", Y);
+const X: u32 = 1;
+const Y: usize = &X as *const u32 as usize;
+println!("{}", Y);
+```
+"##,
+
+E0019: r##"
+A function call isn't allowed in the const's initialization expression
+because the expression's value must be known at compile-time. Example of
+erroneous code:
+
+```
+enum Test {
+ V1
+}
+
+impl Test {
+ fn test(&self) -> i32 {
+ 12
+ }
+}
+
+fn main() {
+ const FOO: Test = Test::V1;
+
+ const A: i32 = FOO.test(); // You can't call Test::func() here !
+}
+```
+
+Remember: you can't use a function call inside a const's initialization
+expression! However, you can totally use it elsewhere you want:
+
+```
+fn main() {
+ const FOO: Test = Test::V1;
+
+ FOO.func(); // here is good
+ let x = FOO.func(); // or even here!
+}
```
"##,
E0133: r##"
Using unsafe functionality, such as dereferencing raw pointers and calling
functions via FFI or marked as unsafe, is potentially dangerous and disallowed
-by safety checks. As such, those safety checks can be temporarily relaxed by
-wrapping the unsafe instructions inside an `unsafe` block. For instance:
+by safety checks. These safety checks can be relaxed for a section of the code
+by wrapping the unsafe instructions with an `unsafe` block. For instance:
```
unsafe fn f() { return; }
```
"##,
+E0261: r##"
+When using a lifetime like `'a` in a type, it must be declared before being
+used.
+
+These two examples illustrate the problem:
+
+```
+// error, use of undeclared lifetime name `'a`
+fn foo(x: &'a str) { }
+
+struct Foo {
+ // error, use of undeclared lifetime name `'a`
+ x: &'a str,
+}
+```
+
+These can be fixed by declaring lifetime parameters:
+
+```
+fn foo<'a>(x: &'a str) { }
+
+struct Foo<'a> {
+ x: &'a str,
+}
+```
+"##,
+
+E0262: r##"
+Declaring certain lifetime names in parameters is disallowed. For example,
+because the `'static` lifetime is a special built-in lifetime name denoting
+the lifetime of the entire program, this is an error:
+
+```
+// error, illegal lifetime parameter name `'static`
+fn foo<'static>(x: &'static str) { }
+```
+"##,
+
+E0263: r##"
+A lifetime name cannot be declared more than once in the same scope. For
+example:
+
+```
+// error, lifetime name `'a` declared twice in the same scope
+fn foo<'a, 'b, 'a>(x: &'a str, y: &'b str) { }
+```
+"##,
+
E0265: r##"
This error indicates that a static or constant references itself.
All statics and constants need to resolve to a value in an acyclic manner.
foo(3_i8);
// Here, we invoke `foo` with an `i8`, which does not satisfy
-// the constraint `<i8 as Trait>::AssociatedType=32`, and
+// the constraint `<i8 as Trait>::AssociatedType=u32`, and
// therefore the type-checker complains with this error code.
```
foo: &'static T
}
```
+"##,
+
+E0378: r##"
+Method calls that aren't calls to inherent `const` methods are disallowed
+in statics, constants, and constant functions.
+
+For example:
+
+```
+const BAZ: i32 = Foo(25).bar(); // error, `bar` isn't `const`
+
+struct Foo(i32);
+
+impl Foo {
+ const fn foo(&self) -> i32 {
+ self.bar() // error, `bar` isn't `const`
+ }
+
+ fn bar(&self) -> i32 { self.0 }
+}
+```
+
+For more information about `const fn`'s, see [RFC 911].
+
+[RFC 911]: https://github.com/rust-lang/rfcs/blob/master/text/0911-const-fn.md
+"##,
+
+E0394: r##"
+From [RFC 246]:
+
+ > It is illegal for a static to reference another static by value. It is
+ > required that all references be borrowed.
+
+[RFC 246]: https://github.com/rust-lang/rfcs/pull/246
+"##,
+
+E0397: r##"
+It is not allowed for a mutable static to allocate or have destructors. For
+example:
+
+```
+// error: mutable statics are not allowed to have boxes
+static mut FOO: Option<Box<usize>> = None;
+
+// error: mutable statics are not allowed to have destructors
+static mut BAR: Option<Vec<i32>> = None;
+```
+"##,
+
+E0398: r##"
+In Rust 1.3, the default object lifetime bounds are expected to
+change, as described in RFC #1156 [1]. You are getting a warning
+because the compiler thinks it is possible that this change will cause
+a compilation error in your code. It is possible, though unlikely,
+that this is a false alarm.
+
+The heart of the change is that where `&'a Box<SomeTrait>` used to
+default to `&'a Box<SomeTrait+'a>`, it now defaults to `&'a
+Box<SomeTrait+'static>` (here, `SomeTrait` is the name of some trait
+type). Note that the only types which are affected are references to
+boxes, like `&Box<SomeTrait>` or `&[Box<SomeTrait>]`. More common
+types like `&SomeTrait` or `Box<SomeTrait>` are unaffected.
+
+To silence this warning, edit your code to use an explicit bound.
+Most of the time, this means that you will want to change the
+signature of a function that you are calling. For example, if
+the error is reported on a call like `foo(x)`, and `foo` is
+defined as follows:
+
+```
+fn foo(arg: &Box<SomeTrait>) { ... }
+```
+
+you might change it to:
+
+```
+fn foo<'a>(arg: &Box<SomeTrait+'a>) { ... }
+```
+
+This explicitly states that you expect the trait object `SomeTrait` to
+contain references (with a maximum lifetime of `'a`).
+
+[1]: https://github.com/rust-lang/rfcs/pull/1156
"##
}
register_diagnostics! {
- E0011,
- E0012,
- E0014,
- E0016,
E0017,
- E0019,
E0022,
E0038,
E0109,
E0136,
E0138,
E0139,
- E0261, // use of undeclared lifetime name
- E0262, // illegal lifetime parameter name
- E0263, // lifetime name declared twice in same scope
E0264, // unknown external lang item
E0266, // expected item
E0269, // not all control paths return a value
E0314, // closure outlives stack frame
E0315, // cannot invoke closure outside of its lifetime
E0316, // nested quantification of lifetimes
- E0370 // discriminant overflow
+ E0370, // discriminant overflow
+ E0395, // pointer comparison in const-expr
+ E0396 // pointer dereference in const-expr
}
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
- html_favicon_url = "http://www.rust-lang.org/favicon.ico",
+ html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/")]
+#![feature(append)]
#![feature(associated_consts)]
#![feature(box_patterns)]
#![feature(box_syntax)]
+#![feature(clone_from_slice)]
#![feature(collections)]
-#![feature(core)]
+#![feature(const_fn)]
#![feature(duration)]
#![feature(duration_span)]
+#![feature(dynamic_lib)]
+#![feature(enumset)]
#![feature(fs_canonicalize)]
-#![feature(hash)]
+#![feature(hash_default)]
+#![feature(hashmap_hasher)]
#![feature(into_cow)]
+#![feature(iter_cmp)]
+#![feature(iter_arith)]
#![feature(libc)]
+#![feature(map_in_place)]
+#![feature(num_bits_bytes)]
#![feature(path_ext)]
#![feature(quote)]
+#![feature(range_inclusive)]
+#![feature(ref_slice)]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
+#![feature(scoped_tls)]
+#![feature(slice_bytes)]
+#![feature(slice_extras)]
#![feature(slice_patterns)]
+#![feature(slice_position_elem)]
#![feature(staged_api)]
-#![feature(std_misc)]
#![feature(str_char)]
+#![feature(str_match_indices)]
+#![feature(vec_push_all)]
+#![feature(wrapping)]
#![cfg_attr(test, feature(test))]
#![allow(trivial_casts)]
pub use rustc_back::x86_64;
}
+pub mod ast_map;
+
pub mod middle {
pub mod astconv_util;
pub mod astencode;
+ pub mod cast;
pub mod cfg;
pub mod check_const;
pub mod check_static_recursion;
}
// Build the diagnostics array at the end so that the metadata includes error use sites.
-#[cfg(stage0)]
-__build_diagnostic_array! { DIAGNOSTICS }
-#[cfg(not(stage0))]
__build_diagnostic_array! { librustc, DIAGNOSTICS }
use middle::privacy::ExportedItems;
use middle::ty::{self, Ty};
use session::{early_error, Session};
-use session::config::UnstableFeatures;
use lint::{Level, LevelSource, Lint, LintId, LintArray, LintPass, LintPassObject};
-use lint::{Default, CommandLine, Node, Allow, Warn, Deny, Forbid, ReleaseChannel};
+use lint::{Default, CommandLine, Node, Allow, Warn, Deny, Forbid};
use lint::builtin;
use util::nodemap::FnvHashMap;
}
}
}
-
- fn maybe_stage_features(&mut self, sess: &Session) {
- let lvl = match sess.opts.unstable_features {
- UnstableFeatures::Default => return,
- UnstableFeatures::Disallow => Forbid,
- UnstableFeatures::Cheat => Allow
- };
- match self.by_name.get("unstable_features") {
- Some(&Id(lint_id)) => if self.get_level_source(lint_id).0 != Forbid {
- self.set_level(lint_id, (lvl, ReleaseChannel))
- },
- Some(&Renamed(_, lint_id)) => if self.get_level_source(lint_id).0 != Forbid {
- self.set_level(lint_id, (lvl, ReleaseChannel))
- },
- None => unreachable!()
- }
- }
}
/// Context for lint checking.
let name = lint.name_lower();
let mut def = None;
- let mut note = None;
let msg = match source {
Default => {
format!("{}, #[{}({})] on by default", msg,
def = Some(src);
msg.to_string()
}
- ReleaseChannel => {
- let release_channel = option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)");
- note = Some(format!("this feature may not be used in the {} release channel",
- release_channel));
- msg.to_string()
- }
};
// For purposes of printing, we can treat forbid as deny.
_ => sess.bug("impossible level in raw_emit_lint"),
}
- if let Some(note) = note {
- sess.note(¬e[..]);
- }
-
if let Some(span) = def {
sess.span_note(span, "lint level defined here");
}
pub fn check_crate(tcx: &ty::ctxt,
exported_items: &ExportedItems) {
- // If this is a feature-staged build of rustc then flip several lints to 'forbid'
- tcx.sess.lint_store.borrow_mut().maybe_stage_features(&tcx.sess);
-
let krate = tcx.map.krate();
let mut cx = Context::new(tcx, krate, exported_items);
// If we missed any lints added to the session, then there's a bug somewhere
// in the iteration code.
- for (id, v) in &*tcx.sess.lints.borrow() {
+ for (id, v) in tcx.sess.lints.borrow().iter() {
for &(lint, span, ref msg) in v {
tcx.sess.span_bug(span,
&format!("unprocessed lint {} at {}: {}",
#[macro_export]
macro_rules! lint_array { ($( $lint:expr ),*) => (
{
- #[allow(non_upper_case_globals)]
- static array: LintArray = &[ $( &$lint ),* ];
- array
+ static ARRAY: LintArray = &[ $( &$lint ),* ];
+ ARRAY
}
) }
/// Lint level was set by a command-line flag.
CommandLine,
-
- /// Lint level was set by the release channel.
- ReleaseChannel
}
pub type LevelSource = (Level, LintSource);
tag_table_closure_kinds = 0x65,
tag_table_upvar_capture_map = 0x66,
tag_table_capture_modes = 0x67,
- tag_table_object_cast_map = 0x68,
+ // GAP 0x68
tag_table_const_qualif = 0x69,
+ tag_table_cast_kinds = 0x6a,
}
}
pub const tag_defaulted_trait: usize = 0xa4;
pub const tag_impl_coerce_unsized_kind: usize = 0xa5;
+
+pub const tag_items_data_item_constness: usize = 0xa6;
use metadata::loader;
use metadata::loader::CratePaths;
+use std::cell::RefCell;
use std::path::PathBuf;
use std::rc::Rc;
use std::fs;
let loader::Library { dylib, rlib, metadata } = lib;
let cnum_map = self.resolve_crate_deps(root, metadata.as_slice(), span);
- let codemap_import_info = import_codemap(self.sess.codemap(), &metadata);
let cmeta = Rc::new( cstore::crate_metadata {
name: name.to_string(),
data: metadata,
cnum_map: cnum_map,
cnum: cnum,
- codemap_import_info: codemap_import_info,
+ codemap_import_info: RefCell::new(vec![]),
span: span,
});
/// file they represent, just information about length, line breaks, and
/// multibyte characters. This information is enough to generate valid debuginfo
/// for items inlined from other crates.
-fn import_codemap(local_codemap: &codemap::CodeMap,
- metadata: &MetadataBlob)
- -> Vec<cstore::ImportedFileMap> {
+pub fn import_codemap(local_codemap: &codemap::CodeMap,
+ metadata: &MetadataBlob)
+ -> Vec<cstore::ImportedFileMap> {
let external_codemap = decoder::get_imported_filemaps(metadata.as_slice());
let imported_filemaps = external_codemap.into_iter().map(|filemap_to_import| {
// Searching for information from the cstore
+use ast_map;
use metadata::common::*;
use metadata::cstore;
use metadata::decoder;
-use middle::def;
use middle::lang_items;
use middle::ty;
use rbml::reader;
use std::rc::Rc;
use syntax::ast;
-use syntax::ast_map;
use syntax::attr;
use syntax::attr::AttrMetaMethods;
use syntax::diagnostic::expect;
decoder::maybe_get_item_ast(&*cdata, tcx, def.node, decode_inlined_item)
}
-pub fn get_enum_variant_defs(cstore: &cstore::CStore, enum_id: ast::DefId)
- -> Vec<(def::Def, ast::Name, ast::Visibility)> {
- let cdata = cstore.get_crate_data(enum_id.krate);
- decoder::get_enum_variant_defs(&*cstore.intr, &*cdata, enum_id.node)
-}
-
pub fn get_enum_variants<'tcx>(tcx: &ty::ctxt<'tcx>, def: ast::DefId)
-> Vec<Rc<ty::VariantInfo<'tcx>>> {
let cstore = &tcx.sess.cstore;
decoder::get_impl_trait(&*cdata, def.node, tcx)
}
-// Given a def_id for an impl, return information about its vtables
-pub fn get_impl_vtables<'tcx>(tcx: &ty::ctxt<'tcx>,
- def: ast::DefId)
- -> ty::vtable_res<'tcx> {
- let cstore = &tcx.sess.cstore;
- let cdata = cstore.get_crate_data(def.krate);
- decoder::get_impl_vtables(&*cdata, def.node, tcx)
-}
-
pub fn get_native_libraries(cstore: &cstore::CStore, crate_num: ast::CrateNum)
-> Vec<(cstore::NativeLibraryKind, String)> {
let cdata = cstore.get_crate_data(crate_num);
decoder::is_typedef(&*cdata, did.node)
}
+pub fn is_const_fn(cstore: &cstore::CStore, did: ast::DefId) -> bool {
+ let cdata = cstore.get_crate_data(did.krate);
+ decoder::is_const_fn(&*cdata, did.node)
+}
+
+pub fn is_impl(cstore: &cstore::CStore, did: ast::DefId) -> bool {
+ let cdata = cstore.get_crate_data(did.krate);
+ decoder::is_impl(&*cdata, did.node)
+}
+
pub fn get_stability(cstore: &cstore::CStore,
def: ast::DefId)
-> Option<attr::Stability> {
decoder::get_stability(&*cdata, def.node)
}
-pub fn is_staged_api(cstore: &cstore::CStore, def: ast::DefId) -> bool {
- let cdata = cstore.get_crate_data(def.krate);
+pub fn is_staged_api(cstore: &cstore::CStore, krate: ast::CrateNum) -> bool {
+ let cdata = cstore.get_crate_data(krate);
let attrs = decoder::get_crate_attributes(cdata.data());
for attr in &attrs {
if &attr.name()[..] == "staged_api" {
decoder::get_repr_attrs(&*cdata, def.node)
}
-pub fn is_associated_type(cstore: &cstore::CStore, def: ast::DefId) -> bool {
- let cdata = cstore.get_crate_data(def.krate);
- decoder::is_associated_type(&*cdata, def.node)
-}
-
pub fn is_defaulted_trait(cstore: &cstore::CStore, trait_def_id: ast::DefId) -> bool {
let cdata = cstore.get_crate_data(trait_def_id.krate);
decoder::is_defaulted_trait(&*cdata, trait_def_id.node)
pub use self::NativeLibraryKind::*;
use back::svh::Svh;
-use metadata::decoder;
-use metadata::loader;
+use metadata::{creader, decoder, loader};
use session::search_paths::PathKind;
use util::nodemap::{FnvHashMap, NodeMap};
-use std::cell::RefCell;
+use std::cell::{RefCell, Ref};
use std::rc::Rc;
use std::path::PathBuf;
use flate::Bytes;
pub data: MetadataBlob,
pub cnum_map: cnum_map,
pub cnum: ast::CrateNum,
- pub codemap_import_info: Vec<ImportedFileMap>,
+ pub codemap_import_info: RefCell<Vec<ImportedFileMap>>,
pub span: codemap::Span,
}
pub fn iter_crate_data<I>(&self, mut i: I) where
I: FnMut(ast::CrateNum, &crate_metadata),
{
- for (&k, v) in &*self.metas.borrow() {
+ for (&k, v) in self.metas.borrow().iter() {
i(k, &**v);
}
}
pub fn iter_crate_data_origins<I>(&self, mut i: I) where
I: FnMut(ast::CrateNum, &crate_metadata, Option<CrateSource>),
{
- for (&k, v) in &*self.metas.borrow() {
+ for (&k, v) in self.metas.borrow().iter() {
let origin = self.get_used_crate_source(k);
origin.as_ref().map(|cs| { assert!(k == cs.cnum); });
i(k, &**v, origin);
}
ordering.push(cnum);
};
- for (&num, _) in &*self.metas.borrow() {
+ for (&num, _) in self.metas.borrow().iter() {
visit(self, num, &mut ordering);
}
ordering.reverse();
pub fn data<'a>(&'a self) -> &'a [u8] { self.data.as_slice() }
pub fn name(&self) -> String { decoder::get_crate_name(self.data()) }
pub fn hash(&self) -> Svh { decoder::get_crate_hash(self.data()) }
+ pub fn imported_filemaps<'a>(&'a self, codemap: &codemap::CodeMap)
+ -> Ref<'a, Vec<ImportedFileMap>> {
+ let filemaps = self.codemap_import_info.borrow();
+ if filemaps.is_empty() {
+ drop(filemaps);
+ let filemaps = creader::import_codemap(codemap, &self.data);
+
+ // This shouldn't borrow twice, but there is no way to downgrade RefMut to Ref.
+ *self.codemap_import_info.borrow_mut() = filemaps;
+ self.codemap_import_info.borrow()
+ } else {
+ filemaps
+ }
+ }
}
impl MetadataBlob {
pub use self::DefLike::*;
use self::Family::*;
+use ast_map;
use back::svh::Svh;
use metadata::cstore::crate_metadata;
use metadata::common::*;
use middle::subst;
use middle::ty::{ImplContainer, TraitContainer};
use middle::ty::{self, Ty};
-use middle::astencode::vtable_decoder_helpers;
use util::nodemap::FnvHashMap;
use std::cell::{Cell, RefCell};
use rbml::reader;
use rbml;
use serialize::Decodable;
-use syntax::ast_map;
use syntax::attr;
use syntax::parse::token::{IdentInterner, special_idents};
use syntax::parse::token;
let pos = u32_from_be_bytes(&d.data[hash_pos..]) as usize;
let tagged_doc = reader::doc_at(d.data, pos).unwrap();
- let belt = tag_index_buckets_bucket_elt;
-
- let mut ret = None;
- reader::tagged_docs(tagged_doc.doc, belt, |elt| {
+ reader::tagged_docs(tagged_doc.doc, tag_index_buckets_bucket_elt).find(|elt| {
+ eq_fn(&elt.data[elt.start + 4 .. elt.end])
+ }).map(|elt| {
let pos = u32_from_be_bytes(&elt.data[elt.start..]) as usize;
- if eq_fn(&elt.data[elt.start + 4 .. elt.end]) {
- ret = Some(reader::doc_at(d.data, pos).unwrap().doc);
- false
- } else {
- true
- }
- });
- ret
+ reader::doc_at(d.data, pos).unwrap().doc
+ })
}
pub fn maybe_find_item<'a>(item_id: ast::NodeId,
}
}
+fn fn_constness(item: rbml::Doc) -> ast::Constness {
+ match reader::maybe_get_doc(item, tag_items_data_item_constness) {
+ None => ast::Constness::NotConst,
+ Some(constness_doc) => {
+ match reader::doc_as_u8(constness_doc) as char {
+ 'c' => ast::Constness::Const,
+ 'n' => ast::Constness::NotConst,
+ _ => panic!("unknown constness character")
+ }
+ }
+ }
+}
+
fn item_sort(item: rbml::Doc) -> Option<char> {
- let mut ret = None;
- reader::tagged_docs(item, tag_item_trait_item_sort, |doc| {
- ret = Some(doc.as_str_slice().as_bytes()[0] as char);
- false
- });
- ret
+ reader::tagged_docs(item, tag_item_trait_item_sort).nth(0).map(|doc| {
+ doc.as_str_slice().as_bytes()[0] as char
+ })
}
fn item_symbol(item: rbml::Doc) -> String {
}
fn item_parent_item(cdata: Cmd, d: rbml::Doc) -> Option<ast::DefId> {
- let mut ret = None;
- reader::tagged_docs(d, tag_items_data_parent_item, |did| {
- ret = Some(translated_def_id(cdata, did));
- false
- });
- ret
+ reader::tagged_docs(d, tag_items_data_parent_item).nth(0).map(|did| {
+ translated_def_id(cdata, did)
+ })
}
fn item_require_parent_item(cdata: Cmd, d: rbml::Doc) -> ast::DefId {
})
}
-fn each_reexport<F>(d: rbml::Doc, f: F) -> bool where
- F: FnMut(rbml::Doc) -> bool,
-{
- reader::tagged_docs(d, tag_items_data_item_reexport, f)
+fn reexports<'a>(d: rbml::Doc<'a>) -> reader::TaggedDocsIterator<'a> {
+ reader::tagged_docs(d, tag_items_data_item_reexport)
}
fn variant_disr_val(d: rbml::Doc) -> Option<ty::Disr> {
|_, did| translate_def_id(cdata, did))
}
+fn maybe_doc_type<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd) -> Option<Ty<'tcx>> {
+ reader::maybe_get_doc(doc, tag_items_data_item_type).map(|tp| {
+ parse_ty_data(tp.data, cdata.cnum, tp.start, tcx,
+ |_, did| translate_def_id(cdata, did))
+ })
+}
+
fn doc_method_fty<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>,
cdata: Cmd) -> ty::BareFnTy<'tcx> {
let tp = reader::get_doc(doc, tag_item_method_fty);
doc_trait_ref(tp, tcx, cdata)
}
-fn enum_variant_ids(item: rbml::Doc, cdata: Cmd) -> Vec<ast::DefId> {
- let mut ids = vec![];
- reader::tagged_docs(item, tag_items_data_item_variant, |p| {
- ids.push(translated_def_id(cdata, p));
- true
- });
- ids
-}
-
fn item_path(item_doc: rbml::Doc) -> Vec<ast_map::PathElem> {
let path_doc = reader::get_doc(item_doc, tag_path);
-
- let len_doc = reader::get_doc(path_doc, tag_path_len);
- let len = reader::doc_as_u32(len_doc) as usize;
-
- let mut result = Vec::with_capacity(len);
- reader::docs(path_doc, |tag, elt_doc| {
+ reader::docs(path_doc).filter_map(|(tag, elt_doc)| {
if tag == tag_path_elem_mod {
let s = elt_doc.as_str_slice();
- result.push(ast_map::PathMod(token::intern(s)));
+ Some(ast_map::PathMod(token::intern(s)))
} else if tag == tag_path_elem_name {
let s = elt_doc.as_str_slice();
- result.push(ast_map::PathName(token::intern(s)));
+ Some(ast_map::PathName(token::intern(s)))
} else {
// ignore tag_path_len element
+ None
}
- true
- });
-
- result
+ }).collect()
}
fn item_name(intr: &IdentInterner, item: rbml::Doc) -> ast::Name {
fn parse_associated_type_names(item_doc: rbml::Doc) -> Vec<ast::Name> {
let names_doc = reader::get_doc(item_doc, tag_associated_type_names);
- let mut names = Vec::new();
- reader::tagged_docs(names_doc, tag_associated_type_name, |name_doc| {
- let name = token::intern(name_doc.as_str_slice());
- names.push(name);
- true
- });
- names
+ reader::tagged_docs(names_doc, tag_associated_type_name)
+ .map(|name_doc| token::intern(name_doc.as_str_slice()))
+ .collect()
}
pub fn get_trait_def<'tcx>(cdata: Cmd,
}
}
-pub fn get_impl_vtables<'tcx>(cdata: Cmd,
- id: ast::NodeId,
- tcx: &ty::ctxt<'tcx>)
- -> ty::vtable_res<'tcx>
-{
- let item_doc = lookup_item(id, cdata.data());
- let vtables_doc = reader::get_doc(item_doc, tag_item_impl_vtables);
- let mut decoder = reader::Decoder::new(vtables_doc);
- decoder.read_vtable_res(tcx, cdata)
-}
-
-
pub fn get_symbol(data: &[u8], id: ast::NodeId) -> String {
return item_symbol(lookup_item(id, data));
}
{
let root = rbml::Doc::new(cdata.data());
let lang_items = reader::get_doc(root, tag_lang_items);
- reader::tagged_docs(lang_items, tag_lang_items_item, |item_doc| {
+ reader::tagged_docs(lang_items, tag_lang_items_item).all(|item_doc| {
let id_doc = reader::get_doc(item_doc, tag_lang_items_item_id);
let id = reader::doc_as_u32(id_doc) as usize;
let node_id_doc = reader::get_doc(item_doc,
G: FnMut(ast::CrateNum) -> Rc<crate_metadata>,
{
// Iterate over all children.
- let _ = reader::tagged_docs(item_doc, tag_mod_child, |child_info_doc| {
+ for child_info_doc in reader::tagged_docs(item_doc, tag_mod_child) {
let child_def_id = translated_def_id(cdata, child_info_doc);
// This item may be in yet another crate if it was the child of a
let def_like = item_to_def_like(crate_data, child_item_doc, child_def_id);
let visibility = item_visibility(child_item_doc);
callback(def_like, child_name, visibility);
-
}
}
-
- true
- });
+ }
// As a special case, iterate over all static methods of
// associated implementations too. This is a bit of a botch.
// --pcwalton
- let _ = reader::tagged_docs(item_doc,
- tag_items_data_item_inherent_impl,
- |inherent_impl_def_id_doc| {
- let inherent_impl_def_id = item_def_id(inherent_impl_def_id_doc,
- cdata);
+ for inherent_impl_def_id_doc in reader::tagged_docs(item_doc,
+ tag_items_data_item_inherent_impl) {
+ let inherent_impl_def_id = item_def_id(inherent_impl_def_id_doc, cdata);
let items = reader::get_doc(rbml::Doc::new(cdata.data()), tag_items);
if let Some(inherent_impl_doc) = maybe_find_item(inherent_impl_def_id.node, items) {
- let _ = reader::tagged_docs(inherent_impl_doc,
- tag_item_impl_item,
- |impl_item_def_id_doc| {
+ for impl_item_def_id_doc in reader::tagged_docs(inherent_impl_doc,
+ tag_item_impl_item) {
let impl_item_def_id = item_def_id(impl_item_def_id_doc,
cdata);
if let Some(impl_method_doc) = maybe_find_item(impl_item_def_id.node, items) {
item_visibility(impl_method_doc));
}
}
- true
- });
+ }
}
- true
- });
+ }
- // Iterate over all reexports.
- let _ = each_reexport(item_doc, |reexport_doc| {
+ for reexport_doc in reexports(item_doc) {
let def_id_doc = reader::get_doc(reexport_doc,
tag_items_data_item_reexport_def_id);
let child_def_id = translated_def_id(cdata, def_id_doc);
// a public re-export.
callback(def_like, token::intern(name), ast::Public);
}
-
- true
- });
+ }
}
/// Iterates over each child of the given item.
}
}
-pub fn get_enum_variant_defs(intr: &IdentInterner,
- cdata: Cmd,
- id: ast::NodeId)
- -> Vec<(def::Def, ast::Name, ast::Visibility)> {
- let data = cdata.data();
- let items = reader::get_doc(rbml::Doc::new(data), tag_items);
- let item = find_item(id, items);
- enum_variant_ids(item, cdata).iter().map(|did| {
- let item = find_item(did.node, items);
- let name = item_name(intr, item);
- let visibility = item_visibility(item);
- match item_to_def_like(cdata, item, *did) {
- DlDef(def @ def::DefVariant(..)) => (def, name, visibility),
- _ => unreachable!()
- }
- }).collect()
-}
-
pub fn get_enum_variants<'tcx>(intr: Rc<IdentInterner>, cdata: Cmd, id: ast::NodeId,
tcx: &ty::ctxt<'tcx>) -> Vec<Rc<ty::VariantInfo<'tcx>>> {
let data = cdata.data();
let items = reader::get_doc(rbml::Doc::new(data), tag_items);
let item = find_item(id, items);
let mut disr_val = 0;
- enum_variant_ids(item, cdata).iter().map(|did| {
+ reader::tagged_docs(item, tag_items_data_item_variant).map(|p| {
+ let did = translated_def_id(cdata, p);
let item = find_item(did.node, items);
let ctor_ty = item_type(ast::DefId { krate: cdata.cnum, node: id},
item, tcx, cdata);
let name = item_name(&*intr, item);
let (ctor_ty, arg_tys, arg_names) = match ctor_ty.sty {
- ty::ty_bare_fn(_, ref f) =>
+ ty::TyBareFn(_, ref f) =>
(Some(ctor_ty), f.sig.0.inputs.clone(), None),
_ => { // Nullary or struct enum variant.
let mut arg_names = Vec::new();
name: name,
// I'm not even sure if we encode visibility
// for variants -- TEST -- tjc
- id: *did,
+ id: did,
disr_val: old_disr_val,
vis: ast::Inherited
})
/// Returns the def IDs of all the items in the given implementation.
pub fn get_impl_items(cdata: Cmd, impl_id: ast::NodeId)
-> Vec<ty::ImplOrTraitItemId> {
- let mut impl_items = Vec::new();
- reader::tagged_docs(lookup_item(impl_id, cdata.data()),
- tag_item_impl_item, |doc| {
+ reader::tagged_docs(lookup_item(impl_id, cdata.data()), tag_item_impl_item).map(|doc| {
let def_id = item_def_id(doc, cdata);
match item_sort(doc) {
- Some('C') => impl_items.push(ty::ConstTraitItemId(def_id)),
- Some('r') | Some('p') => {
- impl_items.push(ty::MethodTraitItemId(def_id))
- }
- Some('t') => impl_items.push(ty::TypeTraitItemId(def_id)),
+ Some('C') => ty::ConstTraitItemId(def_id),
+ Some('r') | Some('p') => ty::MethodTraitItemId(def_id),
+ Some('t') => ty::TypeTraitItemId(def_id),
_ => panic!("unknown impl item sort"),
}
- true
- });
-
- impl_items
+ }).collect()
}
pub fn get_trait_name(intr: Rc<IdentInterner>,
id: ast::NodeId,
tcx: &ty::ctxt<'tcx>)
-> ty::ImplOrTraitItem<'tcx> {
- let method_doc = lookup_item(id, cdata.data());
+ let item_doc = lookup_item(id, cdata.data());
- let def_id = item_def_id(method_doc, cdata);
+ let def_id = item_def_id(item_doc, cdata);
- let container_id = item_require_parent_item(cdata, method_doc);
+ let container_id = item_require_parent_item(cdata, item_doc);
let container_doc = lookup_item(container_id.node, cdata.data());
let container = match item_family(container_doc) {
Trait => TraitContainer(container_id),
_ => ImplContainer(container_id),
};
- let name = item_name(&*intr, method_doc);
- let vis = item_visibility(method_doc);
+ let name = item_name(&*intr, item_doc);
+ let vis = item_visibility(item_doc);
- match item_sort(method_doc) {
+ match item_sort(item_doc) {
Some('C') => {
- let ty = doc_type(method_doc, tcx, cdata);
- let default = get_provided_source(method_doc, cdata);
+ let ty = doc_type(item_doc, tcx, cdata);
+ let default = get_provided_source(item_doc, cdata);
ty::ConstTraitItem(Rc::new(ty::AssociatedConst {
name: name,
ty: ty,
}))
}
Some('r') | Some('p') => {
- let generics = doc_generics(method_doc, tcx, cdata, tag_method_ty_generics);
- let predicates = doc_predicates(method_doc, tcx, cdata, tag_method_ty_generics);
- let fty = doc_method_fty(method_doc, tcx, cdata);
- let explicit_self = get_explicit_self(method_doc);
- let provided_source = get_provided_source(method_doc, cdata);
+ let generics = doc_generics(item_doc, tcx, cdata, tag_method_ty_generics);
+ let predicates = doc_predicates(item_doc, tcx, cdata, tag_method_ty_generics);
+ let fty = doc_method_fty(item_doc, tcx, cdata);
+ let explicit_self = get_explicit_self(item_doc);
+ let provided_source = get_provided_source(item_doc, cdata);
ty::MethodTraitItem(Rc::new(ty::Method::new(name,
generics,
provided_source)))
}
Some('t') => {
+ let ty = maybe_doc_type(item_doc, tcx, cdata);
ty::TypeTraitItem(Rc::new(ty::AssociatedType {
name: name,
+ ty: ty,
vis: vis,
def_id: def_id,
container: container,
-> Vec<ty::ImplOrTraitItemId> {
let data = cdata.data();
let item = lookup_item(id, data);
- let mut result = Vec::new();
- reader::tagged_docs(item, tag_item_trait_item, |mth| {
+ reader::tagged_docs(item, tag_item_trait_item).map(|mth| {
let def_id = item_def_id(mth, cdata);
match item_sort(mth) {
- Some('C') => result.push(ty::ConstTraitItemId(def_id)),
- Some('r') | Some('p') => {
- result.push(ty::MethodTraitItemId(def_id));
- }
- Some('t') => result.push(ty::TypeTraitItemId(def_id)),
+ Some('C') => ty::ConstTraitItemId(def_id),
+ Some('r') | Some('p') => ty::MethodTraitItemId(def_id),
+ Some('t') => ty::TypeTraitItemId(def_id),
_ => panic!("unknown trait item sort"),
}
- true
- });
- result
+ }).collect()
}
pub fn get_item_variances(cdata: Cmd, id: ast::NodeId) -> ty::ItemVariances {
-> Vec<Rc<ty::Method<'tcx>>> {
let data = cdata.data();
let item = lookup_item(id, data);
- let mut result = Vec::new();
- reader::tagged_docs(item, tag_item_trait_item, |mth_id| {
+ reader::tagged_docs(item, tag_item_trait_item).filter_map(|mth_id| {
let did = item_def_id(mth_id, cdata);
let mth = lookup_item(did.node, data);
did.node,
tcx);
if let ty::MethodTraitItem(ref method) = trait_item {
- result.push((*method).clone())
+ Some((*method).clone())
+ } else {
+ None
}
+ } else {
+ None
}
- true
- });
-
- return result;
+ }).collect()
}
pub fn get_associated_consts<'tcx>(intr: Rc<IdentInterner>,
-> Vec<Rc<ty::AssociatedConst<'tcx>>> {
let data = cdata.data();
let item = lookup_item(id, data);
- let mut result = Vec::new();
- for &tag in &[tag_item_trait_item, tag_item_impl_item] {
- reader::tagged_docs(item, tag, |ac_id| {
+ [tag_item_trait_item, tag_item_impl_item].iter().flat_map(|&tag| {
+ reader::tagged_docs(item, tag).filter_map(|ac_id| {
let did = item_def_id(ac_id, cdata);
let ac_doc = lookup_item(did.node, data);
did.node,
tcx);
if let ty::ConstTraitItem(ref ac) = trait_item {
- result.push((*ac).clone())
+ Some((*ac).clone())
+ } else {
+ None
}
+ } else {
+ None
}
- true
- });
- }
-
- return result;
+ })
+ }).collect()
}
pub fn get_type_name_if_impl(cdata: Cmd,
return None;
}
- let mut ret = None;
- reader::tagged_docs(item, tag_item_impl_type_basename, |doc| {
- ret = Some(token::intern(doc.as_str_slice()));
- false
- });
-
- ret
+ reader::tagged_docs(item, tag_item_impl_type_basename).nth(0).map(|doc| {
+ token::intern(doc.as_str_slice())
+ })
}
pub fn get_methods_if_impl(intr: Rc<IdentInterner>,
}
// If this impl implements a trait, don't consider it.
- let ret = reader::tagged_docs(item, tag_item_trait_ref, |_doc| {
- false
- });
-
- if !ret { return None }
+ if reader::tagged_docs(item, tag_item_trait_ref).next().is_some() {
+ return None;
+ }
- let mut impl_method_ids = Vec::new();
- reader::tagged_docs(item, tag_item_impl_item, |impl_method_doc| {
- impl_method_ids.push(item_def_id(impl_method_doc, cdata));
- true
- });
+ let impl_method_ids = reader::tagged_docs(item, tag_item_impl_item)
+ .map(|impl_method_doc| item_def_id(impl_method_doc, cdata));
let mut impl_methods = Vec::new();
- for impl_method_id in &impl_method_ids {
+ for impl_method_id in impl_method_ids {
let impl_method_doc = lookup_item(impl_method_id.node, cdata.data());
let family = item_family(impl_method_doc);
match family {
-> Option<ast::DefId>
{
let item = lookup_item(node_id, cdata.data());
- let mut ret = None;
- reader::tagged_docs(item, tag_items_data_item_is_tuple_struct_ctor, |_| {
- ret = Some(item_require_parent_item(cdata, item));
- false
- });
- ret
+ reader::tagged_docs(item, tag_items_data_item_is_tuple_struct_ctor).next().map(|_| {
+ item_require_parent_item(cdata, item)
+ })
}
pub fn get_item_attrs(cdata: Cmd,
pub fn get_struct_field_attrs(cdata: Cmd) -> HashMap<ast::NodeId, Vec<ast::Attribute>> {
let data = rbml::Doc::new(cdata.data());
let fields = reader::get_doc(data, tag_struct_fields);
- let mut map = HashMap::new();
- reader::tagged_docs(fields, tag_struct_field, |field| {
+ reader::tagged_docs(fields, tag_struct_field).map(|field| {
let id = reader::doc_as_u32(reader::get_doc(field, tag_struct_field_id));
let attrs = get_attributes(field);
- map.insert(id, attrs);
- true
- });
- map
+ (id, attrs)
+ }).collect()
}
fn struct_field_family_to_visibility(family: Family) -> ast::Visibility {
-> Vec<ty::field_ty> {
let data = cdata.data();
let item = lookup_item(id, data);
- let mut result = Vec::new();
- reader::tagged_docs(item, tag_item_field, |an_item| {
+ reader::tagged_docs(item, tag_item_field).filter_map(|an_item| {
let f = item_family(an_item);
if f == PublicField || f == InheritedField {
let name = item_name(&*intr, an_item);
let did = item_def_id(an_item, cdata);
let tagdoc = reader::get_doc(an_item, tag_item_field_origin);
let origin_id = translated_def_id(cdata, tagdoc);
- result.push(ty::field_ty {
+ Some(ty::field_ty {
name: name,
id: did,
vis: struct_field_family_to_visibility(f),
origin: origin_id,
- });
+ })
+ } else {
+ None
}
- true
- });
- reader::tagged_docs(item, tag_item_unnamed_field, |an_item| {
+ }).chain(reader::tagged_docs(item, tag_item_unnamed_field).map(|an_item| {
let did = item_def_id(an_item, cdata);
let tagdoc = reader::get_doc(an_item, tag_item_field_origin);
let f = item_family(an_item);
let origin_id = translated_def_id(cdata, tagdoc);
- result.push(ty::field_ty {
+ ty::field_ty {
name: special_idents::unnamed_field.name,
id: did,
vis: struct_field_family_to_visibility(f),
origin: origin_id,
- });
- true
- });
- result
+ }
+ })).collect()
}
fn get_meta_items(md: rbml::Doc) -> Vec<P<ast::MetaItem>> {
- let mut items: Vec<P<ast::MetaItem>> = Vec::new();
- reader::tagged_docs(md, tag_meta_item_word, |meta_item_doc| {
+ reader::tagged_docs(md, tag_meta_item_word).map(|meta_item_doc| {
let nd = reader::get_doc(meta_item_doc, tag_meta_item_name);
let n = token::intern_and_get_ident(nd.as_str_slice());
- items.push(attr::mk_word_item(n));
- true
- });
- reader::tagged_docs(md, tag_meta_item_name_value, |meta_item_doc| {
+ attr::mk_word_item(n)
+ }).chain(reader::tagged_docs(md, tag_meta_item_name_value).map(|meta_item_doc| {
let nd = reader::get_doc(meta_item_doc, tag_meta_item_name);
let vd = reader::get_doc(meta_item_doc, tag_meta_item_value);
let n = token::intern_and_get_ident(nd.as_str_slice());
let v = token::intern_and_get_ident(vd.as_str_slice());
// FIXME (#623): Should be able to decode MetaNameValue variants,
// but currently the encoder just drops them
- items.push(attr::mk_name_value_item_str(n, v));
- true
- });
- reader::tagged_docs(md, tag_meta_item_list, |meta_item_doc| {
+ attr::mk_name_value_item_str(n, v)
+ })).chain(reader::tagged_docs(md, tag_meta_item_list).map(|meta_item_doc| {
let nd = reader::get_doc(meta_item_doc, tag_meta_item_name);
let n = token::intern_and_get_ident(nd.as_str_slice());
let subitems = get_meta_items(meta_item_doc);
- items.push(attr::mk_list_item(n, subitems.into_iter().collect()));
- true
- });
- return items;
+ attr::mk_list_item(n, subitems)
+ })).collect()
}
fn get_attributes(md: rbml::Doc) -> Vec<ast::Attribute> {
- let mut attrs: Vec<ast::Attribute> = Vec::new();
match reader::maybe_get_doc(md, tag_attributes) {
- Some(attrs_d) => {
- reader::tagged_docs(attrs_d, tag_attribute, |attr_doc| {
- let is_sugared_doc = reader::doc_as_u8(
- reader::get_doc(attr_doc, tag_attribute_is_sugared_doc)
- ) == 1;
- let meta_items = get_meta_items(attr_doc);
- // Currently it's only possible to have a single meta item on
- // an attribute
- assert_eq!(meta_items.len(), 1);
- let meta_item = meta_items.into_iter().nth(0).unwrap();
- attrs.push(
+ Some(attrs_d) => {
+ reader::tagged_docs(attrs_d, tag_attribute).map(|attr_doc| {
+ let is_sugared_doc = reader::doc_as_u8(
+ reader::get_doc(attr_doc, tag_attribute_is_sugared_doc)
+ ) == 1;
+ let meta_items = get_meta_items(attr_doc);
+ // Currently it's only possible to have a single meta item on
+ // an attribute
+ assert_eq!(meta_items.len(), 1);
+ let meta_item = meta_items.into_iter().nth(0).unwrap();
codemap::Spanned {
node: ast::Attribute_ {
id: attr::mk_attr_id(),
is_sugared_doc: is_sugared_doc,
},
span: codemap::DUMMY_SP
- });
- true
- });
- }
- None => ()
+ }
+ }).collect()
+ },
+ None => vec![],
}
- return attrs;
}
fn list_crate_attributes(md: rbml::Doc, hash: &Svh,
}
pub fn get_crate_deps(data: &[u8]) -> Vec<CrateDep> {
- let mut deps: Vec<CrateDep> = Vec::new();
let cratedoc = rbml::Doc::new(data);
let depsdoc = reader::get_doc(cratedoc, tag_crate_deps);
- let mut crate_num = 1;
+
fn docstr(doc: rbml::Doc, tag_: usize) -> String {
let d = reader::get_doc(doc, tag_);
d.as_str_slice().to_string()
}
- reader::tagged_docs(depsdoc, tag_crate_dep, |depdoc| {
+
+ reader::tagged_docs(depsdoc, tag_crate_dep).enumerate().map(|(crate_num, depdoc)| {
let name = docstr(depdoc, tag_crate_dep_crate_name);
let hash = Svh::new(&docstr(depdoc, tag_crate_dep_hash));
- deps.push(CrateDep {
- cnum: crate_num,
+ CrateDep {
+ cnum: crate_num as u32 + 1,
name: name,
hash: hash,
- });
- crate_num += 1;
- true
- });
- return deps;
+ }
+ }).collect()
}
fn list_crate_deps(data: &[u8], out: &mut io::Write) -> io::Result<()> {
where F: FnMut(ast::DefId),
{
let item_doc = lookup_item(id, cdata.data());
- reader::tagged_docs(item_doc,
- tag_items_data_item_inherent_impl,
- |impl_doc| {
+ for impl_doc in reader::tagged_docs(item_doc, tag_items_data_item_inherent_impl) {
if reader::maybe_get_doc(impl_doc, tag_item_trait_ref).is_none() {
callback(item_def_id(impl_doc, cdata));
}
- true
- });
+ }
}
pub fn each_implementation_for_trait<F>(cdata: Cmd,
{
if cdata.cnum == def_id.krate {
let item_doc = lookup_item(def_id.node, cdata.data());
- let _ = reader::tagged_docs(item_doc,
- tag_items_data_item_extension_impl,
- |impl_doc| {
+ for impl_doc in reader::tagged_docs(item_doc, tag_items_data_item_extension_impl) {
callback(item_def_id(impl_doc, cdata));
- true
- });
+ }
return;
}
let def_id_u64 = def_to_u64(crate_local_did);
let impls_doc = reader::get_doc(rbml::Doc::new(cdata.data()), tag_impls);
- let _ = reader::tagged_docs(impls_doc, tag_impls_impl, |impl_doc| {
+ for impl_doc in reader::tagged_docs(impls_doc, tag_impls_impl) {
let impl_trait = reader::get_doc(impl_doc, tag_impls_impl_trait_def_id);
if reader::doc_as_u64(impl_trait) == def_id_u64 {
callback(item_def_id(impl_doc, cdata));
}
- true
- });
+ }
}
}
-> Vec<(cstore::NativeLibraryKind, String)> {
let libraries = reader::get_doc(rbml::Doc::new(cdata.data()),
tag_native_libraries);
- let mut result = Vec::new();
- reader::tagged_docs(libraries, tag_native_libraries_lib, |lib_doc| {
+ reader::tagged_docs(libraries, tag_native_libraries_lib).map(|lib_doc| {
let kind_doc = reader::get_doc(lib_doc, tag_native_libraries_kind);
let name_doc = reader::get_doc(lib_doc, tag_native_libraries_name);
let kind: cstore::NativeLibraryKind =
cstore::NativeLibraryKind::from_u32(reader::doc_as_u32(kind_doc)).unwrap();
let name = name_doc.as_str().to_string();
- result.push((kind, name));
- true
- });
- return result;
+ (kind, name)
+ }).collect()
}
pub fn get_plugin_registrar_fn(data: &[u8]) -> Option<ast::NodeId> {
F: FnMut(ast::Name, Vec<ast::Attribute>, String) -> bool,
{
let macros = reader::get_doc(rbml::Doc::new(data), tag_macro_defs);
- reader::tagged_docs(macros, tag_macro_def, |macro_doc| {
+ for macro_doc in reader::tagged_docs(macros, tag_macro_def) {
let name = item_name(intr, macro_doc);
let attrs = get_attributes(macro_doc);
let body = reader::get_doc(macro_doc, tag_macro_def_body);
- f(name, attrs, body.as_str().to_string())
- });
+ if !f(name, attrs, body.as_str().to_string()) {
+ break;
+ }
+ }
}
pub fn get_dylib_dependency_formats(cdata: Cmd)
-> Vec<lang_items::LangItem>
{
let items = reader::get_doc(rbml::Doc::new(cdata.data()), tag_lang_items);
- let mut result = Vec::new();
- reader::tagged_docs(items, tag_lang_items_missing, |missing_docs| {
- let item: lang_items::LangItem =
- lang_items::LangItem::from_u32(reader::doc_as_u32(missing_docs)).unwrap();
- result.push(item);
- true
- });
- return result;
+ reader::tagged_docs(items, tag_lang_items_missing).map(|missing_docs| {
+ lang_items::LangItem::from_u32(reader::doc_as_u32(missing_docs)).unwrap()
+ }).collect()
}
pub fn get_method_arg_names(cdata: Cmd, id: ast::NodeId) -> Vec<String> {
- let mut ret = Vec::new();
let method_doc = lookup_item(id, cdata.data());
match reader::maybe_get_doc(method_doc, tag_method_argument_names) {
Some(args_doc) => {
- reader::tagged_docs(args_doc, tag_method_argument_name, |name_doc| {
- ret.push(name_doc.as_str_slice().to_string());
- true
- });
- }
- None => {}
+ reader::tagged_docs(args_doc, tag_method_argument_name).map(|name_doc| {
+ name_doc.as_str_slice().to_string()
+ }).collect()
+ },
+ None => vec![],
}
- return ret;
}
pub fn get_reachable_extern_fns(cdata: Cmd) -> Vec<ast::DefId> {
- let mut ret = Vec::new();
let items = reader::get_doc(rbml::Doc::new(cdata.data()),
tag_reachable_extern_fns);
- reader::tagged_docs(items, tag_reachable_extern_fn_id, |doc| {
- ret.push(ast::DefId {
+ reader::tagged_docs(items, tag_reachable_extern_fn_id).map(|doc| {
+ ast::DefId {
krate: cdata.cnum,
node: reader::doc_as_u32(doc),
- });
- true
- });
- return ret;
+ }
+ }).collect()
}
pub fn is_typedef(cdata: Cmd, id: ast::NodeId) -> bool {
}
}
+pub fn is_const_fn(cdata: Cmd, id: ast::NodeId) -> bool {
+ let item_doc = lookup_item(id, cdata.data());
+ match fn_constness(item_doc) {
+ ast::Constness::Const => true,
+ ast::Constness::NotConst => false,
+ }
+}
+
+pub fn is_impl(cdata: Cmd, id: ast::NodeId) -> bool {
+ let item_doc = lookup_item(id, cdata.data());
+ match item_family(item_doc) {
+ Impl => true,
+ _ => false,
+ }
+}
+
fn doc_generics<'tcx>(base_doc: rbml::Doc,
tcx: &ty::ctxt<'tcx>,
cdata: Cmd,
let doc = reader::get_doc(base_doc, tag);
let mut types = subst::VecPerParamSpace::empty();
- reader::tagged_docs(doc, tag_type_param_def, |p| {
+ for p in reader::tagged_docs(doc, tag_type_param_def) {
let bd = parse_type_param_def_data(
p.data, p.start, cdata.cnum, tcx,
|_, did| translate_def_id(cdata, did));
types.push(bd.space, bd);
- true
- });
+ }
let mut regions = subst::VecPerParamSpace::empty();
- reader::tagged_docs(doc, tag_region_param_def, |rp_doc| {
+ for rp_doc in reader::tagged_docs(doc, tag_region_param_def) {
let ident_str_doc = reader::get_doc(rp_doc,
tag_region_param_def_ident);
let name = item_name(&*token::get_ident_interner(), ident_str_doc);
let doc = reader::get_doc(rp_doc, tag_region_param_def_index);
let index = reader::doc_as_u64(doc) as u32;
- let mut bounds = Vec::new();
- reader::tagged_docs(rp_doc, tag_items_data_region, |p| {
- bounds.push(
- parse_region_data(
- p.data, cdata.cnum, p.start, tcx,
- |_, did| translate_def_id(cdata, did)));
- true
- });
+ let bounds = reader::tagged_docs(rp_doc, tag_items_data_region).map(|p| {
+ parse_region_data(p.data, cdata.cnum, p.start, tcx,
+ |_, did| translate_def_id(cdata, did))
+ }).collect();
regions.push(space, ty::RegionParameterDef { name: name,
def_id: def_id,
space: space,
index: index,
bounds: bounds });
-
- true
- });
+ }
ty::Generics { types: types, regions: regions }
}
let doc = reader::get_doc(base_doc, tag);
let mut predicates = subst::VecPerParamSpace::empty();
- reader::tagged_docs(doc, tag_predicate, |predicate_doc| {
+ for predicate_doc in reader::tagged_docs(doc, tag_predicate) {
let space_doc = reader::get_doc(predicate_doc, tag_predicate_space);
let space = subst::ParamSpace::from_uint(reader::doc_as_u8(space_doc) as usize);
|_, did| translate_def_id(cdata, did));
predicates.push(space, data);
- true
- });
+ }
ty::GenericPredicates { predicates: predicates }
}
-pub fn is_associated_type(cdata: Cmd, id: ast::NodeId) -> bool {
- let items = reader::get_doc(rbml::Doc::new(cdata.data()), tag_items);
- match maybe_find_item(id, items) {
- None => false,
- Some(item) => item_sort(item) == Some('t'),
- }
-}
-
pub fn is_defaulted_trait(cdata: Cmd, trait_id: ast::NodeId) -> bool {
let trait_doc = lookup_item(trait_id, cdata.data());
assert!(item_family(trait_doc) == Family::Trait);
let crate_doc = rbml::Doc::new(metadata);
let cm_doc = reader::get_doc(crate_doc, tag_codemap);
- let mut filemaps = vec![];
-
- reader::tagged_docs(cm_doc, tag_codemap_filemap, |filemap_doc| {
+ reader::tagged_docs(cm_doc, tag_codemap_filemap).map(|filemap_doc| {
let mut decoder = reader::Decoder::new(filemap_doc);
- let filemap: codemap::FileMap = Decodable::decode(&mut decoder).unwrap();
- filemaps.push(filemap);
- true
- });
-
- return filemaps;
+ Decodable::decode(&mut decoder).unwrap()
+ }).collect()
}
pub use self::InlinedItemRef::*;
+use ast_map::{self, LinkedPath, PathElem, PathElems};
use back::svh::Svh;
use session::config;
use metadata::common::*;
use std::io::{Cursor, SeekFrom};
use syntax::abi;
use syntax::ast::{self, DefId, NodeId};
-use syntax::ast_map::{self, LinkedPath, PathElem, PathElems};
use syntax::ast_util::*;
use syntax::ast_util;
use syntax::attr;
let impl_items = ecx.tcx.impl_items.borrow();
match ecx.tcx.inherent_impls.borrow().get(&exp.def_id) {
Some(implementations) => {
- for base_impl_did in &**implementations {
+ for base_impl_did in implementations.iter() {
for &method_did in impl_items.get(base_impl_did).unwrap() {
let impl_item = ty::impl_or_trait_item(
ecx.tcx,
-> bool {
match ecx.tcx.trait_items_cache.borrow().get(&exp.def_id) {
Some(trait_items) => {
- for trait_item in &**trait_items {
+ for trait_item in trait_items.iter() {
if let ty::MethodTraitItem(ref m) = *trait_item {
encode_reexported_static_method(rbml_w,
exp,
rbml_w.wr_tagged_u8(tag_items_data_item_visibility, ch as u8);
}
+fn encode_constness(rbml_w: &mut Encoder, constness: ast::Constness) {
+ rbml_w.start_tag(tag_items_data_item_constness);
+ let ch = match constness {
+ ast::Constness::Const => 'c',
+ ast::Constness::NotConst => 'n',
+ };
+ rbml_w.wr_str(&ch.to_string());
+ rbml_w.end_tag();
+}
+
fn encode_explicit_self(rbml_w: &mut Encoder,
explicit_self: &ty::ExplicitSelfCategory) {
let tag = tag_item_trait_method_explicit_self;
abbrevs: &ecx.type_abbrevs
};
- for param in generics.types.iter() {
+ for param in &generics.types {
rbml_w.start_tag(tag_type_param_def);
tyencode::enc_type_param_def(rbml_w, ty_str_ctxt, param);
rbml_w.end_tag();
}
// Region parameters
- for param in generics.regions.iter() {
+ for param in &generics.regions {
rbml_w.start_tag(tag_region_param_def);
rbml_w.start_tag(tag_region_param_def_ident);
encode_stability(rbml_w, stab);
let elem = ast_map::PathName(associated_const.name);
- encode_path(rbml_w, impl_path.chain(Some(elem).into_iter()));
+ encode_path(rbml_w, impl_path.chain(Some(elem)));
if let Some(ii) = impl_item_opt {
encode_attributes(rbml_w, &ii.attrs);
encode_bounds_and_type_for_item(rbml_w, ecx, m.def_id.local_id());
let elem = ast_map::PathName(m.name);
- encode_path(rbml_w, impl_path.chain(Some(elem).into_iter()));
+ encode_path(rbml_w, impl_path.chain(Some(elem)));
if let Some(impl_item) = impl_item_opt {
if let ast::MethodImplItem(ref sig, _) = impl_item.node {
encode_attributes(rbml_w, &impl_item.attrs);
let scheme = ty::lookup_item_type(ecx.tcx, m.def_id);
let any_types = !scheme.generics.types.is_empty();
- if any_types || is_default_impl || attr::requests_inline(&impl_item.attrs) {
+ let needs_inline = any_types || is_default_impl ||
+ attr::requests_inline(&impl_item.attrs);
+ if needs_inline || sig.constness == ast::Constness::Const {
encode_inlined_item(ecx, rbml_w, IIImplItemRef(local_def(parent_id),
impl_item));
}
+ encode_constness(rbml_w, sig.constness);
if !any_types {
encode_symbol(ecx, rbml_w, m.def_id.node);
}
rbml_w.end_tag();
}
-fn encode_info_for_associated_type(ecx: &EncodeContext,
- rbml_w: &mut Encoder,
- associated_type: &ty::AssociatedType,
- impl_path: PathElems,
- parent_id: NodeId,
- impl_item_opt: Option<&ast::ImplItem>) {
+fn encode_info_for_associated_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
+ rbml_w: &mut Encoder,
+ associated_type: &ty::AssociatedType<'tcx>,
+ impl_path: PathElems,
+ parent_id: NodeId,
+ impl_item_opt: Option<&ast::ImplItem>) {
debug!("encode_info_for_associated_type({:?},{:?})",
associated_type.def_id,
token::get_name(associated_type.name));
encode_parent_item(rbml_w, local_def(parent_id));
encode_item_sort(rbml_w, 't');
- encode_bounds_and_type_for_item(rbml_w, ecx, associated_type.def_id.local_id());
-
let stab = stability::lookup(ecx.tcx, associated_type.def_id);
encode_stability(rbml_w, stab);
let elem = ast_map::PathName(associated_type.name);
- encode_path(rbml_w, impl_path.chain(Some(elem).into_iter()));
+ encode_path(rbml_w, impl_path.chain(Some(elem)));
if let Some(ii) = impl_item_opt {
encode_attributes(rbml_w, &ii.attrs);
- encode_type(ecx, rbml_w, ty::node_id_to_type(ecx.tcx, ii.id));
+ } else {
+ encode_predicates(rbml_w, ecx,
+ &ty::lookup_predicates(ecx.tcx, associated_type.def_id),
+ tag_item_generics);
+ }
+
+ if let Some(ty) = associated_type.ty {
+ encode_type(ecx, rbml_w, ty);
}
rbml_w.end_tag();
let mut repr_attrs = Vec::new();
for attr in attrs {
repr_attrs.extend(attr::find_repr_attrs(ecx.tcx.sess.diagnostic(),
- attr).into_iter());
+ attr));
}
rbml_w.start_tag(tag_items_data_item_repr);
repr_attrs.encode(rbml_w);
match ecx.tcx.inherent_impls.borrow().get(&def_id) {
None => {}
Some(implementations) => {
- for &impl_def_id in &**implementations {
+ for &impl_def_id in implementations.iter() {
rbml_w.start_tag(tag_items_data_item_inherent_impl);
encode_def_id(rbml_w, impl_def_id);
rbml_w.end_tag();
});
}
-fn encode_stability(rbml_w: &mut Encoder, stab_opt: Option<attr::Stability>) {
+fn encode_stability(rbml_w: &mut Encoder, stab_opt: Option<&attr::Stability>) {
stab_opt.map(|stab| {
rbml_w.start_tag(tag_items_data_item_stability);
stab.encode(rbml_w).unwrap();
encode_stability(rbml_w, stab);
rbml_w.end_tag();
}
- ast::ItemFn(ref decl, _, _, ref generics, _) => {
+ ast::ItemFn(ref decl, _, constness, _, ref generics, _) => {
add_to_index(item, rbml_w, index);
rbml_w.start_tag(tag_items_data_item);
encode_def_id(rbml_w, def_id);
encode_name(rbml_w, item.ident.name);
encode_path(rbml_w, path);
encode_attributes(rbml_w, &item.attrs);
- if tps_len > 0 || attr::requests_inline(&item.attrs) {
+ let needs_inline = tps_len > 0 || attr::requests_inline(&item.attrs);
+ if needs_inline || constness == ast::Constness::Const {
encode_inlined_item(ecx, rbml_w, IIItemRef(item));
}
if tps_len == 0 {
encode_symbol(ecx, rbml_w, item.id);
}
+ encode_constness(rbml_w, constness);
encode_visibility(rbml_w, vis);
encode_stability(rbml_w, stab);
encode_method_argument_names(rbml_w, &**decl);
encode_name(rbml_w, item.ident.name);
encode_unsafety(rbml_w, unsafety);
- let trait_ref = ty::impl_id_to_trait_ref(tcx, item.id);
+ let trait_ref = ty::impl_trait_ref(tcx, local_def(item.id)).unwrap();
encode_trait_ref(rbml_w, ecx, trait_ref, tag_item_trait_ref);
rbml_w.end_tag();
}
- ast::ItemImpl(unsafety, polarity, _, ref opt_trait, ref ty, ref ast_items) => {
+ ast::ItemImpl(unsafety, polarity, _, _, ref ty, ref ast_items) => {
// We need to encode information about the default methods we
// have inherited, so we drive this based on the impl structure.
let impl_items = tcx.impl_items.borrow();
}
rbml_w.end_tag();
}
- if opt_trait.is_some() {
- let trait_ref = ty::impl_id_to_trait_ref(tcx, item.id);
+ if let Some(trait_ref) = ty::impl_trait_ref(tcx, local_def(item.id)) {
encode_trait_ref(rbml_w, ecx, trait_ref, tag_item_trait_ref);
}
encode_path(rbml_w, path.clone());
encode_attributes(rbml_w, &item.attrs);
encode_visibility(rbml_w, vis);
encode_stability(rbml_w, stab);
- for &method_def_id in &*ty::trait_item_def_ids(tcx, def_id) {
+ for &method_def_id in ty::trait_item_def_ids(tcx, def_id).iter() {
rbml_w.start_tag(tag_item_trait_item);
match method_def_id {
ty::ConstTraitItemId(const_def_id) => {
let elem = ast_map::PathName(associated_const.name);
encode_path(rbml_w,
- path.clone().chain(Some(elem).into_iter()));
+ path.clone().chain(Some(elem)));
encode_item_sort(rbml_w, 'C');
encode_family(rbml_w, 'C');
let elem = ast_map::PathName(method_ty.name);
encode_path(rbml_w,
- path.clone().chain(Some(elem).into_iter()));
+ path.clone().chain(Some(elem)));
match method_ty.explicit_self {
ty::StaticExplicitSelfCategory => {
let elem = ast_map::PathName(associated_type.name);
encode_path(rbml_w,
- path.clone().chain(Some(elem).into_iter()));
+ path.clone().chain(Some(elem)));
encode_item_sort(rbml_w, 't');
encode_family(rbml_w, 'y');
for id in ecx.reachable {
if let Some(ast_map::NodeItem(i)) = ecx.tcx.map.find(*id) {
- if let ast::ItemFn(_, _, abi, ref generics, _) = i.node {
+ if let ast::ItemFn(_, _, _, abi, ref generics, _) = i.node {
if abi != abi::Rust && !generics.is_type_parameterized() {
rbml_w.wr_tagged_u32(tag_reachable_extern_fn_id, *id);
}
let slot = candidates.entry(hash_str)
.or_insert_with(|| (HashMap::new(), HashMap::new()));
let (ref mut rlibs, ref mut dylibs) = *slot;
- if rlib {
- rlibs.insert(fs::canonicalize(path).unwrap(), kind);
- } else {
- dylibs.insert(fs::canonicalize(path).unwrap(), kind);
- }
-
- FileMatches
+ fs::canonicalize(path).map(|p| {
+ if rlib {
+ rlibs.insert(p, kind);
+ } else {
+ dylibs.insert(p, kind);
+ }
+ FileMatches
+ }).unwrap_or(FileDoesntMatch)
});
- self.rejected_via_kind.extend(staticlibs.into_iter());
+ self.rejected_via_kind.extend(staticlibs);
// We have now collected all known libraries into a set of candidates
// keyed of the filename hash listed. For each filename, we also have a
for (lib, kind) in m {
info!("{} reading metadata from: {}", flavor, lib.display());
- let metadata = match get_metadata_section(self.target.options.is_like_osx,
- &lib) {
+ let metadata = match get_metadata_section(self.target, &lib) {
Ok(blob) => {
if self.crate_matches(blob.as_slice(), &lib) {
blob
}
// Just a small wrapper to time how long reading metadata takes.
-fn get_metadata_section(is_osx: bool, filename: &Path) -> Result<MetadataBlob, String> {
+fn get_metadata_section(target: &Target, filename: &Path)
+ -> Result<MetadataBlob, String> {
let mut ret = None;
let dur = Duration::span(|| {
- ret = Some(get_metadata_section_imp(is_osx, filename));
+ ret = Some(get_metadata_section_imp(target, filename));
});
info!("reading {:?} => {}", filename.file_name().unwrap(), dur);
return ret.unwrap();;
}
-fn get_metadata_section_imp(is_osx: bool, filename: &Path) -> Result<MetadataBlob, String> {
+fn get_metadata_section_imp(target: &Target, filename: &Path)
+ -> Result<MetadataBlob, String> {
if !filename.exists() {
return Err(format!("no such file: '{}'", filename.display()));
}
name_len as usize).to_vec();
let name = String::from_utf8(name).unwrap();
debug!("get_metadata_section: name {}", name);
- if read_meta_section_name(is_osx) == name {
+ if read_meta_section_name(target) == name {
let cbuf = llvm::LLVMGetSectionContents(si.llsi);
let csz = llvm::LLVMGetSectionSize(si.llsi) as usize;
let cvbuf: *const u8 = cbuf as *const u8;
}
}
-pub fn meta_section_name(is_osx: bool) -> &'static str {
- if is_osx {
+pub fn meta_section_name(target: &Target) -> &'static str {
+ if target.options.is_like_osx {
"__DATA,__note.rustc"
+ } else if target.options.is_like_msvc {
+ // When using link.exe it was seen that the section name `.note.rustc`
+ // was getting shortened to `.note.ru`, and according to the PE and COFF
+ // specification:
+ //
+ // > Executable images do not use a string table and do not support
+ // > section names longer than 8 characters
+ //
+ // https://msdn.microsoft.com/en-us/library/windows/hardware/gg463119.aspx
+ //
+ // As a result, we choose a slightly shorter name! As to why
+ // `.note.rustc` works on MinGW, that's another good question...
+ ".rustc"
} else {
".note.rustc"
}
}
-pub fn read_meta_section_name(is_osx: bool) -> &'static str {
- if is_osx {
+pub fn read_meta_section_name(target: &Target) -> &'static str {
+ if target.options.is_like_osx {
"__note.rustc"
+ } else if target.options.is_like_msvc {
+ ".rustc"
} else {
".note.rustc"
}
}
// A diagnostic function for dumping crate metadata to an output stream
-pub fn list_file_metadata(is_osx: bool, path: &Path,
+pub fn list_file_metadata(target: &Target, path: &Path,
out: &mut io::Write) -> io::Result<()> {
- match get_metadata_section(is_osx, path) {
+ match get_metadata_section(target, path) {
Ok(bytes) => decoder::list_crate_metadata(bytes.as_slice(), out),
Err(msg) => {
write!(out, "{}\n", msg)
}
if let Some(sel) = import.as_ref() {
- for (name, span) in sel.iter() {
+ for (name, span) in sel {
if !seen.contains(name) {
self.sess.span_err(*span, "imported macro not found");
}
}
}
- for (name, span) in reexport.iter() {
+ for (name, span) in &reexport {
if !seen.contains(name) {
self.sess.span_err(*span, "reexported macro not found");
}
use syntax::ast;
use syntax::parse::token;
-// Compact string representation for Ty values. API ty_str &
+// Compact string representation for Ty values. API TyStr &
// parse_from_str. Extra parameters are for converting to/from def_ids in the
// data buffer. Whatever format you choose should not contain pipe characters.
// Identifies a type alias (`type X = ...`).
TypeWithId,
- // Identifies a type parameter (`fn foo<X>() { ... }`).
- TypeParameter,
-
// Identifies a region parameter (`fn foo<'X>() { ... }`).
RegionParameter,
tcx: &ty::ctxt<'tcx>, conv: F) -> subst::Substs<'tcx> where
F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
{
- debug!("parse_substs_data {}", data_log_string(data, pos));
+ debug!("parse_substs_data{}", data_log_string(data, pos));
let mut st = parse_state_from_data(data, crate_num, pos, tcx);
parse_substs(&mut st, conv)
}
-pub fn parse_bounds_data<'tcx, F>(data: &[u8], crate_num: ast::CrateNum,
- pos: usize, tcx: &ty::ctxt<'tcx>, conv: F)
- -> ty::ParamBounds<'tcx> where
- F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
-{
- let mut st = parse_state_from_data(data, crate_num, pos, tcx);
- parse_bounds(&mut st, conv)
-}
-
pub fn parse_existential_bounds_data<'tcx, F>(data: &[u8], crate_num: ast::CrateNum,
pos: usize, tcx: &ty::ctxt<'tcx>, conv: F)
-> ty::ExistentialBounds<'tcx> where
len: len };
match tcx.rcache.borrow().get(&key).cloned() {
- Some(tt) => return tt,
+ Some(tt) => {
+ // If there is a closure buried in the type some where, then we
+ // need to re-convert any def ids (see case 'k', below). That means
+ // we can't reuse the cached version.
+ if !ty::type_has_ty_closure(tt) {
+ return tt;
+ }
+ }
None => {}
}
let mut ps = PState {
fn parse_object_lifetime_default<'a,'tcx, F>(st: &mut PState<'a,'tcx>,
conv: &mut F)
- -> Option<ty::ObjectLifetimeDefault>
+ -> ty::ObjectLifetimeDefault
where F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
{
match next(st) {
- 'n' => None,
- 'a' => Some(ty::ObjectLifetimeDefault::Ambiguous),
+ 'a' => ty::ObjectLifetimeDefault::Ambiguous,
+ 'b' => ty::ObjectLifetimeDefault::BaseDefault,
's' => {
let region = parse_region_(st, conv);
- Some(ty::ObjectLifetimeDefault::Specific(region))
+ ty::ObjectLifetimeDefault::Specific(region)
}
_ => panic!("parse_object_lifetime_default: bad input")
}
-> ty::ExistentialBounds<'tcx> where
F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
{
- let ty::ParamBounds { trait_bounds, mut region_bounds, builtin_bounds, projection_bounds } =
- parse_bounds_(st, conv);
- assert_eq!(region_bounds.len(), 1);
- assert_eq!(trait_bounds.len(), 0);
- let region_bound = region_bounds.pop().unwrap();
+ let builtin_bounds = parse_builtin_bounds_(st, conv);
+ let region_bound = parse_region_(st, conv);
+ let mut projection_bounds = Vec::new();
+
+ loop {
+ match next(st) {
+ 'P' => {
+ projection_bounds.push(
+ ty::Binder(parse_projection_predicate_(st, conv)));
+ }
+ '.' => { break; }
+ c => {
+ panic!("parse_bounds: bad bounds ('{}')", c)
+ }
+ }
+ }
+
+ let region_bound_will_change = match next(st) {
+ 'y' => true,
+ 'n' => false,
+ c => panic!("parse_ty: expected y/n not '{}'", c)
+ };
+
return ty::ExistentialBounds { region_bound: region_bound,
builtin_bounds: builtin_bounds,
- projection_bounds: projection_bounds };
+ projection_bounds: projection_bounds,
+ region_bound_will_change: region_bound_will_change };
}
fn parse_builtin_bounds<F>(st: &mut PState, mut _conv: F) -> ty::BuiltinBounds where
fn parse_builtin_bounds_<F>(st: &mut PState, _conv: &mut F) -> ty::BuiltinBounds where
F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
{
- let mut builtin_bounds = ty::empty_builtin_bounds();
+ let mut builtin_bounds = ty::BuiltinBounds::empty();
loop {
match next(st) {
}
}
}
-
-fn parse_bounds<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, mut conv: F)
- -> ty::ParamBounds<'tcx> where
- F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
-{
- parse_bounds_(st, &mut conv)
-}
-
-fn parse_bounds_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F)
- -> ty::ParamBounds<'tcx> where
- F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
-{
- let builtin_bounds = parse_builtin_bounds_(st, conv);
-
- let region_bounds = parse_region_bounds_(st, conv);
-
- let mut param_bounds = ty::ParamBounds {
- region_bounds: region_bounds,
- builtin_bounds: builtin_bounds,
- trait_bounds: Vec::new(),
- projection_bounds: Vec::new(),
- };
-
-
- loop {
- match next(st) {
- 'I' => {
- param_bounds.trait_bounds.push(
- ty::Binder(parse_trait_ref_(st, conv)));
- }
- 'P' => {
- param_bounds.projection_bounds.push(
- ty::Binder(parse_projection_predicate_(st, conv)));
- }
- '.' => {
- return param_bounds;
- }
- c => {
- panic!("parse_bounds: bad bounds ('{}')", c)
- }
- }
- }
-}
-
-fn parse_region_bounds_<'a, 'tcx, F>(st: &mut PState<'a, 'tcx>, conv: &mut F)
- -> Vec<ty::Region> where
- F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
-{
- let mut region_bounds = Vec::new();
- loop {
- match next(st) {
- 'R' => { region_bounds.push(parse_region_(st, conv)); }
- '.' => { return region_bounds; }
- c => { panic!("parse_bounds: bad bounds ('{}')", c); }
- }
- }
-}
pub abbrevs: &'a abbrev_map<'tcx>
}
-// Compact string representation for Ty values. API ty_str & parse_from_str.
+// Compact string representation for Ty values. API TyStr & parse_from_str.
// Extra parameters are for converting to/from def_ids in the string rep.
// Whatever format you choose should not contain pipe characters.
pub struct ty_abbrev {
let pos = w.mark_stable_position();
match t.sty {
- ty::ty_bool => mywrite!(w, "b"),
- ty::ty_char => mywrite!(w, "c"),
- ty::ty_int(t) => {
+ ty::TyBool => mywrite!(w, "b"),
+ ty::TyChar => mywrite!(w, "c"),
+ ty::TyInt(t) => {
match t {
ast::TyIs => mywrite!(w, "is"),
ast::TyI8 => mywrite!(w, "MB"),
ast::TyI64 => mywrite!(w, "MD")
}
}
- ty::ty_uint(t) => {
+ ty::TyUint(t) => {
match t {
ast::TyUs => mywrite!(w, "us"),
ast::TyU8 => mywrite!(w, "Mb"),
ast::TyU64 => mywrite!(w, "Md")
}
}
- ty::ty_float(t) => {
+ ty::TyFloat(t) => {
match t {
ast::TyF32 => mywrite!(w, "Mf"),
ast::TyF64 => mywrite!(w, "MF"),
}
}
- ty::ty_enum(def, substs) => {
+ ty::TyEnum(def, substs) => {
mywrite!(w, "t[{}|", (cx.ds)(def));
enc_substs(w, cx, substs);
mywrite!(w, "]");
}
- ty::ty_trait(box ty::TyTrait { ref principal,
+ ty::TyTrait(box ty::TraitTy { ref principal,
ref bounds }) => {
mywrite!(w, "x[");
enc_trait_ref(w, cx, principal.0);
enc_existential_bounds(w, cx, bounds);
mywrite!(w, "]");
}
- ty::ty_tup(ref ts) => {
+ ty::TyTuple(ref ts) => {
mywrite!(w, "T[");
for t in ts { enc_ty(w, cx, *t); }
mywrite!(w, "]");
}
- ty::ty_uniq(typ) => { mywrite!(w, "~"); enc_ty(w, cx, typ); }
- ty::ty_ptr(mt) => { mywrite!(w, "*"); enc_mt(w, cx, mt); }
- ty::ty_rptr(r, mt) => {
+ ty::TyBox(typ) => { mywrite!(w, "~"); enc_ty(w, cx, typ); }
+ ty::TyRawPtr(mt) => { mywrite!(w, "*"); enc_mt(w, cx, mt); }
+ ty::TyRef(r, mt) => {
mywrite!(w, "&");
enc_region(w, cx, *r);
enc_mt(w, cx, mt);
}
- ty::ty_vec(t, sz) => {
+ ty::TyArray(t, sz) => {
mywrite!(w, "V");
enc_ty(w, cx, t);
- mywrite!(w, "/");
- match sz {
- Some(n) => mywrite!(w, "{}|", n),
- None => mywrite!(w, "|"),
- }
+ mywrite!(w, "/{}|", sz);
}
- ty::ty_str => {
+ ty::TySlice(t) => {
+ mywrite!(w, "V");
+ enc_ty(w, cx, t);
+ mywrite!(w, "/|");
+ }
+ ty::TyStr => {
mywrite!(w, "v");
}
- ty::ty_bare_fn(Some(def_id), f) => {
+ ty::TyBareFn(Some(def_id), f) => {
mywrite!(w, "F");
mywrite!(w, "{}|", (cx.ds)(def_id));
enc_bare_fn_ty(w, cx, f);
}
- ty::ty_bare_fn(None, f) => {
+ ty::TyBareFn(None, f) => {
mywrite!(w, "G");
enc_bare_fn_ty(w, cx, f);
}
- ty::ty_infer(_) => {
+ ty::TyInfer(_) => {
cx.diag.handler().bug("cannot encode inference variable types");
}
- ty::ty_param(ParamTy {space, idx, name}) => {
+ ty::TyParam(ParamTy {space, idx, name}) => {
mywrite!(w, "p[{}|{}|{}]", idx, space.to_uint(), token::get_name(name))
}
- ty::ty_struct(def, substs) => {
+ ty::TyStruct(def, substs) => {
mywrite!(w, "a[{}|", (cx.ds)(def));
enc_substs(w, cx, substs);
mywrite!(w, "]");
}
- ty::ty_closure(def, substs) => {
+ ty::TyClosure(def, substs) => {
mywrite!(w, "k[{}|", (cx.ds)(def));
enc_substs(w, cx, substs);
mywrite!(w, "]");
}
- ty::ty_projection(ref data) => {
+ ty::TyProjection(ref data) => {
mywrite!(w, "P[");
enc_trait_ref(w, cx, data.trait_ref);
mywrite!(w, "{}]", token::get_name(data.item_name));
}
- ty::ty_err => {
+ ty::TyError => {
mywrite!(w, "e");
}
}
pub fn enc_existential_bounds<'a,'tcx>(w: &mut Encoder,
cx: &ctxt<'a,'tcx>,
bs: &ty::ExistentialBounds<'tcx>) {
- let param_bounds = ty::ParamBounds { trait_bounds: vec!(),
- region_bounds: vec!(bs.region_bound),
- builtin_bounds: bs.builtin_bounds,
- projection_bounds: bs.projection_bounds.clone() };
- enc_bounds(w, cx, ¶m_bounds);
-}
-
-pub fn enc_bounds<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>,
- bs: &ty::ParamBounds<'tcx>) {
enc_builtin_bounds(w, cx, &bs.builtin_bounds);
- enc_region_bounds(w, cx, &bs.region_bounds);
-
- for tp in &bs.trait_bounds {
- mywrite!(w, "I");
- enc_trait_ref(w, cx, tp.0);
- }
+ enc_region(w, cx, bs.region_bound);
for tp in &bs.projection_bounds {
mywrite!(w, "P");
}
mywrite!(w, ".");
+
+ mywrite!(w, "{}", if bs.region_bound_will_change {'y'} else {'n'});
}
pub fn enc_region_bounds<'a, 'tcx>(w: &mut Encoder,
fn enc_object_lifetime_default<'a, 'tcx>(w: &mut Encoder,
cx: &ctxt<'a, 'tcx>,
- default: Option<ty::ObjectLifetimeDefault>)
+ default: ty::ObjectLifetimeDefault)
{
match default {
- None => mywrite!(w, "n"),
- Some(ty::ObjectLifetimeDefault::Ambiguous) => mywrite!(w, "a"),
- Some(ty::ObjectLifetimeDefault::Specific(r)) => {
+ ty::ObjectLifetimeDefault::Ambiguous => mywrite!(w, "a"),
+ ty::ObjectLifetimeDefault::BaseDefault => mywrite!(w, "b"),
+ ty::ObjectLifetimeDefault::Specific(r) => {
mywrite!(w, "s");
enc_region(w, cx, r);
}
use middle::def;
use middle::ty::{self, Ty};
use syntax::ast;
-use util::ppaux::Repr;
pub const NO_REGIONS: usize = 1;
pub const NO_TPS: usize = 2;
let def = match tcx.def_map.borrow().get(&ast_ty.id) {
None => {
tcx.sess.span_bug(ast_ty.span,
- &format!("unbound path {}", path.repr(tcx)))
+ &format!("unbound path {:?}", path))
}
Some(d) => d.full_def()
};
// FIXME: remove this after snapshot, and Results are handled
#![allow(unused_must_use)]
+use ast_map;
use metadata::common as c;
use metadata::cstore as cstore;
use session::Session;
use metadata::encoder as e;
use middle::region;
use metadata::tydecode;
-use metadata::tydecode::{DefIdSource, NominalType, TypeWithId, TypeParameter};
+use metadata::tydecode::{DefIdSource, NominalType, TypeWithId};
use metadata::tydecode::{RegionParameter, ClosureSource};
use metadata::tyencode;
+use middle::cast;
use middle::check_const::ConstQualif;
use middle::mem_categorization::Typer;
use middle::privacy::{AllPublic, LastMod};
use middle::subst;
use middle::subst::VecPerParamSpace;
use middle::ty::{self, Ty, MethodCall, MethodCallee, MethodOrigin};
-use util::ppaux::ty_to_string;
-use syntax::{ast, ast_map, ast_util, codemap, fold};
+use syntax::{ast, ast_util, codemap, fold};
use syntax::codemap::Span;
use syntax::fold::Folder;
use syntax::parse::token;
/// codemap as a side-effect of creating the crate_metadata's
/// `codemap_import_info`.
pub fn tr_span(&self, span: Span) -> Span {
- let imported_filemaps = &self.cdata.codemap_import_info[..];
-
let span = if span.lo > span.hi {
// Currently macro expansion sometimes produces invalid Span values
// where lo > hi. In order not to crash the compiler when trying to
span
};
- let filemap_index = {
+ let imported_filemaps = self.cdata.imported_filemaps(self.tcx.sess.codemap());
+ let filemap = {
// Optimize for the case that most spans within a translated item
// originate from the same filemap.
let last_filemap_index = self.last_filemap_index.get();
+ let last_filemap = &imported_filemaps[last_filemap_index];
- if span.lo >= imported_filemaps[last_filemap_index].original_start_pos &&
- span.lo <= imported_filemaps[last_filemap_index].original_end_pos &&
- span.hi >= imported_filemaps[last_filemap_index].original_start_pos &&
- span.hi <= imported_filemaps[last_filemap_index].original_end_pos {
- last_filemap_index
+ if span.lo >= last_filemap.original_start_pos &&
+ span.lo <= last_filemap.original_end_pos &&
+ span.hi >= last_filemap.original_start_pos &&
+ span.hi <= last_filemap.original_end_pos {
+ last_filemap
} else {
let mut a = 0;
let mut b = imported_filemaps.len();
}
self.last_filemap_index.set(a);
- a
+ &imported_filemaps[a]
}
};
- let lo = (span.lo - imported_filemaps[filemap_index].original_start_pos) +
- imported_filemaps[filemap_index].translated_filemap.start_pos;
- let hi = (span.hi - imported_filemaps[filemap_index].original_start_pos) +
- imported_filemaps[filemap_index].translated_filemap.start_pos;
+ let lo = (span.lo - filemap.original_start_pos) +
+ filemap.translated_filemap.start_pos;
+ let hi = (span.hi - filemap.original_start_pos) +
+ filemap.translated_filemap.start_pos;
codemap::mk_sp(lo, hi)
}
// ______________________________________________________________________
// Encoding and decoding the AST itself
//
-// The hard work is done by an autogenerated module astencode_gen. To
-// regenerate astencode_gen, run src/etc/gen-astencode. It will
-// replace astencode_gen with a dummy file and regenerate its
-// contents. If you get compile errors, the dummy file
-// remains---resolve the errors and then rerun astencode_gen.
-// Annoying, I know, but hopefully only temporary.
-//
// When decoding, we have to renumber the AST so that the node ids that
// appear within are disjoint from the node ids in our existing ASTs.
// We also have to adjust the spans: for now we just insert a dummy span,
}
}
-impl<'tcx> tr for MethodOrigin<'tcx> {
- fn tr(&self, dcx: &DecodeContext) -> MethodOrigin<'tcx> {
- match *self {
- ty::MethodStatic(did) => ty::MethodStatic(did.tr(dcx)),
- ty::MethodStaticClosure(did) => {
- ty::MethodStaticClosure(did.tr(dcx))
- }
- ty::MethodTypeParam(ref mp) => {
- ty::MethodTypeParam(
- ty::MethodParam {
- // def-id is already translated when we read it out
- trait_ref: mp.trait_ref.clone(),
- method_num: mp.method_num,
- impl_def_id: mp.impl_def_id.tr(dcx),
- }
- )
- }
- ty::MethodTraitObject(ref mo) => {
- ty::MethodTraitObject(
- ty::MethodObject {
- trait_ref: mo.trait_ref.clone(),
- .. *mo
- }
- )
- }
- }
- }
+pub fn encode_closure_kind(ebml_w: &mut Encoder, kind: ty::ClosureKind) {
+ kind.encode(ebml_w).unwrap();
}
-pub fn encode_closure_kind(ebml_w: &mut Encoder, kind: ty::ClosureKind) {
+pub fn encode_cast_kind(ebml_w: &mut Encoder, kind: cast::CastKind) {
kind.encode(ebml_w).unwrap();
}
pub trait vtable_decoder_helpers<'tcx> {
fn read_vec_per_param_space<T, F>(&mut self, f: F) -> VecPerParamSpace<T> where
F: FnMut(&mut Self) -> T;
- fn read_vtable_res_with_key(&mut self,
- tcx: &ty::ctxt<'tcx>,
- cdata: &cstore::crate_metadata)
- -> (u32, ty::vtable_res<'tcx>);
- fn read_vtable_res(&mut self,
- tcx: &ty::ctxt<'tcx>, cdata: &cstore::crate_metadata)
- -> ty::vtable_res<'tcx>;
- fn read_vtable_param_res(&mut self,
- tcx: &ty::ctxt<'tcx>, cdata: &cstore::crate_metadata)
- -> ty::vtable_param_res<'tcx>;
- fn read_vtable_origin(&mut self,
- tcx: &ty::ctxt<'tcx>, cdata: &cstore::crate_metadata)
- -> ty::vtable_origin<'tcx>;
}
impl<'tcx, 'a> vtable_decoder_helpers<'tcx> for reader::Decoder<'a> {
let fns = self.read_to_vec(|this| Ok(f(this))).unwrap();
VecPerParamSpace::new(types, selfs, fns)
}
-
- fn read_vtable_res_with_key(&mut self,
- tcx: &ty::ctxt<'tcx>,
- cdata: &cstore::crate_metadata)
- -> (u32, ty::vtable_res<'tcx>) {
- self.read_struct("VtableWithKey", 2, |this| {
- let autoderef = this.read_struct_field("autoderef", 0, |this| {
- Decodable::decode(this)
- }).unwrap();
- Ok((autoderef, this.read_struct_field("vtable_res", 1, |this| {
- Ok(this.read_vtable_res(tcx, cdata))
- }).unwrap()))
- }).unwrap()
- }
-
- fn read_vtable_res(&mut self,
- tcx: &ty::ctxt<'tcx>,
- cdata: &cstore::crate_metadata)
- -> ty::vtable_res<'tcx>
- {
- self.read_vec_per_param_space(
- |this| this.read_vtable_param_res(tcx, cdata))
- }
-
- fn read_vtable_param_res(&mut self,
- tcx: &ty::ctxt<'tcx>, cdata: &cstore::crate_metadata)
- -> ty::vtable_param_res<'tcx> {
- self.read_to_vec(|this| Ok(this.read_vtable_origin(tcx, cdata)))
- .unwrap().into_iter().collect()
- }
-
- fn read_vtable_origin(&mut self,
- tcx: &ty::ctxt<'tcx>, cdata: &cstore::crate_metadata)
- -> ty::vtable_origin<'tcx> {
- self.read_enum("vtable_origin", |this| {
- this.read_enum_variant(&["vtable_static",
- "vtable_param",
- "vtable_error",
- "vtable_closure"],
- |this, i| {
- Ok(match i {
- 0 => {
- ty::vtable_static(
- this.read_enum_variant_arg(0, |this| {
- Ok(this.read_def_id_nodcx(cdata))
- }).unwrap(),
- this.read_enum_variant_arg(1, |this| {
- Ok(this.read_substs_nodcx(tcx, cdata))
- }).unwrap(),
- this.read_enum_variant_arg(2, |this| {
- Ok(this.read_vtable_res(tcx, cdata))
- }).unwrap()
- )
- }
- 1 => {
- ty::vtable_param(
- this.read_enum_variant_arg(0, |this| {
- Decodable::decode(this)
- }).unwrap(),
- this.read_enum_variant_arg(1, |this| {
- this.read_uint()
- }).unwrap()
- )
- }
- 2 => {
- ty::vtable_closure(
- this.read_enum_variant_arg(0, |this| {
- Ok(this.read_def_id_nodcx(cdata))
- }).unwrap()
- )
- }
- 3 => {
- ty::vtable_error
- }
- _ => panic!("bad enum variant")
- })
- })
- }).unwrap()
- }
}
// ___________________________________________________________________________
})
}
- if let Some(trait_ref) = tcx.object_cast_map.borrow().get(&id) {
- rbml_w.tag(c::tag_table_object_cast_map, |rbml_w| {
- rbml_w.id(id);
- rbml_w.emit_trait_ref(ecx, &trait_ref.0);
- })
- }
-
if let Some(adjustment) = tcx.adjustments.borrow().get(&id) {
match *adjustment {
ty::AdjustDerefRef(ref adj) => {
})
}
- for &qualif in tcx.const_qualif_map.borrow().get(&id).iter() {
+ if let Some(cast_kind) = tcx.cast_kinds.borrow().get(&id) {
+ rbml_w.tag(c::tag_table_cast_kinds, |rbml_w| {
+ rbml_w.id(id);
+ encode_cast_kind(rbml_w, *cast_kind)
+ })
+ }
+
+ if let Some(qualif) = tcx.const_qualif_map.borrow().get(&id) {
rbml_w.tag(c::tag_table_const_qualif, |rbml_w| {
rbml_w.id(id);
qualif.encode(rbml_w).unwrap()
-> subst::Substs<'tcx>;
fn read_auto_adjustment<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
-> ty::AutoAdjustment<'tcx>;
+ fn read_cast_kind<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
+ -> cast::CastKind;
fn read_closure_kind<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
-> ty::ClosureKind;
fn read_closure_ty<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
-> subst::Substs<'tcx> {
self.read_opaque(|this, doc| {
Ok(tydecode::parse_substs_data(doc.data,
- dcx.cdata.cnum,
- doc.start,
- dcx.tcx,
- |s, a| this.convert_def_id(dcx, s, a)))
+ dcx.cdata.cnum,
+ doc.start,
+ dcx.tcx,
+ |s, a| this.convert_def_id(dcx, s, a)))
}).unwrap()
}
}).unwrap()
}
+ fn read_cast_kind<'b, 'c>(&mut self, _dcx: &DecodeContext<'b, 'c, 'tcx>)
+ -> cast::CastKind
+ {
+ Decodable::decode(self).unwrap()
+ }
+
fn read_closure_kind<'b, 'c>(&mut self, _dcx: &DecodeContext<'b, 'c, 'tcx>)
-> ty::ClosureKind
{
-> ast::DefId {
let r = match source {
NominalType | TypeWithId | RegionParameter => dcx.tr_def_id(did),
- TypeParameter | ClosureSource => dcx.tr_intern_def_id(did)
+ ClosureSource => dcx.tr_intern_def_id(did)
};
debug!("convert_def_id(source={:?}, did={:?})={:?}", source, did, r);
return r;
fn decode_side_tables(dcx: &DecodeContext,
ast_doc: rbml::Doc) {
let tbl_doc = ast_doc.get(c::tag_table as usize);
- reader::docs(tbl_doc, |tag, entry_doc| {
+ for (tag, entry_doc) in reader::docs(tbl_doc) {
let mut entry_dsr = reader::Decoder::new(entry_doc);
let id0: ast::NodeId = Decodable::decode(&mut entry_dsr).unwrap();
let id = dcx.tr_id(id0);
}
c::tag_table_node_type => {
let ty = val_dsr.read_ty(dcx);
- debug!("inserting ty for node {}: {}",
- id, ty_to_string(dcx.tcx, ty));
+ debug!("inserting ty for node {}: {:?}",
+ id, ty);
dcx.tcx.node_type_insert(id, ty);
}
c::tag_table_item_subst => {
};
dcx.tcx.method_map.borrow_mut().insert(method_call, method);
}
- c::tag_table_object_cast_map => {
- let trait_ref = val_dsr.read_poly_trait_ref(dcx);
- dcx.tcx.object_cast_map.borrow_mut()
- .insert(id, trait_ref);
- }
c::tag_table_adjustments => {
let adj: ty::AutoAdjustment = val_dsr.read_auto_adjustment(dcx);
dcx.tcx.adjustments.borrow_mut().insert(id, adj);
dcx.tcx.closure_kinds.borrow_mut().insert(ast_util::local_def(id),
closure_kind);
}
+ c::tag_table_cast_kinds => {
+ let cast_kind =
+ val_dsr.read_cast_kind(dcx);
+ dcx.tcx.cast_kinds.borrow_mut().insert(id, cast_kind);
+ }
c::tag_table_const_qualif => {
let qualif: ConstQualif = Decodable::decode(val_dsr).unwrap();
dcx.tcx.const_qualif_map.borrow_mut().insert(id, qualif);
}
debug!(">< Side table doc loaded");
- true
- });
+ }
}
// ______________________________________________________________________
#[cfg(test)]
fn mk_ctxt() -> parse::ParseSess {
- parse::new_parse_sess()
+ parse::ParseSess::new()
}
#[cfg(test)]
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Helpers for handling cast expressions, used in both
+// typeck and trans.
+
+use middle::ty::{self, Ty};
+
+use syntax::ast;
+
+/// Types that are represented as ints.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum IntTy {
+ U(ast::UintTy),
+ I,
+ CEnum,
+ Bool,
+ Char
+}
+
+// Valid types for the result of a non-coercion cast
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum CastTy<'tcx> {
+ /// Various types that are represented as ints and handled mostly
+ /// in the same way, merged for easier matching.
+ Int(IntTy),
+ /// Floating-Point types
+ Float,
+ /// Function Pointers
+ FnPtr,
+ /// Raw pointers
+ Ptr(&'tcx ty::mt<'tcx>),
+ /// References
+ RPtr(&'tcx ty::mt<'tcx>),
+}
+
+/// Cast Kind. See RFC 401 (or librustc_typeck/check/cast.rs)
+#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
+pub enum CastKind {
+ CoercionCast,
+ PtrPtrCast,
+ PtrAddrCast,
+ AddrPtrCast,
+ NumericCast,
+ EnumCast,
+ PrimIntCast,
+ U8CharCast,
+ ArrayPtrCast,
+ FnPtrPtrCast,
+ FnPtrAddrCast
+}
+
+impl<'tcx> CastTy<'tcx> {
+ pub fn from_ty(tcx: &ty::ctxt<'tcx>, t: Ty<'tcx>)
+ -> Option<CastTy<'tcx>> {
+ match t.sty {
+ ty::TyBool => Some(CastTy::Int(IntTy::Bool)),
+ ty::TyChar => Some(CastTy::Int(IntTy::Char)),
+ ty::TyInt(_) => Some(CastTy::Int(IntTy::I)),
+ ty::TyUint(u) => Some(CastTy::Int(IntTy::U(u))),
+ ty::TyFloat(_) => Some(CastTy::Float),
+ ty::TyEnum(..) if ty::type_is_c_like_enum(
+ tcx, t) => Some(CastTy::Int(IntTy::CEnum)),
+ ty::TyRawPtr(ref mt) => Some(CastTy::Ptr(mt)),
+ ty::TyRef(_, ref mt) => Some(CastTy::RPtr(mt)),
+ ty::TyBareFn(..) => Some(CastTy::FnPtr),
+ _ => None,
+ }
+ }
+}
ast::ExprRange(ref start, ref end) => {
let fields = start.as_ref().map(|e| &**e).into_iter()
- .chain(end.as_ref().map(|e| &**e).into_iter());
+ .chain(end.as_ref().map(|e| &**e));
self.straightline(expr, pred, fields)
}
use graphviz as dot;
use syntax::ast;
-use syntax::ast_map;
+use ast_map;
use middle::cfg;
pub type Node<'a> = (cfg::CFGIndex, &'a cfg::CFGNode);
}
pub fn node_is_reachable(&self, id: ast::NodeId) -> bool {
- self.graph.depth_traverse(self.entry).any(|node| node.id() == id)
+ self.graph.depth_traverse(self.entry)
+ .any(|idx| self.graph.node_data(idx).id() == id)
}
}
//
// - For each *mutable* static item, it checks that its **type**:
// - doesn't have a destructor
-// - doesn't own an owned pointer
+// - doesn't own a box
//
// - For each *immutable* static item, it checks that its **value**:
-// - doesn't own owned, managed pointers
+// - doesn't own a box
// - doesn't contain a struct literal or a call to an enum variant / struct constructor where
// - the type of the struct/enum has a dtor
//
// - It's not possible to take the address of a static item with unsafe interior. This is enforced
// by borrowck::gather_loans
+use middle::cast::{CastKind};
use middle::const_eval;
use middle::def;
use middle::expr_use_visitor as euv;
use middle::traits;
use middle::ty::{self, Ty};
use util::nodemap::NodeMap;
-use util::ppaux;
use syntax::ast;
use syntax::codemap::Span;
-use syntax::print::pprust;
use syntax::visit::{self, Visitor};
use std::collections::hash_map::Entry;
#[derive(Copy, Clone, Eq, PartialEq)]
enum Mode {
Const,
+ ConstFn,
Static,
StaticMut,
})
}
+ fn fn_like(&mut self,
+ fk: visit::FnKind,
+ fd: &ast::FnDecl,
+ b: &ast::Block,
+ s: Span,
+ fn_id: ast::NodeId)
+ -> ConstQualif {
+ match self.tcx.const_qualif_map.borrow_mut().entry(fn_id) {
+ Entry::Occupied(entry) => return *entry.get(),
+ Entry::Vacant(entry) => {
+ // Prevent infinite recursion on re-entry.
+ entry.insert(ConstQualif::empty());
+ }
+ }
+
+ let mode = match fk {
+ visit::FkItemFn(_, _, _, ast::Constness::Const, _, _) => {
+ Mode::ConstFn
+ }
+ visit::FkMethod(_, m, _) => {
+ if m.constness == ast::Constness::Const {
+ Mode::ConstFn
+ } else {
+ Mode::Var
+ }
+ }
+ _ => Mode::Var
+ };
+
+ // Ensure the arguments are simple, not mutable/by-ref or patterns.
+ if mode == Mode::ConstFn {
+ for arg in &fd.inputs {
+ match arg.pat.node {
+ ast::PatIdent(ast::BindByValue(ast::MutImmutable), _, None) => {}
+ _ => {
+ span_err!(self.tcx.sess, arg.pat.span, E0022,
+ "arguments of constant functions can only \
+ be immutable by-value bindings");
+ }
+ }
+ }
+ }
+
+ let qualif = self.with_mode(mode, |this| {
+ this.with_euv(Some(fn_id), |euv| euv.walk_fn(fd, b));
+ visit::walk_fn(this, fk, fd, b, s);
+ this.qualif
+ });
+
+ // Keep only bits that aren't affected by function body (NON_ZERO_SIZED),
+ // and bits that don't change semantics, just optimizations (PREFER_IN_PLACE).
+ let qualif = qualif & (ConstQualif::NON_ZERO_SIZED | ConstQualif::PREFER_IN_PLACE);
+
+ self.tcx.const_qualif_map.borrow_mut().insert(fn_id, qualif);
+ qualif
+ }
+
fn add_qualif(&mut self, qualif: ConstQualif) {
self.qualif = self.qualif | qualif;
}
+ /// Returns true if the call is to a const fn or method.
+ fn handle_const_fn_call(&mut self,
+ expr: &ast::Expr,
+ def_id: ast::DefId,
+ ret_ty: Ty<'tcx>)
+ -> bool {
+ if let Some(fn_like) = const_eval::lookup_const_fn_by_id(self.tcx, def_id) {
+ if
+ // we are in a static/const initializer
+ self.mode != Mode::Var &&
+
+ // feature-gate is not enabled
+ !self.tcx.sess.features.borrow().const_fn &&
+
+ // this doesn't come from a macro that has #[allow_internal_unstable]
+ !self.tcx.sess.codemap().span_allows_unstable(expr.span)
+ {
+ self.tcx.sess.span_err(
+ expr.span,
+ &format!("const fns are an unstable feature"));
+ fileline_help!(
+ self.tcx.sess,
+ expr.span,
+ "in Nightly builds, add `#![feature(const_fn)]` to the crate \
+ attributes to enable");
+ }
+
+ let qualif = self.fn_like(fn_like.kind(),
+ fn_like.decl(),
+ fn_like.body(),
+ fn_like.span(),
+ fn_like.id());
+ self.add_qualif(qualif);
+
+ if ty::type_contents(self.tcx, ret_ty).interior_unsafe() {
+ self.add_qualif(ConstQualif::MUTABLE_MEM);
+ }
+
+ true
+ } else {
+ false
+ }
+ }
+
fn record_borrow(&mut self, id: ast::NodeId, mutbl: ast::Mutability) {
match self.rvalue_borrows.entry(id) {
Entry::Occupied(mut entry) => {
fn msg(&self) -> &'static str {
match self.mode {
Mode::Const => "constant",
+ Mode::ConstFn => "constant function",
Mode::StaticMut | Mode::Static => "static",
Mode::Var => unreachable!(),
}
let suffix = if tcontents.has_dtor() {
"destructors"
} else if tcontents.owns_owned() {
- "owned pointers"
+ "boxes"
} else {
return
};
- self.tcx.sess.span_err(e.span, &format!("mutable statics are not allowed \
- to have {}", suffix));
+ span_err!(self.tcx.sess, e.span, E0397,
+ "mutable statics are not allowed to have {}", suffix);
}
fn check_static_type(&self, e: &ast::Expr) {
let ty = ty::node_id_to_type(self.tcx, e.id);
let infcx = infer::new_infer_ctxt(self.tcx);
- let mut fulfill_cx = traits::FulfillmentContext::new();
+ let mut fulfill_cx = traits::FulfillmentContext::new(false);
let cause = traits::ObligationCause::new(e.span, e.id, traits::SharedStatic);
fulfill_cx.register_builtin_bound(&infcx, ty, ty::BoundSync, cause);
let env = ty::empty_parameter_environment(self.tcx);
impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
fn visit_item(&mut self, i: &ast::Item) {
- debug!("visit_item(item={})", pprust::item_to_string(i));
+ debug!("visit_item(item={})", self.tcx.map.node_to_string(i.id));
match i.node {
ast::ItemStatic(_, ast::MutImmutable, ref expr) => {
self.check_static_type(&**expr);
b: &'v ast::Block,
s: Span,
fn_id: ast::NodeId) {
- assert!(self.mode == Mode::Var);
- self.with_euv(Some(fn_id), |euv| euv.walk_fn(fd, b));
- visit::walk_fn(self, fk, fd, b, s);
+ self.fn_like(fk, fd, b, s, fn_id);
}
fn visit_pat(&mut self, p: &ast::Pat) {
}
}
+ fn visit_block(&mut self, block: &ast::Block) {
+ // Check all statements in the block
+ for stmt in &block.stmts {
+ let span = match stmt.node {
+ ast::StmtDecl(ref decl, _) => {
+ match decl.node {
+ ast::DeclLocal(_) => decl.span,
+
+ // Item statements are allowed
+ ast::DeclItem(_) => continue
+ }
+ }
+ ast::StmtExpr(ref expr, _) => expr.span,
+ ast::StmtSemi(ref semi, _) => semi.span,
+ ast::StmtMac(..) => {
+ self.tcx.sess.span_bug(stmt.span, "unexpanded statement \
+ macro in const?!")
+ }
+ };
+ self.add_qualif(ConstQualif::NOT_CONST);
+ if self.mode != Mode::Var {
+ span_err!(self.tcx.sess, span, E0016,
+ "blocks in {}s are limited to items and \
+ tail expressions", self.msg());
+ }
+ }
+ visit::walk_block(self, block);
+ }
+
fn visit_expr(&mut self, ex: &ast::Expr) {
let mut outer = self.qualif;
self.qualif = ConstQualif::empty();
// Special-case some expressions to avoid certain flags bubbling up.
match ex.node {
ast::ExprCall(ref callee, ref args) => {
- for arg in args.iter() {
+ for arg in args {
self.visit_expr(&**arg)
}
self.visit_expr(&**element);
// The count is checked elsewhere (typeck).
let count = match node_ty.sty {
- ty::ty_vec(_, Some(n)) => n,
+ ty::TyArray(_, n) => n,
_ => unreachable!()
};
// [element; 0] is always zero-sized.
// Compute the most demanding borrow from all the arms'
// patterns and set that on the discriminator.
let mut borrow = None;
- for pat in arms.iter().flat_map(|arm| arm.pats.iter()) {
+ for pat in arms.iter().flat_map(|arm| &arm.pats) {
let pat_borrow = self.rvalue_borrows.remove(&pat.id);
match (borrow, pat_borrow) {
(None, _) | (_, Some(ast::MutMutable)) => {
visit::walk_expr(self, ex);
let div_or_rem = op.node == ast::BiDiv || op.node == ast::BiRem;
match node_ty.sty {
- ty::ty_uint(_) | ty::ty_int(_) if div_or_rem => {
+ ty::TyUint(_) | ty::TyInt(_) if div_or_rem => {
if !self.qualif.intersects(ConstQualif::NOT_CONST) {
match const_eval::eval_const_expr_partial(self.tcx, ex, None) {
Ok(_) => {}
fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
e: &ast::Expr, node_ty: Ty<'tcx>) {
match node_ty.sty {
- ty::ty_struct(did, _) |
- ty::ty_enum(did, _) if ty::has_dtor(v.tcx, did) => {
+ ty::TyStruct(did, _) |
+ ty::TyEnum(did, _) if ty::has_dtor(v.tcx, did) => {
v.add_qualif(ConstQualif::NEEDS_DROP);
if v.mode != Mode::Var {
v.tcx.sess.span_err(e.span,
"allocations are not allowed in {}s", v.msg());
}
}
- ast::ExprUnary(ast::UnDeref, ref ptr) => {
- match ty::node_id_to_type(v.tcx, ptr.id).sty {
- ty::ty_ptr(_) => {
- // This shouldn't be allowed in constants at all.
+ ast::ExprUnary(op, ref inner) => {
+ match ty::node_id_to_type(v.tcx, inner.id).sty {
+ ty::TyRawPtr(_) => {
+ assert!(op == ast::UnDeref);
+
v.add_qualif(ConstQualif::NOT_CONST);
+ if v.mode != Mode::Var {
+ span_err!(v.tcx.sess, e.span, E0396,
+ "raw pointers cannot be dereferenced in {}s", v.msg());
+ }
}
_ => {}
}
}
- ast::ExprCast(ref from, _) => {
- let toty = ty::expr_ty(v.tcx, e);
- let fromty = ty::expr_ty(v.tcx, &**from);
- let is_legal_cast =
- ty::type_is_numeric(toty) ||
- ty::type_is_unsafe_ptr(toty) ||
- (ty::type_is_bare_fn(toty) && ty::type_is_bare_fn_item(fromty));
- if !is_legal_cast {
- v.add_qualif(ConstQualif::NOT_CONST);
- if v.mode != Mode::Var {
- span_err!(v.tcx.sess, e.span, E0012,
- "can not cast to `{}` in {}s",
- ppaux::ty_to_string(v.tcx, toty), v.msg());
+ ast::ExprBinary(op, ref lhs, _) => {
+ match ty::node_id_to_type(v.tcx, lhs.id).sty {
+ ty::TyRawPtr(_) => {
+ assert!(op.node == ast::BiEq || op.node == ast::BiNe ||
+ op.node == ast::BiLe || op.node == ast::BiLt ||
+ op.node == ast::BiGe || op.node == ast::BiGt);
+
+ v.add_qualif(ConstQualif::NOT_CONST);
+ if v.mode != Mode::Var {
+ span_err!(v.tcx.sess, e.span, E0395,
+ "raw pointers cannot be compared in {}s", v.msg());
+ }
}
+ _ => {}
}
- if ty::type_is_unsafe_ptr(fromty) && ty::type_is_numeric(toty) {
- v.add_qualif(ConstQualif::NOT_CONST);
- if v.mode != Mode::Var {
- span_err!(v.tcx.sess, e.span, E0018,
- "can not cast a pointer to an integer in {}s", v.msg());
+ }
+ ast::ExprCast(ref from, _) => {
+ debug!("Checking const cast(id={})", from.id);
+ match v.tcx.cast_kinds.borrow().get(&from.id) {
+ None => v.tcx.sess.span_bug(e.span, "no kind for cast"),
+ Some(&CastKind::PtrAddrCast) | Some(&CastKind::FnPtrAddrCast) => {
+ v.add_qualif(ConstQualif::NOT_CONST);
+ if v.mode != Mode::Var {
+ span_err!(v.tcx.sess, e.span, E0018,
+ "raw pointers cannot be cast to integers in {}s", v.msg());
+ }
}
+ _ => {}
}
}
ast::ExprPath(..) => {
v.add_qualif(ConstQualif::NON_ZERO_SIZED);
}
Some(def::DefStruct(_)) => {
- if let ty::ty_bare_fn(..) = node_ty.sty {
+ if let ty::TyBareFn(..) = node_ty.sty {
// Count the function pointer.
v.add_qualif(ConstQualif::NON_ZERO_SIZED);
}
Some(def::DefStatic(..)) => {
match v.mode {
Mode::Static | Mode::StaticMut => {}
- Mode::Const => {
+ Mode::Const | Mode::ConstFn => {
span_err!(v.tcx.sess, e.span, E0013,
- "constants cannot refer to other statics, \
- insert an intermediate constant instead");
+ "{}s cannot refer to other statics, insert \
+ an intermediate constant instead", v.msg());
}
Mode::Var => v.add_qualif(ConstQualif::NOT_CONST)
}
doesn't point to a constant");
}
}
+ Some(def::DefLocal(_)) if v.mode == Mode::ConstFn => {
+ // Sadly, we can't determine whether the types are zero-sized.
+ v.add_qualif(ConstQualif::NOT_CONST | ConstQualif::NON_ZERO_SIZED);
+ }
def => {
v.add_qualif(ConstQualif::NOT_CONST);
if v.mode != Mode::Var {
};
}
let def = v.tcx.def_map.borrow().get(&callee.id).map(|d| d.full_def());
- match def {
- Some(def::DefStruct(..)) => {}
+ let is_const = match def {
+ Some(def::DefStruct(..)) => true,
Some(def::DefVariant(..)) => {
// Count the discriminator.
v.add_qualif(ConstQualif::NON_ZERO_SIZED);
+ true
}
- _ => {
- v.add_qualif(ConstQualif::NOT_CONST);
- if v.mode != Mode::Var {
- span_err!(v.tcx.sess, e.span, E0015,
- "function calls in {}s are limited to \
- struct and enum constructors", v.msg());
- }
+ Some(def::DefMethod(did, def::FromImpl(_))) |
+ Some(def::DefFn(did, _)) => {
+ v.handle_const_fn_call(e, did, node_ty)
}
- }
- }
- ast::ExprBlock(ref block) => {
- // Check all statements in the block
- let mut block_span_err = |span| {
+ _ => false
+ };
+ if !is_const {
v.add_qualif(ConstQualif::NOT_CONST);
if v.mode != Mode::Var {
- span_err!(v.tcx.sess, span, E0016,
- "blocks in {}s are limited to items and \
- tail expressions", v.msg());
+ span_err!(v.tcx.sess, e.span, E0015,
+ "function calls in {}s are limited to \
+ constant functions, \
+ struct and enum constructors", v.msg());
}
+ }
+ }
+ ast::ExprMethodCall(..) => {
+ let method_did = match v.tcx.method_map.borrow()[&method_call].origin {
+ ty::MethodStatic(did) => Some(did),
+ _ => None
};
- for stmt in &block.stmts {
- match stmt.node {
- ast::StmtDecl(ref decl, _) => {
- match decl.node {
- ast::DeclLocal(_) => block_span_err(decl.span),
-
- // Item statements are allowed
- ast::DeclItem(_) => {}
- }
- }
- ast::StmtExpr(ref expr, _) => block_span_err(expr.span),
- ast::StmtSemi(ref semi, _) => block_span_err(semi.span),
- ast::StmtMac(..) => {
- v.tcx.sess.span_bug(e.span, "unexpanded statement \
- macro in const?!")
- }
+ let is_const = match method_did {
+ Some(did) => v.handle_const_fn_call(e, did, node_ty),
+ None => false
+ };
+ if !is_const {
+ v.add_qualif(ConstQualif::NOT_CONST);
+ if v.mode != Mode::Var {
+ span_err!(v.tcx.sess, e.span, E0378,
+ "method calls in {}s are limited to \
+ constant inherent methods", v.msg());
}
}
}
}
ast::ExprClosure(..) => {
- // Paths in constant constexts cannot refer to local variables,
+ // Paths in constant contexts cannot refer to local variables,
// as there are none, and thus closures can't have upvars there.
if ty::with_freevars(v.tcx, e.id, |fv| !fv.is_empty()) {
assert!(v.mode == Mode::Var,
}
}
- ast::ExprUnary(..) |
- ast::ExprBinary(..) |
+ ast::ExprBlock(_) |
ast::ExprIndex(..) |
ast::ExprField(..) |
ast::ExprTupField(..) |
// Miscellaneous expressions that could be implemented.
ast::ExprRange(..) |
- // Various other expressions.
- ast::ExprMethodCall(..) |
+ // Expressions with side-effects.
ast::ExprAssign(..) |
ast::ExprAssignOp(..) |
ast::ExprInlineAsm(_) |
// statics cannot be consumed by value at any time, that would imply
// that they're an initializer (what a const is for) or kept in sync
// over time (not feasible), so deny it outright.
- self.tcx.sess.span_err(consume_span,
- "cannot refer to other statics by value, use the \
- address-of operator or a constant instead");
+ span_err!(self.tcx.sess, consume_span, E0394,
+ "cannot refer to other statics by value, use the \
+ address-of operator or a constant instead");
}
break;
}
}
let mutbl = bk.to_mutbl_lossy();
if mutbl == ast::MutMutable && self.mode == Mode::StaticMut {
- // Mutable slices are the only `&mut` allowed in globals,
- // but only in `static mut`, nowhere else.
+ // Mutable slices are the only `&mut` allowed in
+ // globals, but only in `static mut`, nowhere else.
+ // FIXME: This exception is really weird... there isn't
+ // any fundamental reason to restrict this based on
+ // type of the expression. `&mut [1]` has exactly the
+ // same representation as &mut 1.
match cmt.ty.sty {
- ty::ty_vec(_, _) => break,
+ ty::TyArray(_, _) | ty::TySlice(_) => break,
_ => {}
}
}
use self::Usefulness::*;
use self::WitnessPreference::*;
-use middle::const_eval::{compare_const_vals, const_bool, const_float, const_val};
+use middle::const_eval::{compare_const_vals, ConstVal};
use middle::const_eval::{eval_const_expr, eval_const_expr_partial};
use middle::const_eval::{const_expr_to_pat, lookup_const_by_id};
use middle::def::*;
use syntax::parse::token;
use syntax::ptr::P;
use syntax::visit::{self, Visitor, FnKind};
-use util::ppaux::ty_to_string;
use util::nodemap::FnvHashMap;
pub const DUMMY_WILD_PAT: &'static Pat = &Pat {
/// Enum variants.
Variant(ast::DefId),
/// Literal values.
- ConstantValue(const_val),
+ ConstantValue(ConstVal),
/// Ranges of literal values (2..5).
- ConstantRange(const_val, const_val),
+ ConstantRange(ConstVal, ConstVal),
/// Array patterns of length n.
Slice(usize),
/// Array patterns with a subslice.
for pat in inlined_arms
.iter()
- .flat_map(|&(ref pats, _)| pats.iter()) {
+ .flat_map(|&(ref pats, _)| pats) {
// Third, check legality of move bindings.
check_legality_of_bindings_in_at_patterns(cx, &**pat);
if !type_is_empty(cx.tcx, pat_ty) {
// We know the type is inhabited, so this must be wrong
span_err!(cx.tcx.sess, ex.span, E0002,
- "non-exhaustive patterns: type {} is non-empty",
- ty_to_string(cx.tcx, pat_ty)
- );
+ "non-exhaustive patterns: type {} is non-empty",
+ pat_ty);
}
// If the type *is* empty, it's vacuously exhaustive
return;
let matrix: Matrix = inlined_arms
.iter()
.filter(|&&(_, guard)| guard.is_none())
- .flat_map(|arm| arm.0.iter())
+ .flat_map(|arm| &arm.0)
.map(|pat| vec![&**pat])
.collect();
check_exhaustive(cx, ex.span, &matrix, source);
match p.node {
ast::PatIdent(ast::BindByValue(ast::MutImmutable), ident, None) => {
let pat_ty = ty::pat_ty(cx.tcx, p);
- if let ty::ty_enum(def_id, _) = pat_ty.sty {
+ if let ty::TyEnum(def_id, _) = pat_ty.sty {
let def = cx.tcx.def_map.borrow().get(&p.id).map(|d| d.full_def());
if let Some(DefLocal(_)) = def {
if ty::enum_variants(cx.tcx, def_id).iter().any(|variant|
span_warn!(cx.tcx.sess, p.span, E0170,
"pattern binding `{}` is named the same as one \
of the variants of the type `{}`",
- &token::get_ident(ident.node), ty_to_string(cx.tcx, pat_ty));
+ &token::get_ident(ident.node), pat_ty);
fileline_help!(cx.tcx.sess, p.span,
"if you meant to match on a variant, \
consider making the path in the pattern qualified: `{}::{}`",
- ty_to_string(cx.tcx, pat_ty), &token::get_ident(ident.node));
+ pat_ty, &token::get_ident(ident.node));
}
}
}
ast_util::walk_pat(pat, |p| {
if let ast::PatLit(ref expr) = p.node {
match eval_const_expr_partial(cx.tcx, &**expr, None) {
- Ok(const_float(f)) if f.is_nan() => {
+ Ok(ConstVal::Float(f)) if f.is_nan() => {
span_warn!(cx.tcx.sess, p.span, E0003,
"unmatchable NaN in pattern, \
use the is_nan method in a guard instead");
}
}
-fn const_val_to_expr(value: &const_val) -> P<ast::Expr> {
+fn const_val_to_expr(value: &ConstVal) -> P<ast::Expr> {
let node = match value {
- &const_bool(b) => ast::LitBool(b),
+ &ConstVal::Bool(b) => ast::LitBool(b),
_ => unreachable!()
};
P(ast::Expr {
let pats_len = pats.len();
let mut pats = pats.into_iter().map(|p| P((*p).clone()));
let pat = match left_ty.sty {
- ty::ty_tup(_) => ast::PatTup(pats.collect()),
+ ty::TyTuple(_) => ast::PatTup(pats.collect()),
- ty::ty_enum(cid, _) | ty::ty_struct(cid, _) => {
+ ty::TyEnum(cid, _) | ty::TyStruct(cid, _) => {
let (vid, is_structure) = match ctor {
&Variant(vid) =>
(vid, ty::enum_variant_with_id(cx.tcx, cid, vid).arg_names.is_some()),
}
}
- ty::ty_rptr(_, ty::mt { ty, mutbl }) => {
+ ty::TyRef(_, ty::mt { ty, mutbl }) => {
match ty.sty {
- ty::ty_vec(_, Some(n)) => match ctor {
+ ty::TyArray(_, n) => match ctor {
&Single => {
assert_eq!(pats_len, n);
ast::PatVec(pats.collect(), None, vec!())
},
_ => unreachable!()
},
- ty::ty_vec(_, None) => match ctor {
+ ty::TySlice(_) => match ctor {
&Slice(n) => {
assert_eq!(pats_len, n);
ast::PatVec(pats.collect(), None, vec!())
},
_ => unreachable!()
},
- ty::ty_str => ast::PatWild(ast::PatWildSingle),
+ ty::TyStr => ast::PatWild(ast::PatWildSingle),
_ => {
assert_eq!(pats_len, 1);
}
}
- ty::ty_vec(_, Some(len)) => {
+ ty::TyArray(_, len) => {
assert_eq!(pats_len, len);
ast::PatVec(pats.collect(), None, vec![])
}
fn missing_constructor(cx: &MatchCheckCtxt, &Matrix(ref rows): &Matrix,
left_ty: Ty, max_slice_length: usize) -> Option<Constructor> {
let used_constructors: Vec<Constructor> = rows.iter()
- .flat_map(|row| pat_constructors(cx, row[0], left_ty, max_slice_length).into_iter())
+ .flat_map(|row| pat_constructors(cx, row[0], left_ty, max_slice_length))
.collect();
all_constructors(cx, left_ty, max_slice_length)
.into_iter()
fn all_constructors(cx: &MatchCheckCtxt, left_ty: Ty,
max_slice_length: usize) -> Vec<Constructor> {
match left_ty.sty {
- ty::ty_bool =>
- [true, false].iter().map(|b| ConstantValue(const_bool(*b))).collect(),
+ ty::TyBool =>
+ [true, false].iter().map(|b| ConstantValue(ConstVal::Bool(*b))).collect(),
- ty::ty_rptr(_, ty::mt { ty, .. }) => match ty.sty {
- ty::ty_vec(_, None) =>
+ ty::TyRef(_, ty::mt { ty, .. }) => match ty.sty {
+ ty::TySlice(_) =>
range_inclusive(0, max_slice_length).map(|length| Slice(length)).collect(),
_ => vec!(Single)
},
- ty::ty_enum(eid, _) =>
+ ty::TyEnum(eid, _) =>
ty::enum_variants(cx.tcx, eid)
.iter()
.map(|va| Variant(va.id))
let wild_pats: Vec<_> = repeat(DUMMY_WILD_PAT).take(arity).collect();
let enum_pat = construct_witness(cx, &constructor, wild_pats, left_ty);
let mut new_pats = vec![enum_pat];
- new_pats.extend(pats.into_iter());
+ new_pats.extend(pats);
UsefulWithWitness(new_pats)
},
result => result
vec!(ConstantRange(eval_const_expr(cx.tcx, &**lo), eval_const_expr(cx.tcx, &**hi))),
ast::PatVec(ref before, ref slice, ref after) =>
match left_ty.sty {
- ty::ty_vec(_, Some(_)) => vec!(Single),
+ ty::TyArray(_, _) => vec!(Single),
_ => if slice.is_some() {
range_inclusive(before.len() + after.len(), max_slice_length)
.map(|length| Slice(length))
/// A struct pattern's arity is the number of fields it contains, etc.
pub fn constructor_arity(cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> usize {
match ty.sty {
- ty::ty_tup(ref fs) => fs.len(),
- ty::ty_uniq(_) => 1,
- ty::ty_rptr(_, ty::mt { ty, .. }) => match ty.sty {
- ty::ty_vec(_, None) => match *ctor {
+ ty::TyTuple(ref fs) => fs.len(),
+ ty::TyBox(_) => 1,
+ ty::TyRef(_, ty::mt { ty, .. }) => match ty.sty {
+ ty::TySlice(_) => match *ctor {
Slice(length) => length,
ConstantValue(_) => 0,
_ => unreachable!()
},
- ty::ty_str => 0,
+ ty::TyStr => 0,
_ => 1
},
- ty::ty_enum(eid, _) => {
+ ty::TyEnum(eid, _) => {
match *ctor {
Variant(id) => enum_variant_with_id(cx.tcx, eid, id).args.len(),
_ => unreachable!()
}
}
- ty::ty_struct(cid, _) => ty::lookup_struct_fields(cx.tcx, cid).len(),
- ty::ty_vec(_, Some(n)) => n,
+ ty::TyStruct(cid, _) => ty::lookup_struct_fields(cx.tcx, cid).len(),
+ ty::TyArray(_, n) => n,
_ => 0
}
}
fn range_covered_by_constructor(ctor: &Constructor,
- from: &const_val, to: &const_val) -> Option<bool> {
+ from: &ConstVal, to: &ConstVal) -> Option<bool> {
let (c_from, c_to) = match *ctor {
ConstantValue(ref value) => (value, value),
ConstantRange(ref from, ref to) => (from, to),
use middle::mem_categorization as mc;
use middle::ty::ParameterEnvironment;
use middle::ty;
-use util::ppaux::ty_to_string;
use syntax::ast;
use syntax::codemap::Span;
span: Span,
cmt: mc::cmt<'tcx>,
_: euv::ConsumeMode) {
- debug!("consume; cmt: {:?}; type: {}", *cmt, ty_to_string(self.tcx, cmt.ty));
- if !ty::type_is_sized(self.param_env, span, cmt.ty) {
+ debug!("consume; cmt: {:?}; type: {:?}", *cmt, cmt.ty);
+ if !ty::type_is_sized(Some(self.param_env), self.tcx, span, cmt.ty) {
span_err!(self.tcx.sess, span, E0161,
"cannot move a value of type {0}: the size of {0} cannot be statically determined",
- ty_to_string(self.tcx, cmt.ty));
+ cmt.ty);
}
}
// This compiler pass detects static items that refer to themselves
// recursively.
+use ast_map;
use session::Session;
use middle::def::{DefStatic, DefConst, DefAssociatedConst, DefMap};
-use syntax::ast;
-use syntax::{ast_util, ast_map};
+use syntax::{ast, ast_util};
use syntax::codemap::Span;
use syntax::visit::Visitor;
use syntax::visit;
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
#![allow(non_camel_case_types)]
#![allow(unsigned_negation)]
-pub use self::const_val::*;
+use self::ConstVal::*;
use self::ErrKind::*;
+use ast_map;
+use ast_map::blocks::FnLikeNode;
use metadata::csearch;
use middle::{astencode, def, infer, subst, traits};
use middle::pat_util::def_to_path;
use middle::ty::{self, Ty};
use middle::astconv_util::ast_ty_to_prim_ty;
use util::num::ToPrimitive;
-use util::ppaux::Repr;
use syntax::ast::{self, Expr};
+use syntax::ast_util;
use syntax::codemap::Span;
use syntax::feature_gate;
use syntax::parse::token::InternedString;
use syntax::ptr::P;
-use syntax::{ast_map, ast_util, codemap};
+use syntax::{codemap, visit};
use std::borrow::{Cow, IntoCow};
use std::num::wrapping::OverflowingOps;
use std::cmp::Ordering;
use std::collections::hash_map::Entry::Vacant;
-use std::{i8, i16, i32, i64};
+use std::{i8, i16, i32, i64, u8, u16, u32, u64};
use std::rc::Rc;
fn lookup_const<'a>(tcx: &'a ty::ctxt, e: &Expr) -> Option<&'a Expr> {
Some(ref_id) => {
let trait_id = ty::trait_of_item(tcx, def_id)
.unwrap();
+ let substs = ty::node_id_item_substs(tcx, ref_id)
+ .substs;
resolve_trait_associated_const(tcx, ti, trait_id,
- ref_id)
+ substs)
}
// Technically, without knowing anything about the
// expression that generates the obligation, we could
// a trait-associated const if the caller gives us
// the expression that refers to it.
Some(ref_id) => {
+ let substs = ty::node_id_item_substs(tcx, ref_id)
+ .substs;
resolve_trait_associated_const(tcx, ti, trait_id,
- ref_id).map(|e| e.id)
+ substs).map(|e| e.id)
}
None => None
}
}
}
+fn inline_const_fn_from_external_crate(tcx: &ty::ctxt, def_id: ast::DefId)
+ -> Option<ast::NodeId> {
+ match tcx.extern_const_fns.borrow().get(&def_id) {
+ Some(&ast::DUMMY_NODE_ID) => return None,
+ Some(&fn_id) => return Some(fn_id),
+ None => {}
+ }
+
+ if !csearch::is_const_fn(&tcx.sess.cstore, def_id) {
+ tcx.extern_const_fns.borrow_mut().insert(def_id, ast::DUMMY_NODE_ID);
+ return None;
+ }
+
+ let fn_id = match csearch::maybe_get_item_ast(tcx, def_id,
+ box |a, b, c, d| astencode::decode_inlined_item(a, b, c, d)) {
+ csearch::FoundAst::Found(&ast::IIItem(ref item)) => Some(item.id),
+ csearch::FoundAst::Found(&ast::IIImplItem(_, ref item)) => Some(item.id),
+ _ => None
+ };
+ tcx.extern_const_fns.borrow_mut().insert(def_id,
+ fn_id.unwrap_or(ast::DUMMY_NODE_ID));
+ fn_id
+}
+
+pub fn lookup_const_fn_by_id<'tcx>(tcx: &ty::ctxt<'tcx>, def_id: ast::DefId)
+ -> Option<FnLikeNode<'tcx>>
+{
+ let fn_id = if !ast_util::is_local(def_id) {
+ if let Some(fn_id) = inline_const_fn_from_external_crate(tcx, def_id) {
+ fn_id
+ } else {
+ return None;
+ }
+ } else {
+ def_id.node
+ };
+
+ let fn_like = match FnLikeNode::from_node(tcx.map.get(fn_id)) {
+ Some(fn_like) => fn_like,
+ None => return None
+ };
+
+ match fn_like.kind() {
+ visit::FkItemFn(_, _, _, ast::Constness::Const, _, _) => {
+ Some(fn_like)
+ }
+ visit::FkMethod(_, m, _) => {
+ if m.constness == ast::Constness::Const {
+ Some(fn_like)
+ } else {
+ None
+ }
+ }
+ _ => None
+ }
+}
+
#[derive(Clone, PartialEq)]
-pub enum const_val {
- const_float(f64),
- const_int(i64),
- const_uint(u64),
- const_str(InternedString),
- const_binary(Rc<Vec<u8>>),
- const_bool(bool),
+pub enum ConstVal {
+ Float(f64),
+ Int(i64),
+ Uint(u64),
+ Str(InternedString),
+ Binary(Rc<Vec<u8>>),
+ Bool(bool),
Struct(ast::NodeId),
- Tuple(ast::NodeId)
+ Tuple(ast::NodeId),
}
pub fn const_expr_to_pat(tcx: &ty::ctxt, expr: &Expr, span: Span) -> P<ast::Pat> {
P(ast::Pat { id: expr.id, node: pat, span: span })
}
-pub fn eval_const_expr(tcx: &ty::ctxt, e: &Expr) -> const_val {
+pub fn eval_const_expr(tcx: &ty::ctxt, e: &Expr) -> ConstVal {
match eval_const_expr_partial(tcx, e, None) {
Ok(r) => r,
Err(s) => tcx.sess.span_fatal(s.span, &s.description())
}
}
-pub type EvalResult = Result<const_val, ConstEvalErr>;
-pub type CastResult = Result<const_val, ErrKind>;
+pub type EvalResult = Result<ConstVal, ConstEvalErr>;
+pub type CastResult = Result<ConstVal, ErrKind>;
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum IntTy { I8, I16, I32, I64 }
if oflo {
signal!(e, NegateWithOverflow(a));
} else {
- Ok(const_int(-a))
+ Ok(Int(-a))
}
}
pub fn const_uint_checked_neg<'a>(
a: u64, _e: &'a Expr, _opt_ety: Option<UintTy>) -> EvalResult {
// This always succeeds, and by definition, returns `(!a)+1`.
- Ok(const_uint((!a).wrapping_add(1)))
+ Ok(Uint((!a).wrapping_add(1)))
+}
+
+fn const_uint_not(a: u64, opt_ety: Option<UintTy>) -> ConstVal {
+ let mask = match opt_ety {
+ Some(UintTy::U8) => u8::MAX as u64,
+ Some(UintTy::U16) => u16::MAX as u64,
+ Some(UintTy::U32) => u32::MAX as u64,
+ None | Some(UintTy::U64) => u64::MAX,
+ };
+ Uint(!a & mask)
}
macro_rules! overflow_checking_body {
}
pub_fn_checked_op!{ const_int_checked_add(a: i64, b: i64,.. IntTy) {
- int_arith_body overflowing_add const_int AddiWithOverflow(a, b)
+ int_arith_body overflowing_add Int AddiWithOverflow(a, b)
}}
pub_fn_checked_op!{ const_int_checked_sub(a: i64, b: i64,.. IntTy) {
- int_arith_body overflowing_sub const_int SubiWithOverflow(a, b)
+ int_arith_body overflowing_sub Int SubiWithOverflow(a, b)
}}
pub_fn_checked_op!{ const_int_checked_mul(a: i64, b: i64,.. IntTy) {
- int_arith_body overflowing_mul const_int MuliWithOverflow(a, b)
+ int_arith_body overflowing_mul Int MuliWithOverflow(a, b)
}}
pub fn const_int_checked_div<'a>(
a: i64, b: i64, e: &'a Expr, opt_ety: Option<IntTy>) -> EvalResult {
if b == 0 { signal!(e, DivideByZero); }
let (ret, oflo) = int_arith_body!(a, b, opt_ety, overflowing_div);
- if !oflo { Ok(const_int(ret)) } else { signal!(e, DivideWithOverflow) }
+ if !oflo { Ok(Int(ret)) } else { signal!(e, DivideWithOverflow) }
}
pub fn const_int_checked_rem<'a>(
a: i64, b: i64, e: &'a Expr, opt_ety: Option<IntTy>) -> EvalResult {
if b == 0 { signal!(e, ModuloByZero); }
let (ret, oflo) = int_arith_body!(a, b, opt_ety, overflowing_rem);
- if !oflo { Ok(const_int(ret)) } else { signal!(e, ModuloWithOverflow) }
+ if !oflo { Ok(Int(ret)) } else { signal!(e, ModuloWithOverflow) }
}
pub_fn_checked_op!{ const_int_checked_shl(a: i64, b: i64,.. IntTy) {
- int_shift_body overflowing_shl const_int ShiftLeftWithOverflow
+ int_shift_body overflowing_shl Int ShiftLeftWithOverflow
}}
pub_fn_checked_op!{ const_int_checked_shl_via_uint(a: i64, b: u64,.. IntTy) {
- int_shift_body overflowing_shl const_int ShiftLeftWithOverflow
+ int_shift_body overflowing_shl Int ShiftLeftWithOverflow
}}
pub_fn_checked_op!{ const_int_checked_shr(a: i64, b: i64,.. IntTy) {
- int_shift_body overflowing_shr const_int ShiftRightWithOverflow
+ int_shift_body overflowing_shr Int ShiftRightWithOverflow
}}
pub_fn_checked_op!{ const_int_checked_shr_via_uint(a: i64, b: u64,.. IntTy) {
- int_shift_body overflowing_shr const_int ShiftRightWithOverflow
+ int_shift_body overflowing_shr Int ShiftRightWithOverflow
}}
pub_fn_checked_op!{ const_uint_checked_add(a: u64, b: u64,.. UintTy) {
- uint_arith_body overflowing_add const_uint AdduWithOverflow(a, b)
+ uint_arith_body overflowing_add Uint AdduWithOverflow(a, b)
}}
pub_fn_checked_op!{ const_uint_checked_sub(a: u64, b: u64,.. UintTy) {
- uint_arith_body overflowing_sub const_uint SubuWithOverflow(a, b)
+ uint_arith_body overflowing_sub Uint SubuWithOverflow(a, b)
}}
pub_fn_checked_op!{ const_uint_checked_mul(a: u64, b: u64,.. UintTy) {
- uint_arith_body overflowing_mul const_uint MuluWithOverflow(a, b)
+ uint_arith_body overflowing_mul Uint MuluWithOverflow(a, b)
}}
pub fn const_uint_checked_div<'a>(
a: u64, b: u64, e: &'a Expr, opt_ety: Option<UintTy>) -> EvalResult {
if b == 0 { signal!(e, DivideByZero); }
let (ret, oflo) = uint_arith_body!(a, b, opt_ety, overflowing_div);
- if !oflo { Ok(const_uint(ret)) } else { signal!(e, DivideWithOverflow) }
+ if !oflo { Ok(Uint(ret)) } else { signal!(e, DivideWithOverflow) }
}
pub fn const_uint_checked_rem<'a>(
a: u64, b: u64, e: &'a Expr, opt_ety: Option<UintTy>) -> EvalResult {
if b == 0 { signal!(e, ModuloByZero); }
let (ret, oflo) = uint_arith_body!(a, b, opt_ety, overflowing_rem);
- if !oflo { Ok(const_uint(ret)) } else { signal!(e, ModuloWithOverflow) }
+ if !oflo { Ok(Uint(ret)) } else { signal!(e, ModuloWithOverflow) }
}
pub_fn_checked_op!{ const_uint_checked_shl(a: u64, b: u64,.. UintTy) {
- uint_shift_body overflowing_shl const_uint ShiftLeftWithOverflow
+ uint_shift_body overflowing_shl Uint ShiftLeftWithOverflow
}}
pub_fn_checked_op!{ const_uint_checked_shl_via_int(a: u64, b: i64,.. UintTy) {
- uint_shift_body overflowing_shl const_uint ShiftLeftWithOverflow
+ uint_shift_body overflowing_shl Uint ShiftLeftWithOverflow
}}
pub_fn_checked_op!{ const_uint_checked_shr(a: u64, b: u64,.. UintTy) {
- uint_shift_body overflowing_shr const_uint ShiftRightWithOverflow
+ uint_shift_body overflowing_shr Uint ShiftRightWithOverflow
}}
pub_fn_checked_op!{ const_uint_checked_shr_via_int(a: u64, b: i64,.. UintTy) {
- uint_shift_body overflowing_shr const_uint ShiftRightWithOverflow
+ uint_shift_body overflowing_shr Uint ShiftRightWithOverflow
}}
+// After type checking, `eval_const_expr_partial` should always suffice. The
+// reason for providing `eval_const_expr_with_substs` is to allow
+// trait-associated consts to be evaluated *during* type checking, when the
+// substs for each expression have not been written into `tcx` yet.
pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
e: &Expr,
ty_hint: Option<Ty<'tcx>>) -> EvalResult {
- fn fromb(b: bool) -> const_val { const_int(b as i64) }
+ eval_const_expr_with_substs(tcx, e, ty_hint, |id| {
+ ty::node_id_item_substs(tcx, id).substs
+ })
+}
+
+pub fn eval_const_expr_with_substs<'tcx, S>(tcx: &ty::ctxt<'tcx>,
+ e: &Expr,
+ ty_hint: Option<Ty<'tcx>>,
+ get_substs: S) -> EvalResult
+ where S: Fn(ast::NodeId) -> subst::Substs<'tcx> {
+ fn fromb(b: bool) -> ConstVal { Int(b as i64) }
let ety = ty_hint.or_else(|| ty::expr_ty_opt(tcx, e));
// bindings so that isize/usize is mapped to a type with an
// inherently known bitwidth.
let expr_int_type = ety.and_then(|ty| {
- if let ty::ty_int(t) = ty.sty {
+ if let ty::TyInt(t) = ty.sty {
Some(IntTy::from(tcx, t)) } else { None }
});
let expr_uint_type = ety.and_then(|ty| {
- if let ty::ty_uint(t) = ty.sty {
+ if let ty::TyUint(t) = ty.sty {
Some(UintTy::from(tcx, t)) } else { None }
});
let result = match e.node {
ast::ExprUnary(ast::UnNeg, ref inner) => {
match try!(eval_const_expr_partial(tcx, &**inner, ety)) {
- const_float(f) => const_float(-f),
- const_int(n) => try!(const_int_checked_neg(n, e, expr_int_type)),
- const_uint(i) => {
+ Float(f) => Float(-f),
+ Int(n) => try!(const_int_checked_neg(n, e, expr_int_type)),
+ Uint(i) => {
if !tcx.sess.features.borrow().negate_unsigned {
feature_gate::emit_feature_err(
&tcx.sess.parse_sess.span_diagnostic,
}
try!(const_uint_checked_neg(i, e, expr_uint_type))
}
- const_str(_) => signal!(e, NegateOnString),
- const_bool(_) => signal!(e, NegateOnBoolean),
- const_binary(_) => signal!(e, NegateOnBinary),
- const_val::Tuple(_) => signal!(e, NegateOnTuple),
- const_val::Struct(..) => signal!(e, NegateOnStruct),
+ Str(_) => signal!(e, NegateOnString),
+ Bool(_) => signal!(e, NegateOnBoolean),
+ Binary(_) => signal!(e, NegateOnBinary),
+ Tuple(_) => signal!(e, NegateOnTuple),
+ Struct(..) => signal!(e, NegateOnStruct),
}
}
ast::ExprUnary(ast::UnNot, ref inner) => {
match try!(eval_const_expr_partial(tcx, &**inner, ety)) {
- const_int(i) => const_int(!i),
- const_uint(i) => const_uint(!i),
- const_bool(b) => const_bool(!b),
- const_str(_) => signal!(e, NotOnString),
- const_float(_) => signal!(e, NotOnFloat),
- const_binary(_) => signal!(e, NotOnBinary),
- const_val::Tuple(_) => signal!(e, NotOnTuple),
- const_val::Struct(..) => signal!(e, NotOnStruct),
+ Int(i) => Int(!i),
+ Uint(i) => const_uint_not(i, expr_uint_type),
+ Bool(b) => Bool(!b),
+ Str(_) => signal!(e, NotOnString),
+ Float(_) => signal!(e, NotOnFloat),
+ Binary(_) => signal!(e, NotOnBinary),
+ Tuple(_) => signal!(e, NotOnTuple),
+ Struct(..) => signal!(e, NotOnStruct),
}
}
ast::ExprBinary(op, ref a, ref b) => {
};
match (try!(eval_const_expr_partial(tcx, &**a, ety)),
try!(eval_const_expr_partial(tcx, &**b, b_ty))) {
- (const_float(a), const_float(b)) => {
+ (Float(a), Float(b)) => {
match op.node {
- ast::BiAdd => const_float(a + b),
- ast::BiSub => const_float(a - b),
- ast::BiMul => const_float(a * b),
- ast::BiDiv => const_float(a / b),
- ast::BiRem => const_float(a % b),
+ ast::BiAdd => Float(a + b),
+ ast::BiSub => Float(a - b),
+ ast::BiMul => Float(a * b),
+ ast::BiDiv => Float(a / b),
+ ast::BiRem => Float(a % b),
ast::BiEq => fromb(a == b),
ast::BiLt => fromb(a < b),
ast::BiLe => fromb(a <= b),
_ => signal!(e, InvalidOpForFloats(op.node))
}
}
- (const_int(a), const_int(b)) => {
+ (Int(a), Int(b)) => {
match op.node {
ast::BiAdd => try!(const_int_checked_add(a,b,e,expr_int_type)),
ast::BiSub => try!(const_int_checked_sub(a,b,e,expr_int_type)),
ast::BiMul => try!(const_int_checked_mul(a,b,e,expr_int_type)),
ast::BiDiv => try!(const_int_checked_div(a,b,e,expr_int_type)),
ast::BiRem => try!(const_int_checked_rem(a,b,e,expr_int_type)),
- ast::BiAnd | ast::BiBitAnd => const_int(a & b),
- ast::BiOr | ast::BiBitOr => const_int(a | b),
- ast::BiBitXor => const_int(a ^ b),
+ ast::BiAnd | ast::BiBitAnd => Int(a & b),
+ ast::BiOr | ast::BiBitOr => Int(a | b),
+ ast::BiBitXor => Int(a ^ b),
ast::BiShl => try!(const_int_checked_shl(a,b,e,expr_int_type)),
ast::BiShr => try!(const_int_checked_shr(a,b,e,expr_int_type)),
ast::BiEq => fromb(a == b),
ast::BiGt => fromb(a > b)
}
}
- (const_uint(a), const_uint(b)) => {
+ (Uint(a), Uint(b)) => {
match op.node {
ast::BiAdd => try!(const_uint_checked_add(a,b,e,expr_uint_type)),
ast::BiSub => try!(const_uint_checked_sub(a,b,e,expr_uint_type)),
ast::BiMul => try!(const_uint_checked_mul(a,b,e,expr_uint_type)),
ast::BiDiv => try!(const_uint_checked_div(a,b,e,expr_uint_type)),
ast::BiRem => try!(const_uint_checked_rem(a,b,e,expr_uint_type)),
- ast::BiAnd | ast::BiBitAnd => const_uint(a & b),
- ast::BiOr | ast::BiBitOr => const_uint(a | b),
- ast::BiBitXor => const_uint(a ^ b),
+ ast::BiAnd | ast::BiBitAnd => Uint(a & b),
+ ast::BiOr | ast::BiBitOr => Uint(a | b),
+ ast::BiBitXor => Uint(a ^ b),
ast::BiShl => try!(const_uint_checked_shl(a,b,e,expr_uint_type)),
ast::BiShr => try!(const_uint_checked_shr(a,b,e,expr_uint_type)),
ast::BiEq => fromb(a == b),
}
}
// shifts can have any integral type as their rhs
- (const_int(a), const_uint(b)) => {
+ (Int(a), Uint(b)) => {
match op.node {
ast::BiShl => try!(const_int_checked_shl_via_uint(a,b,e,expr_int_type)),
ast::BiShr => try!(const_int_checked_shr_via_uint(a,b,e,expr_int_type)),
_ => signal!(e, InvalidOpForIntUint(op.node)),
}
}
- (const_uint(a), const_int(b)) => {
+ (Uint(a), Int(b)) => {
match op.node {
ast::BiShl => try!(const_uint_checked_shl_via_int(a,b,e,expr_uint_type)),
ast::BiShr => try!(const_uint_checked_shr_via_int(a,b,e,expr_uint_type)),
_ => signal!(e, InvalidOpForUintInt(op.node)),
}
}
- (const_bool(a), const_bool(b)) => {
- const_bool(match op.node {
+ (Bool(a), Bool(b)) => {
+ Bool(match op.node {
ast::BiAnd => a && b,
ast::BiOr => a || b,
ast::BiBitXor => a ^ b,
def::FromTrait(trait_id) => match tcx.map.find(def_id.node) {
Some(ast_map::NodeTraitItem(ti)) => match ti.node {
ast::ConstTraitItem(ref ty, _) => {
- (resolve_trait_associated_const(tcx, ti,
- trait_id, e.id),
+ let substs = get_substs(e.id);
+ (resolve_trait_associated_const(tcx,
+ ti,
+ trait_id,
+ substs),
Some(&**ty))
}
_ => (None, None)
ast::ExprBlock(ref block) => {
match block.expr {
Some(ref expr) => try!(eval_const_expr_partial(tcx, &**expr, ety)),
- None => const_int(0)
+ None => Int(0)
}
}
- ast::ExprTup(_) => {
- const_val::Tuple(e.id)
- }
- ast::ExprStruct(..) => {
- const_val::Struct(e.id)
- }
+ ast::ExprTup(_) => Tuple(e.id),
+ ast::ExprStruct(..) => Struct(e.id),
ast::ExprTupField(ref base, index) => {
if let Ok(c) = eval_const_expr_partial(tcx, base, None) {
- if let const_val::Tuple(tup_id) = c {
+ if let Tuple(tup_id) = c {
if let ast::ExprTup(ref fields) = tcx.map.expect_expr(tup_id).node {
if index.node < fields.len() {
return eval_const_expr_partial(tcx, &fields[index.node], None)
ast::ExprField(ref base, field_name) => {
// Get the base expression if it is a struct and it is constant
if let Ok(c) = eval_const_expr_partial(tcx, base, None) {
- if let const_val::Struct(struct_id) = c {
+ if let Struct(struct_id) = c {
if let ast::ExprStruct(_, ref fields, _) = tcx.map.expect_expr(struct_id).node {
// Check that the given field exists and evaluate it
if let Some(f) = fields.iter().find(|f| f.ident.node.as_str()
fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>,
ti: &'tcx ast::TraitItem,
trait_id: ast::DefId,
- ref_id: ast::NodeId)
+ rcvr_substs: subst::Substs<'tcx>)
-> Option<&'tcx Expr>
{
- let rcvr_substs = ty::node_id_item_substs(tcx, ref_id).substs;
let subst::SeparateVecsPerParamSpace {
types: rcvr_type,
selfs: rcvr_self,
rcvr_self,
Vec::new()));
let trait_substs = tcx.mk_substs(trait_substs);
- debug!("resolve_trait_associated_const: trait_substs={}",
- trait_substs.repr(tcx));
+ debug!("resolve_trait_associated_const: trait_substs={:?}",
+ trait_substs);
let trait_ref = ty::Binder(ty::TraitRef { def_id: trait_id,
substs: trait_substs });
}
Err(e) => {
tcx.sess.span_bug(ti.span,
- &format!("Encountered error `{}` when trying \
+ &format!("Encountered error `{:?}` when trying \
to select an implementation for \
constant trait item reference.",
- e.repr(tcx)))
+ e))
}
};
}
}
-fn cast_const<'tcx>(tcx: &ty::ctxt<'tcx>, val: const_val, ty: Ty) -> CastResult {
+fn cast_const<'tcx>(tcx: &ty::ctxt<'tcx>, val: ConstVal, ty: Ty) -> CastResult {
macro_rules! convert_val {
($intermediate_ty:ty, $const_type:ident, $target_ty:ty) => {
match val {
- const_bool(b) => Ok($const_type(b as $intermediate_ty as $target_ty)),
- const_uint(u) => Ok($const_type(u as $intermediate_ty as $target_ty)),
- const_int(i) => Ok($const_type(i as $intermediate_ty as $target_ty)),
- const_float(f) => Ok($const_type(f as $intermediate_ty as $target_ty)),
+ Bool(b) => Ok($const_type(b as u64 as $intermediate_ty as $target_ty)),
+ Uint(u) => Ok($const_type(u as $intermediate_ty as $target_ty)),
+ Int(i) => Ok($const_type(i as $intermediate_ty as $target_ty)),
+ Float(f) => Ok($const_type(f as $intermediate_ty as $target_ty)),
_ => Err(ErrKind::CannotCastTo(stringify!($const_type))),
}
}
// Issue #23890: If isize/usize, then dispatch to appropriate target representation type
match (&ty.sty, tcx.sess.target.int_type, tcx.sess.target.uint_type) {
- (&ty::ty_int(ast::TyIs), ast::TyI32, _) => return convert_val!(i32, const_int, i64),
- (&ty::ty_int(ast::TyIs), ast::TyI64, _) => return convert_val!(i64, const_int, i64),
- (&ty::ty_int(ast::TyIs), _, _) => panic!("unexpected target.int_type"),
+ (&ty::TyInt(ast::TyIs), ast::TyI32, _) => return convert_val!(i32, Int, i64),
+ (&ty::TyInt(ast::TyIs), ast::TyI64, _) => return convert_val!(i64, Int, i64),
+ (&ty::TyInt(ast::TyIs), _, _) => panic!("unexpected target.int_type"),
- (&ty::ty_uint(ast::TyUs), _, ast::TyU32) => return convert_val!(u32, const_uint, u64),
- (&ty::ty_uint(ast::TyUs), _, ast::TyU64) => return convert_val!(u64, const_uint, u64),
- (&ty::ty_uint(ast::TyUs), _, _) => panic!("unexpected target.uint_type"),
+ (&ty::TyUint(ast::TyUs), _, ast::TyU32) => return convert_val!(u32, Uint, u64),
+ (&ty::TyUint(ast::TyUs), _, ast::TyU64) => return convert_val!(u64, Uint, u64),
+ (&ty::TyUint(ast::TyUs), _, _) => panic!("unexpected target.uint_type"),
_ => {}
}
match ty.sty {
- ty::ty_int(ast::TyIs) => unreachable!(),
- ty::ty_uint(ast::TyUs) => unreachable!(),
+ ty::TyInt(ast::TyIs) => unreachable!(),
+ ty::TyUint(ast::TyUs) => unreachable!(),
- ty::ty_int(ast::TyI8) => convert_val!(i8, const_int, i64),
- ty::ty_int(ast::TyI16) => convert_val!(i16, const_int, i64),
- ty::ty_int(ast::TyI32) => convert_val!(i32, const_int, i64),
- ty::ty_int(ast::TyI64) => convert_val!(i64, const_int, i64),
+ ty::TyInt(ast::TyI8) => convert_val!(i8, Int, i64),
+ ty::TyInt(ast::TyI16) => convert_val!(i16, Int, i64),
+ ty::TyInt(ast::TyI32) => convert_val!(i32, Int, i64),
+ ty::TyInt(ast::TyI64) => convert_val!(i64, Int, i64),
- ty::ty_uint(ast::TyU8) => convert_val!(u8, const_uint, u64),
- ty::ty_uint(ast::TyU16) => convert_val!(u16, const_uint, u64),
- ty::ty_uint(ast::TyU32) => convert_val!(u32, const_uint, u64),
- ty::ty_uint(ast::TyU64) => convert_val!(u64, const_uint, u64),
+ ty::TyUint(ast::TyU8) => convert_val!(u8, Uint, u64),
+ ty::TyUint(ast::TyU16) => convert_val!(u16, Uint, u64),
+ ty::TyUint(ast::TyU32) => convert_val!(u32, Uint, u64),
+ ty::TyUint(ast::TyU64) => convert_val!(u64, Uint, u64),
- ty::ty_float(ast::TyF32) => convert_val!(f32, const_float, f64),
- ty::ty_float(ast::TyF64) => convert_val!(f64, const_float, f64),
+ ty::TyFloat(ast::TyF32) => convert_val!(f32, Float, f64),
+ ty::TyFloat(ast::TyF64) => convert_val!(f64, Float, f64),
_ => Err(ErrKind::CannotCast),
}
}
-fn lit_to_const(lit: &ast::Lit, ty_hint: Option<Ty>) -> const_val {
+fn lit_to_const(lit: &ast::Lit, ty_hint: Option<Ty>) -> ConstVal {
match lit.node {
- ast::LitStr(ref s, _) => const_str((*s).clone()),
+ ast::LitStr(ref s, _) => Str((*s).clone()),
ast::LitBinary(ref data) => {
- const_binary(data.clone())
+ Binary(data.clone())
}
- ast::LitByte(n) => const_uint(n as u64),
- ast::LitChar(n) => const_uint(n as u64),
- ast::LitInt(n, ast::SignedIntLit(_, ast::Plus)) => const_int(n as i64),
+ ast::LitByte(n) => Uint(n as u64),
+ ast::LitChar(n) => Uint(n as u64),
+ ast::LitInt(n, ast::SignedIntLit(_, ast::Plus)) => Int(n as i64),
ast::LitInt(n, ast::UnsuffixedIntLit(ast::Plus)) => {
match ty_hint.map(|ty| &ty.sty) {
- Some(&ty::ty_uint(_)) => const_uint(n),
- _ => const_int(n as i64)
+ Some(&ty::TyUint(_)) => Uint(n),
+ _ => Int(n as i64)
}
}
ast::LitInt(n, ast::SignedIntLit(_, ast::Minus)) |
- ast::LitInt(n, ast::UnsuffixedIntLit(ast::Minus)) => const_int(-(n as i64)),
- ast::LitInt(n, ast::UnsignedIntLit(_)) => const_uint(n),
+ ast::LitInt(n, ast::UnsuffixedIntLit(ast::Minus)) => Int(-(n as i64)),
+ ast::LitInt(n, ast::UnsignedIntLit(_)) => Uint(n),
ast::LitFloat(ref n, _) |
ast::LitFloatUnsuffixed(ref n) => {
- const_float(n.parse::<f64>().unwrap() as f64)
+ Float(n.parse::<f64>().unwrap() as f64)
}
- ast::LitBool(b) => const_bool(b)
+ ast::LitBool(b) => Bool(b)
}
}
-pub fn compare_const_vals(a: &const_val, b: &const_val) -> Option<Ordering> {
+pub fn compare_const_vals(a: &ConstVal, b: &ConstVal) -> Option<Ordering> {
Some(match (a, b) {
- (&const_int(a), &const_int(b)) => a.cmp(&b),
- (&const_uint(a), &const_uint(b)) => a.cmp(&b),
- (&const_float(a), &const_float(b)) => {
+ (&Int(a), &Int(b)) => a.cmp(&b),
+ (&Uint(a), &Uint(b)) => a.cmp(&b),
+ (&Float(a), &Float(b)) => {
// This is pretty bad but it is the existing behavior.
if a == b {
Ordering::Equal
Ordering::Greater
}
}
- (&const_str(ref a), &const_str(ref b)) => a.cmp(b),
- (&const_bool(a), &const_bool(b)) => a.cmp(&b),
- (&const_binary(ref a), &const_binary(ref b)) => a.cmp(b),
+ (&Str(ref a), &Str(ref b)) => a.cmp(b),
+ (&Bool(a), &Bool(b)) => a.cmp(&b),
+ (&Binary(ref a), &Binary(ref b)) => a.cmp(b),
_ => return None
})
}
-pub fn compare_lit_exprs<'tcx>(tcx: &ty::ctxt<'tcx>,
- a: &Expr,
- b: &Expr,
- ty_hint: Option<Ty<'tcx>>)
- -> Option<Ordering> {
- let a = match eval_const_expr_partial(tcx, a, ty_hint) {
+pub fn compare_lit_exprs<'tcx, S>(tcx: &ty::ctxt<'tcx>,
+ a: &Expr,
+ b: &Expr,
+ ty_hint: Option<Ty<'tcx>>,
+ get_substs: S) -> Option<Ordering>
+ where S: Fn(ast::NodeId) -> subst::Substs<'tcx> {
+ let a = match eval_const_expr_with_substs(tcx, a, ty_hint,
+ |id| {get_substs(id)}) {
Ok(a) => a,
Err(e) => {
tcx.sess.span_err(a.span, &e.description());
return None;
}
};
- let b = match eval_const_expr_partial(tcx, b, ty_hint) {
+ let b = match eval_const_expr_with_substs(tcx, b, ty_hint, get_substs) {
Ok(b) => b,
Err(e) => {
tcx.sess.span_err(b.span, &e.description());
op: &Op) -> bool {
assert_eq!(out_vec.len(), in_vec.len());
let mut changed = false;
- for (out_elt, in_elt) in out_vec.iter_mut().zip(in_vec.iter()) {
+ for (out_elt, in_elt) in out_vec.iter_mut().zip(in_vec) {
let old_val = *out_elt;
let new_val = op.join(old_val, *in_elt);
*out_elt = new_val;
// closely. The idea is that all reachable symbols are live, codes called
// from live codes are live, and everything else is dead.
+use ast_map;
use middle::{def, pat_util, privacy, ty};
use lint;
use util::nodemap::NodeSet;
use std::collections::HashSet;
-use syntax::{ast, ast_map, codemap};
+use syntax::{ast, codemap};
use syntax::ast_util::{local_def, is_local};
use syntax::attr::{self, AttrMetaMethods};
use syntax::visit::{self, Visitor};
struct_has_extern_repr: bool,
ignore_non_const_paths: bool,
inherited_pub_visibility: bool,
+ ignore_variant_stack: Vec<ast::NodeId>,
}
impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
struct_has_extern_repr: false,
ignore_non_const_paths: false,
inherited_pub_visibility: false,
+ ignore_variant_stack: vec![],
}
}
def::DefPrimTy(_) => (),
def::DefVariant(enum_id, variant_id, _) => {
self.check_def_id(enum_id);
- self.check_def_id(variant_id);
+ if !self.ignore_variant_stack.contains(&variant_id.node) {
+ self.check_def_id(variant_id);
+ }
}
_ => {
self.check_def_id(def.def_id());
fn handle_field_access(&mut self, lhs: &ast::Expr, name: ast::Name) {
match ty::expr_ty_adjusted(self.tcx, lhs).sty {
- ty::ty_struct(id, _) => {
+ ty::TyStruct(id, _) => {
let fields = ty::lookup_struct_fields(self.tcx, id);
let field_id = fields.iter()
.find(|field| field.name == name).unwrap().id;
fn handle_tup_field_access(&mut self, lhs: &ast::Expr, idx: usize) {
match ty::expr_ty_adjusted(self.tcx, lhs).sty {
- ty::ty_struct(id, _) => {
+ ty::TyStruct(id, _) => {
let fields = ty::lookup_struct_fields(self.tcx, id);
let field_id = fields[idx].id;
self.live_symbols.insert(field_id.node);
};
let fields = ty::lookup_struct_fields(self.tcx, id);
for pat in pats {
+ if let ast::PatWild(ast::PatWildSingle) = pat.node.pat.node {
+ continue;
+ }
let field_id = fields.iter()
.find(|field| field.name == pat.node.ident.name).unwrap().id;
self.live_symbols.insert(field_id.node);
visit::walk_expr(self, expr);
}
+ fn visit_arm(&mut self, arm: &ast::Arm) {
+ if arm.pats.len() == 1 {
+ let pat = &*arm.pats[0];
+ let variants = pat_util::necessary_variants(&self.tcx.def_map, pat);
+
+ // Inside the body, ignore constructions of variants
+ // necessary for the pattern to match. Those construction sites
+ // can't be reached unless the variant is constructed elsewhere.
+ let len = self.ignore_variant_stack.len();
+ self.ignore_variant_stack.push_all(&*variants);
+ visit::walk_arm(self, arm);
+ self.ignore_variant_stack.truncate(len);
+ } else {
+ visit::walk_arm(self, arm);
+ }
+ }
+
fn visit_pat(&mut self, pat: &ast::Pat) {
let def_map = &self.tcx.def_map;
match pat.node {
worklist.push(*id);
}
for id in reachable_symbols {
+ // Reachable variants can be dead, because we warn about
+ // variants never constructed, not variants never used.
+ if let Some(ast_map::NodeVariant(..)) = tcx.map.find(*id) {
+ continue;
+ }
worklist.push(*id);
}
match self.tcx.inherent_impls.borrow().get(&local_def(id)) {
None => (),
Some(impl_list) => {
- for impl_did in &**impl_list {
- for item_did in &*impl_items.get(impl_did).unwrap() {
+ for impl_did in impl_list.iter() {
+ for item_did in impl_items.get(impl_did).unwrap().iter() {
if self.live_symbols.contains(&item_did.def_id()
.node) {
return true;
pub fn calculate(tcx: &ty::ctxt) {
let mut fmts = tcx.dependency_formats.borrow_mut();
- for &ty in &*tcx.sess.crate_types.borrow() {
+ for &ty in tcx.sess.crate_types.borrow().iter() {
fmts.insert(ty, calculate_type(&tcx.sess, ty));
}
tcx.sess.abort_if_errors();
use middle::def;
use middle::ty::{self, Ty};
use middle::ty::MethodCall;
-use util::ppaux;
use syntax::ast;
use syntax::codemap::Span;
fn type_is_unsafe_function(ty: Ty) -> bool {
match ty.sty {
- ty::ty_bare_fn(_, ref f) => f.unsafety == ast::Unsafety::Unsafe,
+ ty::TyBareFn(_, ref f) => f.unsafety == ast::Unsafety::Unsafe,
_ => false,
}
}
ast::ExprIndex(ref base, _) => ty::node_id_to_type(self.tcx, base.id),
_ => return
};
- debug!("effect: checking index with base type {}",
- ppaux::ty_to_string(self.tcx, base_type));
+ debug!("effect: checking index with base type {:?}",
+ base_type);
match base_type.sty {
- ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => if ty::ty_str == ty.sty {
+ ty::TyBox(ty) | ty::TyRef(_, ty::mt{ty, ..}) => if ty::TyStr == ty.sty {
span_err!(self.tcx.sess, e.span, E0134,
"modification of string types is not allowed");
},
- ty::ty_str => {
+ ty::TyStr => {
span_err!(self.tcx.sess, e.span, E0135,
"modification of string types is not allowed");
}
block: &'v ast::Block, span: Span, _: ast::NodeId) {
let (is_item_fn, is_unsafe_fn) = match fn_kind {
- visit::FkItemFn(_, _, fn_style, _, _) =>
- (true, fn_style == ast::Unsafety::Unsafe),
+ visit::FkItemFn(_, _, unsafety, _, _, _) =>
+ (true, unsafety == ast::Unsafety::Unsafe),
visit::FkMethod(_, sig, _) =>
(true, sig.unsafety == ast::Unsafety::Unsafe),
_ => (false, false),
ast::ExprMethodCall(_, _, _) => {
let method_call = MethodCall::expr(expr.id);
let base_type = self.tcx.method_map.borrow().get(&method_call).unwrap().ty;
- debug!("effect: method call case, base type is {}",
- ppaux::ty_to_string(self.tcx, base_type));
+ debug!("effect: method call case, base type is {:?}",
+ base_type);
if type_is_unsafe_function(base_type) {
self.require_unsafe(expr.span,
"invocation of unsafe method")
}
ast::ExprCall(ref base, _) => {
let base_type = ty::node_id_to_type(self.tcx, base.id);
- debug!("effect: call case, base type is {}",
- ppaux::ty_to_string(self.tcx, base_type));
+ debug!("effect: call case, base type is {:?}",
+ base_type);
if type_is_unsafe_function(base_type) {
self.require_unsafe(expr.span, "call to unsafe function")
}
}
ast::ExprUnary(ast::UnDeref, ref base) => {
let base_type = ty::node_id_to_type(self.tcx, base.id);
- debug!("effect: unary case, base type is {}",
- ppaux::ty_to_string(self.tcx, base_type));
- if let ty::ty_ptr(_) = base_type.sty {
- self.require_unsafe(expr.span, "dereference of unsafe pointer")
+ debug!("effect: unary case, base type is {:?}",
+ base_type);
+ if let ty::TyRawPtr(_) = base_type.sty {
+ self.require_unsafe(expr.span, "dereference of raw pointer")
}
}
ast::ExprAssign(ref base, _) | ast::ExprAssignOp(_, ref base, _) => {
// except according to those terms.
+use ast_map;
use session::{config, Session};
use syntax::ast::{Name, NodeId, Item, ItemFn};
-use syntax::ast_map;
use syntax::attr;
use syntax::codemap::Span;
use syntax::parse::token;
use middle::ty::{MethodCall, MethodObject, MethodTraitObject};
use middle::ty::{MethodOrigin, MethodParam, MethodTypeParam};
use middle::ty::{MethodStatic, MethodStaticClosure};
-use util::ppaux::Repr;
use syntax::{ast, ast_util};
use syntax::ptr::P;
impl OverloadedCallType {
fn from_trait_id(tcx: &ty::ctxt, trait_id: ast::DefId)
-> OverloadedCallType {
- for &(maybe_function_trait, overloaded_call_type) in [
+ for &(maybe_function_trait, overloaded_call_type) in &[
(tcx.lang_items.fn_once_trait(), FnOnceOverloadedCall),
(tcx.lang_items.fn_mut_trait(), FnMutOverloadedCall),
(tcx.lang_items.fn_trait(), FnOverloadedCall)
- ].iter() {
+ ] {
match maybe_function_trait {
Some(function_trait) if function_trait == trait_id => {
return overloaded_call_type
consume_id: ast::NodeId,
consume_span: Span,
cmt: mc::cmt<'tcx>) {
- debug!("delegate_consume(consume_id={}, cmt={})",
- consume_id, cmt.repr(self.tcx()));
+ debug!("delegate_consume(consume_id={}, cmt={:?})",
+ consume_id, cmt);
let mode = copy_or_move(self.typer, &cmt, DirectRefMove);
self.delegate.consume(consume_id, consume_span, cmt, mode);
}
pub fn consume_expr(&mut self, expr: &ast::Expr) {
- debug!("consume_expr(expr={})", expr.repr(self.tcx()));
+ debug!("consume_expr(expr={:?})", expr);
let cmt = return_if_err!(self.mc.cat_expr(expr));
self.delegate_consume(expr.id, expr.span, cmt);
r: ty::Region,
bk: ty::BorrowKind,
cause: LoanCause) {
- debug!("borrow_expr(expr={}, r={}, bk={})",
- expr.repr(self.tcx()), r.repr(self.tcx()), bk.repr(self.tcx()));
+ debug!("borrow_expr(expr={:?}, r={:?}, bk={:?})",
+ expr, r, bk);
let cmt = return_if_err!(self.mc.cat_expr(expr));
self.delegate.borrow(expr.id, expr.span, cmt, r, bk, cause);
}
pub fn walk_expr(&mut self, expr: &ast::Expr) {
- debug!("walk_expr(expr={})", expr.repr(self.tcx()));
+ debug!("walk_expr(expr={:?})", expr);
self.walk_adjustment(expr);
fn walk_callee(&mut self, call: &ast::Expr, callee: &ast::Expr) {
let callee_ty = return_if_err!(self.typer.expr_ty_adjusted(callee));
- debug!("walk_callee: callee={} callee_ty={}",
- callee.repr(self.tcx()), callee_ty.repr(self.tcx()));
+ debug!("walk_callee: callee={:?} callee_ty={:?}",
+ callee, callee_ty);
let call_scope = region::CodeExtent::from_node_id(call.id);
match callee_ty.sty {
- ty::ty_bare_fn(..) => {
+ ty::TyBareFn(..) => {
self.consume_expr(callee);
}
- ty::ty_err => { }
+ ty::TyError => { }
_ => {
let overloaded_call_type =
match self.typer.node_method_origin(MethodCall::expr(call.id)) {
None => {
self.tcx().sess.span_bug(
callee.span,
- &format!("unexpected callee type {}", callee_ty.repr(self.tcx())))
+ &format!("unexpected callee type {}", callee_ty))
}
};
match overloaded_call_type {
// Select just those fields of the `with`
// expression that will actually be used
let with_fields = match with_cmt.ty.sty {
- ty::ty_struct(did, substs) => {
+ ty::TyStruct(did, substs) => {
ty::struct_fields(self.tcx(), did, substs)
}
_ => {
fn walk_autoderefs(&mut self,
expr: &ast::Expr,
autoderefs: usize) {
- debug!("walk_autoderefs expr={} autoderefs={}", expr.repr(self.tcx()), autoderefs);
+ debug!("walk_autoderefs expr={:?} autoderefs={}", expr, autoderefs);
for i in 0..autoderefs {
let deref_id = ty::MethodCall::autoderef(expr.id, i as u32);
let self_ty = ty::no_late_bound_regions(self.tcx(), &self_ty).unwrap();
let (m, r) = match self_ty.sty {
- ty::ty_rptr(r, ref m) => (m.mutbl, r),
+ ty::TyRef(r, ref m) => (m.mutbl, r),
_ => self.tcx().sess.span_bug(expr.span,
- &format!("bad overloaded deref type {}",
- method_ty.repr(self.tcx())))
+ &format!("bad overloaded deref type {:?}",
+ method_ty))
};
let bk = ty::BorrowKind::from_mutbl(m);
self.delegate.borrow(expr.id, expr.span, cmt,
fn walk_autoderefref(&mut self,
expr: &ast::Expr,
adj: &ty::AutoDerefRef<'tcx>) {
- debug!("walk_autoderefref expr={} adj={}",
- expr.repr(self.tcx()),
- adj.repr(self.tcx()));
+ debug!("walk_autoderefref expr={:?} adj={:?}",
+ expr,
+ adj);
self.walk_autoderefs(expr, adj.autoderefs);
opt_autoref: Option<ty::AutoRef<'tcx>>)
-> mc::cmt<'tcx>
{
- debug!("walk_autoref(expr.id={} cmt_derefd={} opt_autoref={:?})",
+ debug!("walk_autoref(expr.id={} cmt_derefd={:?} opt_autoref={:?})",
expr.id,
- cmt_base.repr(self.tcx()),
+ cmt_base,
opt_autoref);
let cmt_base_ty = cmt_base.ty;
}
ty::AutoUnsafe(m) => {
- debug!("walk_autoref: expr.id={} cmt_base={}",
+ debug!("walk_autoref: expr.id={} cmt_base={:?}",
expr.id,
- cmt_base.repr(self.tcx()));
+ cmt_base);
// Converting from a &T to *T (or &mut T to *mut T) is
// treated as borrowing it for the enclosing temporary
cmt_discr: mc::cmt<'tcx>,
pat: &ast::Pat,
mode: &mut TrackMatchMode) {
- debug!("determine_pat_move_mode cmt_discr={} pat={}", cmt_discr.repr(self.tcx()),
- pat.repr(self.tcx()));
+ debug!("determine_pat_move_mode cmt_discr={:?} pat={:?}", cmt_discr,
+ pat);
return_if_err!(self.mc.cat_pattern(cmt_discr, pat, |_mc, cmt_pat, pat| {
let tcx = self.tcx();
let def_map = &self.tcx().def_map;
cmt_discr: mc::cmt<'tcx>,
pat: &ast::Pat,
match_mode: MatchMode) {
- debug!("walk_pat cmt_discr={} pat={}", cmt_discr.repr(self.tcx()),
- pat.repr(self.tcx()));
+ debug!("walk_pat cmt_discr={:?} pat={:?}", cmt_discr,
+ pat);
let mc = &self.mc;
let typer = self.typer;
if pat_util::pat_is_binding(def_map, pat) {
let tcx = typer.tcx();
- debug!("binding cmt_pat={} pat={} match_mode={:?}",
- cmt_pat.repr(tcx),
- pat.repr(tcx),
+ debug!("binding cmt_pat={:?} pat={:?} match_mode={:?}",
+ cmt_pat,
+ pat,
match_mode);
// pat_ty: the type of the binding being produced.
mc.cat_downcast(pat, cmt_pat, cmt_pat_ty, variant_did)
};
- debug!("variant downcast_cmt={} pat={}",
- downcast_cmt.repr(tcx),
- pat.repr(tcx));
+ debug!("variant downcast_cmt={:?} pat={:?}",
+ downcast_cmt,
+ pat);
delegate.matched_pat(pat, downcast_cmt, match_mode);
}
// namespace; we encounter the former on
// e.g. patterns for unit structs).
- debug!("struct cmt_pat={} pat={}",
- cmt_pat.repr(tcx),
- pat.repr(tcx));
+ debug!("struct cmt_pat={:?} pat={:?}",
+ cmt_pat,
+ pat);
delegate.matched_pat(pat, cmt_pat, match_mode);
}
// pattern.
if !tcx.sess.has_errors() {
- let msg = format!("Pattern has unexpected type: {:?} and type {}",
+ let msg = format!("Pattern has unexpected type: {:?} and type {:?}",
def,
- cmt_pat.ty.repr(tcx));
+ cmt_pat.ty);
tcx.sess.span_bug(pat.span, &msg)
}
}
// reported.
if !tcx.sess.has_errors() {
- let msg = format!("Pattern has unexpected def: {:?} and type {}",
+ let msg = format!("Pattern has unexpected def: {:?} and type {:?}",
def,
- cmt_pat.ty.repr(tcx));
+ cmt_pat.ty);
tcx.sess.span_bug(pat.span, &msg[..])
}
}
}
fn walk_captures(&mut self, closure_expr: &ast::Expr) {
- debug!("walk_captures({})", closure_expr.repr(self.tcx()));
+ debug!("walk_captures({:?})", closure_expr);
ty::with_freevars(self.tcx(), closure_expr.id, |freevars| {
for freevar in freevars {
-> Option<SimplifiedType>
{
match ty.sty {
- ty::ty_bool => Some(BoolSimplifiedType),
- ty::ty_char => Some(CharSimplifiedType),
- ty::ty_int(int_type) => Some(IntSimplifiedType(int_type)),
- ty::ty_uint(uint_type) => Some(UintSimplifiedType(uint_type)),
- ty::ty_float(float_type) => Some(FloatSimplifiedType(float_type)),
- ty::ty_enum(def_id, _) => Some(EnumSimplifiedType(def_id)),
- ty::ty_str => Some(StrSimplifiedType),
- ty::ty_vec(..) => Some(VecSimplifiedType),
- ty::ty_ptr(_) => Some(PtrSimplifiedType),
- ty::ty_trait(ref trait_info) => {
+ ty::TyBool => Some(BoolSimplifiedType),
+ ty::TyChar => Some(CharSimplifiedType),
+ ty::TyInt(int_type) => Some(IntSimplifiedType(int_type)),
+ ty::TyUint(uint_type) => Some(UintSimplifiedType(uint_type)),
+ ty::TyFloat(float_type) => Some(FloatSimplifiedType(float_type)),
+ ty::TyEnum(def_id, _) => Some(EnumSimplifiedType(def_id)),
+ ty::TyStr => Some(StrSimplifiedType),
+ ty::TyArray(..) | ty::TySlice(_) => Some(VecSimplifiedType),
+ ty::TyRawPtr(_) => Some(PtrSimplifiedType),
+ ty::TyTrait(ref trait_info) => {
Some(TraitSimplifiedType(trait_info.principal_def_id()))
}
- ty::ty_struct(def_id, _) => {
+ ty::TyStruct(def_id, _) => {
Some(StructSimplifiedType(def_id))
}
- ty::ty_rptr(_, mt) => {
+ ty::TyRef(_, mt) => {
// since we introduce auto-refs during method lookup, we
// just treat &T and T as equivalent from the point of
// view of possibly unifying
simplify_type(tcx, mt.ty, can_simplify_params)
}
- ty::ty_uniq(_) => {
+ ty::TyBox(_) => {
// treat like we would treat `Box`
let def_id = tcx.lang_items.owned_box().unwrap();
Some(StructSimplifiedType(def_id))
}
- ty::ty_closure(def_id, _) => {
+ ty::TyClosure(def_id, _) => {
Some(ClosureSimplifiedType(def_id))
}
- ty::ty_tup(ref tys) => {
+ ty::TyTuple(ref tys) => {
Some(TupleSimplifiedType(tys.len()))
}
- ty::ty_bare_fn(_, ref f) => {
+ ty::TyBareFn(_, ref f) => {
Some(FunctionSimplifiedType(f.sig.0.inputs.len()))
}
- ty::ty_projection(_) => {
+ ty::TyProjection(_) => {
None
}
- ty::ty_param(_) => {
+ ty::TyParam(_) => {
if can_simplify_params {
Some(ParameterSimplifiedType)
} else {
None
}
}
- ty::ty_infer(_) | ty::ty_err => None,
+ ty::TyInfer(_) | ty::TyError => None,
}
}
use middle::ty::{self, FreeRegion};
use util::common::can_reach;
use util::nodemap::FnvHashMap;
-use util::ppaux::Repr;
#[derive(Clone)]
pub struct FreeRegionMap {
}
pub fn relate_free_regions_from_implications<'tcx>(&mut self,
- tcx: &ty::ctxt<'tcx>,
implications: &[Implication<'tcx>])
{
for implication in implications {
- debug!("implication: {}", implication.repr(tcx));
+ debug!("implication: {:?}", implication);
match *implication {
Implication::RegionSubRegion(_, ty::ReFree(free_a), ty::ReFree(free_b)) => {
self.relate_free_regions(free_a, free_b);
pub fn relate_free_regions_from_predicates<'tcx>(&mut self,
tcx: &ty::ctxt<'tcx>,
predicates: &[ty::Predicate<'tcx>]) {
- debug!("relate_free_regions_from_predicates(predicates={})", predicates.repr(tcx));
+ debug!("relate_free_regions_from_predicates(predicates={:?})", predicates);
for predicate in predicates {
match *predicate {
ty::Predicate::Projection(..) |
_ => {
// All named regions are instantiated with free regions.
tcx.sess.bug(
- &format!("record_region_bounds: non free region: {} / {}",
- r_a.repr(tcx),
- r_b.repr(tcx)));
+ &format!("record_region_bounds: non free region: {:?} / {:?}",
+ r_a,
+ r_b));
}
}
}
use middle::infer::{InferCtxt, GenericKind};
use middle::subst::Substs;
use middle::traits;
-use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty};
+use middle::ty::{self, RegionEscape, ToPolyTraitRef, AsPredicate, Ty};
use middle::ty_fold::{TypeFoldable, TypeFolder};
use syntax::ast;
use util::common::ErrorReported;
use util::nodemap::FnvHashSet;
-use util::ppaux::Repr;
// Helper functions related to manipulating region types.
+#[derive(Debug)]
pub enum Implication<'tcx> {
RegionSubRegion(Option<Ty<'tcx>>, ty::Region, ty::Region),
RegionSubGeneric(Option<Ty<'tcx>>, ty::Region, GenericKind<'tcx>),
span: Span)
-> Vec<Implication<'tcx>>
{
- debug!("implications(body_id={}, ty={}, outer_region={})",
+ debug!("implications(body_id={}, ty={:?}, outer_region={:?})",
body_id,
- ty.repr(closure_typer.tcx()),
- outer_region.repr(closure_typer.tcx()));
+ ty,
+ outer_region);
let mut stack = Vec::new();
stack.push((outer_region, None));
out: Vec::new(),
visited: FnvHashSet() };
wf.accumulate_from_ty(ty);
- debug!("implications: out={}", wf.out.repr(closure_typer.tcx()));
+ debug!("implications: out={:?}", wf.out);
wf.out
}
}
fn accumulate_from_ty(&mut self, ty: Ty<'tcx>) {
- debug!("accumulate_from_ty(ty={})",
- ty.repr(self.tcx()));
+ debug!("accumulate_from_ty(ty={:?})",
+ ty);
// When expanding out associated types, we can visit a cyclic
// set of types. Issue #23003.
}
match ty.sty {
- ty::ty_bool |
- ty::ty_char |
- ty::ty_int(..) |
- ty::ty_uint(..) |
- ty::ty_float(..) |
- ty::ty_bare_fn(..) |
- ty::ty_err |
- ty::ty_str => {
+ ty::TyBool |
+ ty::TyChar |
+ ty::TyInt(..) |
+ ty::TyUint(..) |
+ ty::TyFloat(..) |
+ ty::TyBareFn(..) |
+ ty::TyError |
+ ty::TyStr => {
// No borrowed content reachable here.
}
- ty::ty_closure(def_id, substs) => {
+ ty::TyClosure(def_id, substs) => {
let &(r_a, opt_ty) = self.stack.last().unwrap();
self.out.push(Implication::RegionSubClosure(opt_ty, r_a, def_id, substs));
}
- ty::ty_trait(ref t) => {
+ ty::TyTrait(ref t) => {
let required_region_bounds =
object_region_bounds(self.tcx(), &t.principal, t.bounds.builtin_bounds);
self.accumulate_from_object_ty(ty, t.bounds.region_bound, required_region_bounds)
}
- ty::ty_enum(def_id, substs) |
- ty::ty_struct(def_id, substs) => {
+ ty::TyEnum(def_id, substs) |
+ ty::TyStruct(def_id, substs) => {
let item_scheme = ty::lookup_item_type(self.tcx(), def_id);
self.accumulate_from_adt(ty, def_id, &item_scheme.generics, substs)
}
- ty::ty_vec(t, _) |
- ty::ty_ptr(ty::mt { ty: t, .. }) |
- ty::ty_uniq(t) => {
+ ty::TyArray(t, _) |
+ ty::TySlice(t) |
+ ty::TyRawPtr(ty::mt { ty: t, .. }) |
+ ty::TyBox(t) => {
self.accumulate_from_ty(t)
}
- ty::ty_rptr(r_b, mt) => {
+ ty::TyRef(r_b, mt) => {
self.accumulate_from_rptr(ty, *r_b, mt.ty);
}
- ty::ty_param(p) => {
+ ty::TyParam(p) => {
self.push_param_constraint_from_top(p);
}
- ty::ty_projection(ref data) => {
+ ty::TyProjection(ref data) => {
// `<T as TraitRef<..>>::Name`
self.push_projection_constraint_from_top(data);
}
- ty::ty_tup(ref tuptys) => {
+ ty::TyTuple(ref tuptys) => {
for &tupty in tuptys {
self.accumulate_from_ty(tupty);
}
}
- ty::ty_infer(_) => {
+ ty::TyInfer(_) => {
// This should not happen, BUT:
//
// Currently we uncover region relationships on
let variances = ty::item_variances(self.tcx(), def_id);
- for (®ion, &variance) in substs.regions().iter().zip(variances.regions.iter()) {
+ for (®ion, &variance) in substs.regions().iter().zip(&variances.regions) {
match variance {
ty::Contravariant | ty::Invariant => {
// If any data with this lifetime is reachable
}
}
- for (&ty, &variance) in substs.types.iter().zip(variances.types.iter()) {
+ for (&ty, &variance) in substs.types.iter().zip(&variances.types) {
match variance {
ty::Covariant | ty::Invariant => {
// If any data of this type is reachable within,
fn accumulate_from_assoc_types_transitive(&mut self,
data: &ty::PolyTraitPredicate<'tcx>)
{
- debug!("accumulate_from_assoc_types_transitive({})",
- data.repr(self.tcx()));
+ debug!("accumulate_from_assoc_types_transitive({:?})",
+ data);
for poly_trait_ref in traits::supertraits(self.tcx(), data.to_poly_trait_ref()) {
match ty::no_late_bound_regions(self.tcx(), &poly_trait_ref) {
fn accumulate_from_assoc_types(&mut self,
trait_ref: ty::TraitRef<'tcx>)
{
- debug!("accumulate_from_assoc_types({})",
- trait_ref.repr(self.tcx()));
+ debug!("accumulate_from_assoc_types({:?})",
+ trait_ref);
let trait_def_id = trait_ref.def_id;
let trait_def = ty::lookup_trait_def(self.tcx(), trait_def_id);
.iter()
.map(|&name| ty::mk_projection(self.tcx(), trait_ref.clone(), name))
.collect();
- debug!("accumulate_from_assoc_types: assoc_type_projections={}",
- assoc_type_projections.repr(self.tcx()));
+ debug!("accumulate_from_assoc_types: assoc_type_projections={:?}",
+ assoc_type_projections);
let tys = match self.fully_normalize(&assoc_type_projections) {
Ok(tys) => { tys }
Err(ErrorReported) => { return; }
}
fn fully_normalize<T>(&self, value: &T) -> Result<T,ErrorReported>
- where T : TypeFoldable<'tcx> + ty::HasProjectionTypes + Clone + Repr<'tcx>
+ where T : TypeFoldable<'tcx> + ty::HasProjectionTypes
{
let value =
traits::fully_normalize(self.infcx,
let substs = tcx.mk_substs(principal.0.substs.with_self_ty(open_ty));
let trait_refs = vec!(ty::Binder(ty::TraitRef::new(principal.0.def_id, substs)));
- let param_bounds = ty::ParamBounds {
- region_bounds: Vec::new(),
- builtin_bounds: others,
- trait_bounds: trait_refs,
- projection_bounds: Vec::new(), // not relevant to computing region bounds
- };
+ let mut predicates = others.to_predicates(tcx, open_ty);
+ predicates.extend(trait_refs.iter().map(|t| t.as_predicate()));
- let predicates = ty::predicates(tcx, open_ty, ¶m_bounds);
ty::required_region_bounds(tcx, open_ty, predicates)
}
-
-impl<'tcx> Repr<'tcx> for Implication<'tcx> {
- fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
- match *self {
- Implication::RegionSubRegion(_, ref r_a, ref r_b) => {
- format!("RegionSubRegion({}, {})",
- r_a.repr(tcx),
- r_b.repr(tcx))
- }
-
- Implication::RegionSubGeneric(_, ref r, ref p) => {
- format!("RegionSubGeneric({}, {})",
- r.repr(tcx),
- p.repr(tcx))
- }
-
- Implication::RegionSubClosure(_, ref a, ref b, ref c) => {
- format!("RegionSubClosure({}, {}, {})",
- a.repr(tcx),
- b.repr(tcx),
- c.repr(tcx))
- }
-
- Implication::Predicate(ref def_id, ref p) => {
- format!("Predicate({}, {})",
- def_id.repr(tcx),
- p.repr(tcx))
- }
- }
- }
-}
use middle::ty::{self, Ty};
use middle::ty::TyVar;
use middle::ty_relate::{Relate, RelateResult, TypeRelation};
-use util::ppaux::{Repr};
pub struct Bivariate<'a, 'tcx: 'a> {
fields: CombineFields<'a, 'tcx>
fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
+ fn will_change(&mut self, _: bool, _: bool) -> bool {
+ // since we are not comparing regions, we don't care
+ false
+ }
+
fn relate_with_variance<T:Relate<'a,'tcx>>(&mut self,
variance: ty::Variance,
a: &T,
}
fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
- debug!("{}.tys({}, {})", self.tag(),
- a.repr(self.fields.infcx.tcx), b.repr(self.fields.infcx.tcx));
+ debug!("{}.tys({:?}, {:?})", self.tag(),
+ a, b);
if a == b { return Ok(a); }
let infcx = self.fields.infcx;
let a = infcx.type_variables.borrow().replace_if_possible(a);
let b = infcx.type_variables.borrow().replace_if_possible(b);
match (&a.sty, &b.sty) {
- (&ty::ty_infer(TyVar(a_id)), &ty::ty_infer(TyVar(b_id))) => {
+ (&ty::TyInfer(TyVar(a_id)), &ty::TyInfer(TyVar(b_id))) => {
infcx.type_variables.borrow_mut().relate_vars(a_id, BiTo, b_id);
Ok(a)
}
- (&ty::ty_infer(TyVar(a_id)), _) => {
+ (&ty::TyInfer(TyVar(a_id)), _) => {
try!(self.fields.instantiate(b, BiTo, a_id));
Ok(a)
}
- (_, &ty::ty_infer(TyVar(b_id))) => {
+ (_, &ty::TyInfer(TyVar(b_id))) => {
try!(self.fields.instantiate(a, BiTo, b_id));
Ok(a)
}
use middle::ty_fold;
use middle::ty_fold::{TypeFolder, TypeFoldable};
use middle::ty_relate::{self, Relate, RelateResult, TypeRelation};
-use util::ppaux::Repr;
use syntax::ast;
use syntax::codemap::Span;
pub infcx: &'a InferCtxt<'a, 'tcx>,
pub a_is_expected: bool,
pub trace: TypeTrace<'tcx>,
+ pub cause: Option<ty_relate::Cause>,
}
pub fn super_combine_tys<'a,'tcx:'a,R>(infcx: &InferCtxt<'a, 'tcx>,
match (&a.sty, &b.sty) {
// Relate integral variables to other types
- (&ty::ty_infer(ty::IntVar(a_id)), &ty::ty_infer(ty::IntVar(b_id))) => {
+ (&ty::TyInfer(ty::IntVar(a_id)), &ty::TyInfer(ty::IntVar(b_id))) => {
try!(infcx.int_unification_table
.borrow_mut()
.unify_var_var(a_id, b_id)
.map_err(|e| int_unification_error(a_is_expected, e)));
Ok(a)
}
- (&ty::ty_infer(ty::IntVar(v_id)), &ty::ty_int(v)) => {
+ (&ty::TyInfer(ty::IntVar(v_id)), &ty::TyInt(v)) => {
unify_integral_variable(infcx, a_is_expected, v_id, IntType(v))
}
- (&ty::ty_int(v), &ty::ty_infer(ty::IntVar(v_id))) => {
+ (&ty::TyInt(v), &ty::TyInfer(ty::IntVar(v_id))) => {
unify_integral_variable(infcx, !a_is_expected, v_id, IntType(v))
}
- (&ty::ty_infer(ty::IntVar(v_id)), &ty::ty_uint(v)) => {
+ (&ty::TyInfer(ty::IntVar(v_id)), &ty::TyUint(v)) => {
unify_integral_variable(infcx, a_is_expected, v_id, UintType(v))
}
- (&ty::ty_uint(v), &ty::ty_infer(ty::IntVar(v_id))) => {
+ (&ty::TyUint(v), &ty::TyInfer(ty::IntVar(v_id))) => {
unify_integral_variable(infcx, !a_is_expected, v_id, UintType(v))
}
// Relate floating-point variables to other types
- (&ty::ty_infer(ty::FloatVar(a_id)), &ty::ty_infer(ty::FloatVar(b_id))) => {
+ (&ty::TyInfer(ty::FloatVar(a_id)), &ty::TyInfer(ty::FloatVar(b_id))) => {
try!(infcx.float_unification_table
.borrow_mut()
.unify_var_var(a_id, b_id)
.map_err(|e| float_unification_error(relation.a_is_expected(), e)));
Ok(a)
}
- (&ty::ty_infer(ty::FloatVar(v_id)), &ty::ty_float(v)) => {
+ (&ty::TyInfer(ty::FloatVar(v_id)), &ty::TyFloat(v)) => {
unify_float_variable(infcx, a_is_expected, v_id, v)
}
- (&ty::ty_float(v), &ty::ty_infer(ty::FloatVar(v_id))) => {
+ (&ty::TyFloat(v), &ty::TyInfer(ty::FloatVar(v_id))) => {
unify_float_variable(infcx, !a_is_expected, v_id, v)
}
// All other cases of inference are errors
- (&ty::ty_infer(_), _) |
- (_, &ty::ty_infer(_)) => {
+ (&ty::TyInfer(_), _) |
+ (_, &ty::TyInfer(_)) => {
Err(ty::terr_sorts(ty_relate::expected_found(relation, &a, &b)))
}
b_vid: ty::TyVid)
-> RelateResult<'tcx, ()>
{
- let tcx = self.infcx.tcx;
let mut stack = Vec::new();
stack.push((a_ty, dir, b_vid));
loop {
Some(e) => e,
};
- debug!("instantiate(a_ty={} dir={:?} b_vid={})",
- a_ty.repr(tcx),
+ debug!("instantiate(a_ty={:?} dir={:?} b_vid={:?})",
+ a_ty,
dir,
- b_vid.repr(tcx));
+ b_vid);
// Check whether `vid` has been instantiated yet. If not,
// make a generalized form of `ty` and instantiate with
EqTo => self.generalize(a_ty, b_vid, false),
BiTo | SupertypeOf | SubtypeOf => self.generalize(a_ty, b_vid, true),
});
- debug!("instantiate(a_ty={}, dir={:?}, \
- b_vid={}, generalized_ty={})",
- a_ty.repr(tcx), dir, b_vid.repr(tcx),
- generalized_ty.repr(tcx));
+ debug!("instantiate(a_ty={:?}, dir={:?}, \
+ b_vid={:?}, generalized_ty={:?})",
+ a_ty, dir, b_vid,
+ generalized_ty);
self.infcx.type_variables
.borrow_mut()
.instantiate_and_push(
/// Attempts to generalize `ty` for the type variable `for_vid`. This checks for cycle -- that
/// is, whether the type `ty` references `for_vid`. If `make_region_vars` is true, it will also
- /// replace all regions with fresh variables. Returns `ty_err` in the case of a cycle, `Ok`
+ /// replace all regions with fresh variables. Returns `TyError` in the case of a cycle, `Ok`
/// otherwise.
fn generalize(&self,
ty: Ty<'tcx>,
// (In particular, you could have something like `$0 = Box<$1>`
// where `$1` has already been instantiated with `Box<$0>`)
match t.sty {
- ty::ty_infer(ty::TyVar(vid)) => {
+ ty::TyInfer(ty::TyVar(vid)) => {
if vid == self.for_vid {
self.cycle_detected = true;
self.tcx().types.err
ty::ReEarlyBound(..) => {
self.tcx().sess.span_bug(
self.span,
- &format!("Encountered early bound region when generalizing: {}",
- r.repr(self.tcx())));
+ &format!("Encountered early bound region when generalizing: {:?}",
+ r));
}
// Always make a fresh region variable for skolemized regions;
use middle::ty::{self, Ty};
use middle::ty::TyVar;
use middle::ty_relate::{Relate, RelateResult, TypeRelation};
-use util::ppaux::{Repr};
pub struct Equate<'a, 'tcx: 'a> {
fields: CombineFields<'a, 'tcx>
fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
+ fn will_change(&mut self, a: bool, b: bool) -> bool {
+ // if either side changed from what it was, that could cause equality to fail
+ a || b
+ }
+
fn relate_with_variance<T:Relate<'a,'tcx>>(&mut self,
_: ty::Variance,
a: &T,
}
fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
- debug!("{}.tys({}, {})", self.tag(),
- a.repr(self.fields.infcx.tcx), b.repr(self.fields.infcx.tcx));
+ debug!("{}.tys({:?}, {:?})", self.tag(),
+ a, b);
if a == b { return Ok(a); }
let infcx = self.fields.infcx;
let a = infcx.type_variables.borrow().replace_if_possible(a);
let b = infcx.type_variables.borrow().replace_if_possible(b);
match (&a.sty, &b.sty) {
- (&ty::ty_infer(TyVar(a_id)), &ty::ty_infer(TyVar(b_id))) => {
+ (&ty::TyInfer(TyVar(a_id)), &ty::TyInfer(TyVar(b_id))) => {
infcx.type_variables.borrow_mut().relate_vars(a_id, EqTo, b_id);
Ok(a)
}
- (&ty::ty_infer(TyVar(a_id)), _) => {
+ (&ty::TyInfer(TyVar(a_id)), _) => {
try!(self.fields.instantiate(b, EqTo, a_id));
Ok(a)
}
- (_, &ty::ty_infer(TyVar(b_id))) => {
+ (_, &ty::TyInfer(TyVar(b_id))) => {
try!(self.fields.instantiate(a, EqTo, b_id));
Ok(a)
}
}
fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> {
- debug!("{}.regions({}, {})",
+ debug!("{}.regions({:?}, {:?})",
self.tag(),
- a.repr(self.fields.infcx.tcx),
- b.repr(self.fields.infcx.tcx));
+ a,
+ b);
let origin = Subtype(self.fields.trace.clone());
self.fields.infcx.region_vars.make_eqregion(origin, a, b);
Ok(a)
use super::region_inference::SameRegions;
use std::collections::HashSet;
+use ast_map;
use middle::def;
use middle::infer;
+use middle::region;
use middle::subst;
use middle::ty::{self, Ty};
use middle::ty::{Region, ReFree};
+
use std::cell::{Cell, RefCell};
use std::char::from_u32;
-use std::string::String;
+use std::fmt;
use syntax::ast;
-use syntax::ast_map;
use syntax::ast_util::name_to_dummy_lifetime;
use syntax::owned_slice::OwnedSlice;
-use syntax::codemap;
+use syntax::codemap::{Pos, Span};
use syntax::parse::token;
use syntax::print::pprust;
use syntax::ptr::P;
-use util::ppaux::bound_region_to_string;
-use util::ppaux::note_and_explain_region;
-// Note: only import UserString, not Repr, since user-facing error
-// messages shouldn't include debug serializations.
-use util::ppaux::UserString;
+pub fn note_and_explain_region(tcx: &ty::ctxt,
+ prefix: &str,
+ region: ty::Region,
+ suffix: &str) {
+ fn item_scope_tag(item: &ast::Item) -> &'static str {
+ match item.node {
+ ast::ItemImpl(..) => "impl",
+ ast::ItemStruct(..) => "struct",
+ ast::ItemEnum(..) => "enum",
+ ast::ItemTrait(..) => "trait",
+ ast::ItemFn(..) => "function body",
+ _ => "item"
+ }
+ }
+
+ fn explain_span(tcx: &ty::ctxt, heading: &str, span: Span)
+ -> (String, Option<Span>) {
+ let lo = tcx.sess.codemap().lookup_char_pos_adj(span.lo);
+ (format!("the {} at {}:{}", heading, lo.line, lo.col.to_usize()),
+ Some(span))
+ }
+
+ let (description, span) = match region {
+ ty::ReScope(scope) => {
+ let new_string;
+ let unknown_scope = || {
+ format!("{}unknown scope: {:?}{}. Please report a bug.",
+ prefix, scope, suffix)
+ };
+ let span = match scope.span(&tcx.map) {
+ Some(s) => s,
+ None => return tcx.sess.note(&unknown_scope())
+ };
+ let tag = match tcx.map.find(scope.node_id()) {
+ Some(ast_map::NodeBlock(_)) => "block",
+ Some(ast_map::NodeExpr(expr)) => match expr.node {
+ ast::ExprCall(..) => "call",
+ ast::ExprMethodCall(..) => "method call",
+ ast::ExprMatch(_, _, ast::MatchSource::IfLetDesugar { .. }) => "if let",
+ ast::ExprMatch(_, _, ast::MatchSource::WhileLetDesugar) => "while let",
+ ast::ExprMatch(_, _, ast::MatchSource::ForLoopDesugar) => "for",
+ ast::ExprMatch(..) => "match",
+ _ => "expression",
+ },
+ Some(ast_map::NodeStmt(_)) => "statement",
+ Some(ast_map::NodeItem(it)) => item_scope_tag(&*it),
+ Some(_) | None => {
+ return tcx.sess.span_note(span, &unknown_scope());
+ }
+ };
+ let scope_decorated_tag = match scope {
+ region::CodeExtent::Misc(_) => tag,
+ region::CodeExtent::ParameterScope { .. } => {
+ "scope of parameters for function"
+ }
+ region::CodeExtent::DestructionScope(_) => {
+ new_string = format!("destruction scope surrounding {}", tag);
+ &new_string[..]
+ }
+ region::CodeExtent::Remainder(r) => {
+ new_string = format!("block suffix following statement {}",
+ r.first_statement_index);
+ &new_string[..]
+ }
+ };
+ explain_span(tcx, scope_decorated_tag, span)
+ }
+
+ ty::ReFree(ref fr) => {
+ let prefix = match fr.bound_region {
+ ty::BrAnon(idx) => {
+ format!("the anonymous lifetime #{} defined on", idx + 1)
+ }
+ ty::BrFresh(_) => "an anonymous lifetime defined on".to_owned(),
+ _ => {
+ format!("the lifetime {} as defined on",
+ fr.bound_region)
+ }
+ };
+
+ match tcx.map.find(fr.scope.node_id) {
+ Some(ast_map::NodeBlock(ref blk)) => {
+ let (msg, opt_span) = explain_span(tcx, "block", blk.span);
+ (format!("{} {}", prefix, msg), opt_span)
+ }
+ Some(ast_map::NodeItem(it)) => {
+ let tag = item_scope_tag(&*it);
+ let (msg, opt_span) = explain_span(tcx, tag, it.span);
+ (format!("{} {}", prefix, msg), opt_span)
+ }
+ Some(_) | None => {
+ // this really should not happen
+ (format!("{} unknown free region bounded by scope {:?}",
+ prefix, fr.scope), None)
+ }
+ }
+ }
+
+ ty::ReStatic => ("the static lifetime".to_owned(), None),
+
+ ty::ReEmpty => ("the empty lifetime".to_owned(), None),
+
+ ty::ReEarlyBound(ref data) => {
+ (format!("{}", token::get_name(data.name)), None)
+ }
+
+ // I believe these cases should not occur (except when debugging,
+ // perhaps)
+ ty::ReInfer(_) | ty::ReLateBound(..) => {
+ (format!("lifetime {:?}", region), None)
+ }
+ };
+ let message = format!("{}{}{}", prefix, description, suffix);
+ if let Some(span) = span {
+ tcx.sess.span_note(span, &message);
+ } else {
+ tcx.sess.note(&message);
+ }
+}
pub trait ErrorReporting<'tcx> {
fn report_region_errors(&self,
fn values_str(&self, values: &ValuePairs<'tcx>) -> Option<String>;
- fn expected_found_str<T: UserString<'tcx> + Resolvable<'tcx>>(
+ fn expected_found_str<T: fmt::Display + Resolvable<'tcx>>(
&self,
exp_found: &ty::expected_found<T>)
-> Option<String>;
fn give_expl_lifetime_param(&self,
decl: &ast::FnDecl,
unsafety: ast::Unsafety,
+ constness: ast::Constness,
ident: ast::Ident,
opt_explicit_self: Option<&ast::ExplicitSelf_>,
generics: &ast::Generics,
- span: codemap::Span);
+ span: Span);
}
impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
"{}: {} ({})",
trace.origin,
expected_found_str,
- ty::type_err_to_str(self.tcx, terr));
+ terr);
match trace.origin {
infer::MatchExpressionArm(_, arm_span) =>
}
}
- fn expected_found_str<T: UserString<'tcx> + Resolvable<'tcx>>(
+ fn expected_found_str<T: fmt::Display + Resolvable<'tcx>>(
&self,
exp_found: &ty::expected_found<T>)
-> Option<String>
}
Some(format!("expected `{}`, found `{}`",
- expected.user_string(self.tcx),
- found.user_string(self.tcx)))
+ expected,
+ found))
}
fn report_generic_bound_failure(&self,
let labeled_user_string = match bound_kind {
GenericKind::Param(ref p) =>
- format!("the parameter type `{}`", p.user_string(self.tcx)),
+ format!("the parameter type `{}`", p),
GenericKind::Projection(ref p) =>
- format!("the associated type `{}`", p.user_string(self.tcx)),
+ format!("the associated type `{}`", p),
};
match sub {
origin.span(),
&format!(
"consider adding an explicit lifetime bound `{}: {}`...",
- bound_kind.user_string(self.tcx),
- sub.user_string(self.tcx)));
+ bound_kind,
+ sub));
}
ty::ReStatic => {
origin.span(),
&format!(
"consider adding an explicit lifetime bound `{}: 'static`...",
- bound_kind.user_string(self.tcx)));
+ bound_kind));
}
_ => {
origin.span(),
&format!(
"consider adding an explicit lifetime bound for `{}`",
- bound_kind.user_string(self.tcx)));
+ bound_kind));
note_and_explain_region(
self.tcx,
&format!("{} must be valid for ", labeled_user_string),
sub: Region,
sup: Region) {
match origin {
- infer::Subtype(trace) => {
+ infer::Subtype(trace) |
+ infer::DefaultExistentialBound(trace) => {
let terr = ty::terr_regions_does_not_outlive(sup, sub);
self.report_and_explain_type_error(trace, &terr);
}
Some(ref node) => match *node {
ast_map::NodeItem(ref item) => {
match item.node {
- ast::ItemFn(ref fn_decl, pur, _, ref gen, _) => {
- Some((fn_decl, gen, pur, item.ident, None, item.span))
+ ast::ItemFn(ref fn_decl, unsafety, constness, _, ref gen, _) => {
+ Some((fn_decl, gen, unsafety, constness,
+ item.ident, None, item.span))
},
_ => None
}
Some((&sig.decl,
&sig.generics,
sig.unsafety,
+ sig.constness,
item.ident,
Some(&sig.explicit_self.node),
item.span))
Some((&sig.decl,
&sig.generics,
sig.unsafety,
+ sig.constness,
item.ident,
Some(&sig.explicit_self.node),
item.span))
},
None => None
};
- let (fn_decl, generics, unsafety, ident, expl_self, span)
+ let (fn_decl, generics, unsafety, constness, ident, expl_self, span)
= node_inner.expect("expect item fn");
let rebuilder = Rebuilder::new(self.tcx, fn_decl, expl_self,
generics, same_regions, &life_giver);
let (fn_decl, expl_self, generics) = rebuilder.rebuild();
- self.give_expl_lifetime_param(&fn_decl, unsafety, ident,
+ self.give_expl_lifetime_param(&fn_decl, unsafety, constness, ident,
expl_self.as_ref(), &generics, span);
}
}
fn give_expl_lifetime_param(&self,
decl: &ast::FnDecl,
unsafety: ast::Unsafety,
+ constness: ast::Constness,
ident: ast::Ident,
opt_explicit_self: Option<&ast::ExplicitSelf_>,
generics: &ast::Generics,
- span: codemap::Span) {
- let suggested_fn = pprust::fun_to_string(decl, unsafety, ident,
- opt_explicit_self, generics);
+ span: Span) {
+ let suggested_fn = pprust::fun_to_string(decl, unsafety, constness, ident,
+ opt_explicit_self, generics);
let msg = format!("consider using an explicit lifetime \
parameter as shown: {}", suggested_fn);
self.tcx.sess.span_help(span, &msg[..]);
fn report_inference_failure(&self,
var_origin: RegionVariableOrigin) {
+ let br_string = |br: ty::BoundRegion| {
+ let mut s = br.to_string();
+ if !s.is_empty() {
+ s.push_str(" ");
+ }
+ s
+ };
let var_description = match var_origin {
infer::MiscVariable(_) => "".to_string(),
infer::PatternRegion(_) => " for pattern".to_string(),
infer::Autoref(_) => " for autoref".to_string(),
infer::Coercion(_) => " for automatic coercion".to_string(),
infer::LateBoundRegion(_, br, infer::FnCall) => {
- format!(" for {}in function call",
- bound_region_to_string(self.tcx, "lifetime parameter ", true, br))
+ format!(" for lifetime parameter {}in function call",
+ br_string(br))
}
infer::LateBoundRegion(_, br, infer::HigherRankedType) => {
- format!(" for {}in generic type",
- bound_region_to_string(self.tcx, "lifetime parameter ", true, br))
+ format!(" for lifetime parameter {}in generic type", br_string(br))
}
infer::LateBoundRegion(_, br, infer::AssocTypeProjection(type_name)) => {
- format!(" for {}in trait containing associated type `{}`",
- bound_region_to_string(self.tcx, "lifetime parameter ", true, br),
- token::get_name(type_name))
+ format!(" for lifetime parameter {}in trait containing associated type `{}`",
+ br_string(br), token::get_name(type_name))
}
infer::EarlyBoundRegion(_, name) => {
format!(" for lifetime parameter `{}`",
fn note_region_origin(&self, origin: &SubregionOrigin<'tcx>) {
match *origin {
- infer::Subtype(ref trace) => {
+ infer::Subtype(ref trace) |
+ infer::DefaultExistentialBound(ref trace) => {
let desc = match trace.origin {
infer::Misc(_) => {
"types are compatible"
let method_id_opt = match tcx.map.find(parent) {
Some(node) => match node {
ast_map::NodeItem(item) => match item.node {
- ast::ItemFn(_, _, _, ref gen, _) => {
+ ast::ItemFn(_, _, _, _, ref gen, _) => {
taken.push_all(&gen.lifetimes);
None
},
fn give_lifetime(&self) -> ast::Lifetime {
let mut lifetime;
loop {
- let mut s = String::from_str("'");
+ let mut s = String::from("'");
s.push_str(&num_to_string(self.counter.get()));
if !self.taken.contains(&s) {
lifetime = name_to_dummy_lifetime(
}
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+ if !ty::type_needs_infer(t) && !ty::type_has_erasable_regions(t) {
+ return t;
+ }
+
let tcx = self.infcx.tcx;
match t.sty {
- ty::ty_infer(ty::TyVar(v)) => {
+ ty::TyInfer(ty::TyVar(v)) => {
self.freshen(
self.infcx.type_variables.borrow().probe(v),
ty::TyVar(v),
ty::FreshTy)
}
- ty::ty_infer(ty::IntVar(v)) => {
+ ty::TyInfer(ty::IntVar(v)) => {
self.freshen(
self.infcx.int_unification_table.borrow_mut()
.probe(v)
ty::FreshIntTy)
}
- ty::ty_infer(ty::FloatVar(v)) => {
+ ty::TyInfer(ty::FloatVar(v)) => {
self.freshen(
self.infcx.float_unification_table.borrow_mut()
.probe(v)
ty::FreshFloatTy)
}
- ty::ty_infer(ty::FreshTy(c)) |
- ty::ty_infer(ty::FreshIntTy(c)) |
- ty::ty_infer(ty::FreshFloatTy(c)) => {
+ ty::TyInfer(ty::FreshTy(c)) |
+ ty::TyInfer(ty::FreshIntTy(c)) |
+ ty::TyInfer(ty::FreshFloatTy(c)) => {
if c >= self.freshen_count {
tcx.sess.bug(
&format!("Encountered a freshend type with id {} \
t
}
- ty::ty_bool |
- ty::ty_char |
- ty::ty_int(..) |
- ty::ty_uint(..) |
- ty::ty_float(..) |
- ty::ty_enum(..) |
- ty::ty_uniq(..) |
- ty::ty_str |
- ty::ty_err |
- ty::ty_vec(..) |
- ty::ty_ptr(..) |
- ty::ty_rptr(..) |
- ty::ty_bare_fn(..) |
- ty::ty_trait(..) |
- ty::ty_struct(..) |
- ty::ty_closure(..) |
- ty::ty_tup(..) |
- ty::ty_projection(..) |
- ty::ty_param(..) => {
+ ty::TyBool |
+ ty::TyChar |
+ ty::TyInt(..) |
+ ty::TyUint(..) |
+ ty::TyFloat(..) |
+ ty::TyEnum(..) |
+ ty::TyBox(..) |
+ ty::TyStr |
+ ty::TyError |
+ ty::TyArray(..) |
+ ty::TySlice(..) |
+ ty::TyRawPtr(..) |
+ ty::TyRef(..) |
+ ty::TyBareFn(..) |
+ ty::TyTrait(..) |
+ ty::TyStruct(..) |
+ ty::TyClosure(..) |
+ ty::TyTuple(..) |
+ ty::TyProjection(..) |
+ ty::TyParam(..) => {
ty_fold::super_fold_ty(self, t)
}
}
use middle::ty::{self, Ty};
use middle::ty_relate::{Relate, RelateResult, TypeRelation};
-use util::ppaux::Repr;
/// "Greatest lower bound" (common subtype)
pub struct Glb<'a, 'tcx: 'a> {
fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
+ fn will_change(&mut self, a: bool, b: bool) -> bool {
+ // Hmm, so the result of GLB will still be a LB if one or both
+ // sides change to 'static, but it may no longer be the GLB.
+ // I'm going to go with `a || b` here to be conservative,
+ // since the result of this operation may be affected, though
+ // I think it would mostly be more accepting than before (since the result
+ // would be a bigger region).
+ a || b
+ }
+
fn relate_with_variance<T:Relate<'a,'tcx>>(&mut self,
variance: ty::Variance,
a: &T,
}
fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> {
- debug!("{}.regions({}, {})",
+ debug!("{}.regions({:?}, {:?})",
self.tag(),
- a.repr(self.fields.infcx.tcx),
- b.repr(self.fields.infcx.tcx));
+ a,
+ b);
let origin = Subtype(self.fields.trace.clone());
Ok(self.fields.infcx.region_vars.glb_regions(origin, a, b))
use middle::ty_relate::{Relate, RelateResult, TypeRelation};
use syntax::codemap::Span;
use util::nodemap::{FnvHashMap, FnvHashSet};
-use util::ppaux::Repr;
pub trait HigherRankedRelations<'a,'tcx> {
fn higher_ranked_sub<T>(&self, a: &Binder<T>, b: &Binder<T>) -> RelateResult<'tcx, Binder<T>>
-> RelateResult<'tcx, Binder<T>>
where T: Relate<'a,'tcx>
{
- let tcx = self.infcx.tcx;
-
- debug!("higher_ranked_sub(a={}, b={})",
- a.repr(tcx), b.repr(tcx));
+ debug!("higher_ranked_sub(a={:?}, b={:?})",
+ a, b);
// Rather than checking the subtype relationship between `a` and `b`
// as-is, we need to do some extra work here in order to make sure
let (b_prime, skol_map) =
self.infcx.skolemize_late_bound_regions(b, snapshot);
- debug!("a_prime={}", a_prime.repr(tcx));
- debug!("b_prime={}", b_prime.repr(tcx));
+ debug!("a_prime={:?}", a_prime);
+ debug!("b_prime={:?}", b_prime);
// Compare types now that bound regions have been replaced.
let result = try!(self.sub().relate(&a_prime, &b_prime));
}
}
- debug!("higher_ranked_sub: OK result={}",
- result.repr(tcx));
+ debug!("higher_ranked_sub: OK result={:?}",
+ result);
Ok(ty::Binder(result))
});
try!(self.lub().relate(&a_with_fresh, &b_with_fresh));
let result0 =
self.infcx.resolve_type_vars_if_possible(&result0);
- debug!("lub result0 = {}", result0.repr(self.tcx()));
+ debug!("lub result0 = {:?}", result0);
// Generalize the regions appearing in result0 if possible
let new_vars = self.infcx.region_vars_confined_to_snapshot(snapshot);
|r, debruijn| generalize_region(self.infcx, span, snapshot, debruijn,
&new_vars, &a_map, r));
- debug!("lub({},{}) = {}",
- a.repr(self.tcx()),
- b.repr(self.tcx()),
- result1.repr(self.tcx()));
+ debug!("lub({:?},{:?}) = {:?}",
+ a,
+ b,
+ result1);
Ok(ty::Binder(result1))
});
fn higher_ranked_glb<T>(&self, a: &Binder<T>, b: &Binder<T>) -> RelateResult<'tcx, Binder<T>>
where T: Relate<'a,'tcx>
{
- debug!("higher_ranked_glb({}, {})",
- a.repr(self.tcx()), b.repr(self.tcx()));
+ debug!("higher_ranked_glb({:?}, {:?})",
+ a, b);
// Make a snapshot so we can examine "all bindings that were
// created as part of this type comparison".
try!(self.glb().relate(&a_with_fresh, &b_with_fresh));
let result0 =
self.infcx.resolve_type_vars_if_possible(&result0);
- debug!("glb result0 = {}", result0.repr(self.tcx()));
+ debug!("glb result0 = {:?}", result0);
// Generalize the regions appearing in result0 if possible
let new_vars = self.infcx.region_vars_confined_to_snapshot(snapshot);
&a_map, &a_vars, &b_vars,
r));
- debug!("glb({},{}) = {}",
- a.repr(self.tcx()),
- b.repr(self.tcx()),
- result1.repr(self.tcx()));
+ debug!("glb({:?},{:?}) = {:?}",
+ a,
+ b,
+ result1);
Ok(ty::Binder(result1))
});
let escaping_region_vars: FnvHashSet<_> =
escaping_types
.iter()
- .flat_map(|&t| ty_fold::collect_regions(self.tcx, &t).into_iter())
+ .flat_map(|&t| ty_fold::collect_regions(self.tcx, &t))
.collect();
region_vars.retain(|®ion_vid| {
!escaping_region_vars.contains(&r)
});
- debug!("region_vars_confined_to_snapshot: region_vars={} escaping_types={}",
- region_vars.repr(self.tcx),
- escaping_types.repr(self.tcx));
+ debug!("region_vars_confined_to_snapshot: region_vars={:?} escaping_types={:?}",
+ region_vars,
+ escaping_types);
region_vars
}
binder: &ty::Binder<T>,
snapshot: &CombinedSnapshot)
-> (T, SkolemizationMap)
- where T : TypeFoldable<'tcx> + Repr<'tcx>
+ where T : TypeFoldable<'tcx>
{
/*!
* Replace all regions bound by `binder` with skolemized regions and
* details.
*/
- let (result, map) = ty::replace_late_bound_regions(infcx.tcx, binder, |br| {
+ let (result, map) = ty_fold::replace_late_bound_regions(infcx.tcx, binder, |br| {
infcx.region_vars.new_skolemized(br, &snapshot.region_vars_snapshot)
});
- debug!("skolemize_bound_regions(binder={}, result={}, map={})",
- binder.repr(infcx.tcx),
- result.repr(infcx.tcx),
- map.repr(infcx.tcx));
+ debug!("skolemize_bound_regions(binder={:?}, result={:?}, map={:?})",
+ binder,
+ result,
+ map);
(result, map)
}
* hold. See `README.md` for more details.
*/
- debug!("leak_check: skol_map={}",
- skol_map.repr(infcx.tcx));
+ debug!("leak_check: skol_map={:?}",
+ skol_map);
let new_vars = infcx.region_vars_confined_to_snapshot(snapshot);
for (&skol_br, &skol) in skol_map {
}
};
- debug!("{} (which replaced {}) is tainted by {}",
- skol.repr(infcx.tcx),
- skol_br.repr(infcx.tcx),
- tainted_region.repr(infcx.tcx));
+ debug!("{:?} (which replaced {:?}) is tainted by {:?}",
+ skol,
+ skol_br,
+ tainted_region);
// A is not as polymorphic as B:
return Err((skol_br, tainted_region));
snapshot: &CombinedSnapshot,
value: &T)
-> T
- where T : TypeFoldable<'tcx> + Repr<'tcx>
+ where T : TypeFoldable<'tcx>
{
debug_assert!(leak_check(infcx, &skol_map, snapshot).is_ok());
- debug!("plug_leaks(skol_map={}, value={})",
- skol_map.repr(infcx.tcx),
- value.repr(infcx.tcx));
+ debug!("plug_leaks(skol_map={:?}, value={:?})",
+ skol_map,
+ value);
// Compute a mapping from the "taint set" of each skolemized
// region back to the `ty::BoundRegion` that it originally
})
.collect();
- debug!("plug_leaks: inv_skol_map={}",
- inv_skol_map.repr(infcx.tcx));
+ debug!("plug_leaks: inv_skol_map={:?}",
+ inv_skol_map);
// Remove any instantiated type variables from `value`; those can hide
// references to regions from the `fold_regions` code below.
}
});
- debug!("plug_leaks: result={}",
- result.repr(infcx.tcx));
+ debug!("plug_leaks: result={:?}",
+ result);
result
}
use middle::ty::TyVar;
use middle::ty::{self, Ty};
use middle::ty_relate::{RelateResult, TypeRelation};
-use util::ppaux::Repr;
pub trait LatticeDir<'f,'tcx> : TypeRelation<'f,'tcx> {
fn infcx(&self) -> &'f InferCtxt<'f, 'tcx>;
-> RelateResult<'tcx, Ty<'tcx>>
where 'tcx: 'a
{
- debug!("{}.lattice_tys({}, {})",
+ debug!("{}.lattice_tys({:?}, {:?})",
this.tag(),
- a.repr(this.tcx()),
- b.repr(this.tcx()));
+ a,
+ b);
if a == b {
return Ok(a);
let a = infcx.type_variables.borrow().replace_if_possible(a);
let b = infcx.type_variables.borrow().replace_if_possible(b);
match (&a.sty, &b.sty) {
- (&ty::ty_infer(TyVar(..)), &ty::ty_infer(TyVar(..)))
+ (&ty::TyInfer(TyVar(..)), &ty::TyInfer(TyVar(..)))
if infcx.type_var_diverges(a) && infcx.type_var_diverges(b) => {
let v = infcx.next_diverging_ty_var();
try!(this.relate_bound(v, a, b));
Ok(v)
}
- (&ty::ty_infer(TyVar(..)), _) |
- (_, &ty::ty_infer(TyVar(..))) => {
+ (&ty::TyInfer(TyVar(..)), _) |
+ (_, &ty::TyInfer(TyVar(..))) => {
let v = infcx.next_ty_var();
try!(this.relate_bound(v, a, b));
Ok(v)
use middle::ty::{self, Ty};
use middle::ty_relate::{Relate, RelateResult, TypeRelation};
-use util::ppaux::Repr;
/// "Least upper bound" (common supertype)
pub struct Lub<'a, 'tcx: 'a> {
fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
+ fn will_change(&mut self, a: bool, b: bool) -> bool {
+ // result will be 'static if a || b
+ a || b
+ }
+
fn relate_with_variance<T:Relate<'a,'tcx>>(&mut self,
variance: ty::Variance,
a: &T,
}
fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> {
- debug!("{}.regions({}, {})",
+ debug!("{}.regions({:?}, {:?})",
self.tag(),
- a.repr(self.tcx()),
- b.repr(self.tcx()));
+ a,
+ b);
let origin = Subtype(self.fields.trace.clone());
Ok(self.fields.infcx.region_vars.lub_regions(origin, a, b))
use middle::subst;
use middle::subst::Substs;
use middle::ty::{TyVid, IntVid, FloatVid, RegionVid, UnconstrainedNumeric};
-use middle::ty::replace_late_bound_regions;
use middle::ty::{self, Ty};
-use middle::ty_fold::{TypeFolder, TypeFoldable};
+use middle::ty_fold::{self, TypeFolder, TypeFoldable};
use middle::ty_relate::{Relate, RelateResult, TypeRelation};
use rustc_data_structures::unify::{self, UnificationTable};
use std::cell::{RefCell};
use syntax::codemap;
use syntax::codemap::Span;
use util::nodemap::FnvHashMap;
-use util::ppaux::ty_to_string;
-use util::ppaux::{Repr, UserString};
use self::combine::CombineFields;
use self::region_inference::{RegionVarBindings, RegionSnapshot};
/// encounter an error or subtyping constraint.
///
/// See `error_reporting.rs` for more details.
-#[derive(Clone, Debug)]
+#[derive(Clone)]
pub struct TypeTrace<'tcx> {
origin: TypeOrigin,
values: ValuePairs<'tcx>,
// Arose from a subtyping relation
Subtype(TypeTrace<'tcx>),
+ // Arose from a subtyping relation
+ DefaultExistentialBound(TypeTrace<'tcx>),
+
// Stack-allocated closures cannot outlive innermost loop
// or function so as to ensure we only require finite stack
InfStackClosure(Span),
b: Ty<'tcx>)
-> Ty<'tcx>
{
- debug!("common_supertype({}, {})",
- a.repr(cx.tcx), b.repr(cx.tcx));
+ debug!("common_supertype({:?}, {:?})",
+ a, b);
let trace = TypeTrace {
origin: origin,
b: Ty<'tcx>)
-> UnitResult<'tcx>
{
- debug!("mk_subty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx));
+ debug!("mk_subty({:?} <: {:?})", a, b);
cx.sub_types(a_is_expected, origin, a, b)
}
a: Ty<'tcx>,
b: Ty<'tcx>)
-> UnitResult<'tcx> {
- debug!("can_mk_subty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx));
+ debug!("can_mk_subty({:?} <: {:?})", a, b);
cx.probe(|_| {
let trace = TypeTrace {
origin: Misc(codemap::DUMMY_SP),
origin: SubregionOrigin<'tcx>,
a: ty::Region,
b: ty::Region) {
- debug!("mk_subr({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx));
+ debug!("mk_subr({:?} <: {:?})", a, b);
let snapshot = cx.region_vars.start_snapshot();
cx.region_vars.make_subregion(origin, a, b);
cx.region_vars.commit(snapshot);
b: Ty<'tcx>)
-> UnitResult<'tcx>
{
- debug!("mk_eqty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx));
+ debug!("mk_eqty({:?} <: {:?})", a, b);
cx.commit_if_ok(|_| cx.eq_types(a_is_expected, origin, a, b))
}
b: ty::PolyTraitRef<'tcx>)
-> UnitResult<'tcx>
{
- debug!("mk_sub_trait_refs({} <: {})",
- a.repr(cx.tcx), b.repr(cx.tcx));
+ debug!("mk_sub_trait_refs({:?} <: {:?})",
+ a, b);
cx.commit_if_ok(|_| cx.sub_poly_trait_refs(a_is_expected, origin, a.clone(), b.clone()))
}
pub fn type_var_diverges(&'a self, ty: Ty) -> bool {
match ty.sty {
- ty::ty_infer(ty::TyVar(vid)) => self.type_variables.borrow().var_diverges(vid),
+ ty::TyInfer(ty::TyVar(vid)) => self.type_variables.borrow().var_diverges(vid),
_ => false
}
}
pub fn type_is_unconstrained_numeric(&'a self, ty: Ty) -> UnconstrainedNumeric {
use middle::ty::UnconstrainedNumeric::{Neither, UnconstrainedInt, UnconstrainedFloat};
match ty.sty {
- ty::ty_infer(ty::IntVar(vid)) => {
+ ty::TyInfer(ty::IntVar(vid)) => {
if self.int_unification_table.borrow_mut().has_value(vid) {
Neither
} else {
UnconstrainedInt
}
},
- ty::ty_infer(ty::FloatVar(vid)) => {
+ ty::TyInfer(ty::FloatVar(vid)) => {
if self.float_unification_table.borrow_mut().has_value(vid) {
Neither
} else {
-> CombineFields<'a, 'tcx> {
CombineFields {infcx: self,
a_is_expected: a_is_expected,
- trace: trace}
+ trace: trace,
+ cause: None}
}
// public so that it can be used from the rustc_driver unit tests
b: Ty<'tcx>)
-> UnitResult<'tcx>
{
- debug!("sub_types({} <: {})", a.repr(self.tcx), b.repr(self.tcx));
+ debug!("sub_types({:?} <: {:?})", a, b);
self.commit_if_ok(|_| {
let trace = TypeTrace::types(origin, a_is_expected, a, b);
self.sub(a_is_expected, trace).relate(&a, &b).map(|_| ())
b: ty::TraitRef<'tcx>)
-> UnitResult<'tcx>
{
- debug!("sub_trait_refs({} <: {})",
- a.repr(self.tcx),
- b.repr(self.tcx));
+ debug!("sub_trait_refs({:?} <: {:?})",
+ a,
+ b);
self.commit_if_ok(|_| {
let trace = TypeTrace {
origin: origin,
b: ty::PolyTraitRef<'tcx>)
-> UnitResult<'tcx>
{
- debug!("sub_poly_trait_refs({} <: {})",
- a.repr(self.tcx),
- b.repr(self.tcx));
+ debug!("sub_poly_trait_refs({:?} <: {:?})",
+ a,
+ b);
self.commit_if_ok(|_| {
let trace = TypeTrace {
origin: origin,
value: &ty::Binder<T>,
snapshot: &CombinedSnapshot)
-> (T, SkolemizationMap)
- where T : TypeFoldable<'tcx> + Repr<'tcx>
+ where T : TypeFoldable<'tcx>
{
/*! See `higher_ranked::skolemize_late_bound_regions` */
snapshot: &CombinedSnapshot,
value: &T)
-> T
- where T : TypeFoldable<'tcx> + Repr<'tcx>
+ where T : TypeFoldable<'tcx>
{
/*! See `higher_ranked::plug_leaks` */
}
pub fn ty_to_string(&self, t: Ty<'tcx>) -> String {
- ty_to_string(self.tcx,
- self.resolve_type_vars_if_possible(&t))
+ self.resolve_type_vars_if_possible(&t).to_string()
}
pub fn tys_to_string(&self, ts: &[Ty<'tcx>]) -> String {
}
pub fn trait_ref_to_string(&self, t: &ty::TraitRef<'tcx>) -> String {
- let t = self.resolve_type_vars_if_possible(t);
- t.user_string(self.tcx)
+ self.resolve_type_vars_if_possible(t).to_string()
}
pub fn shallow_resolve(&self, typ: Ty<'tcx>) -> Ty<'tcx> {
match typ.sty {
- ty::ty_infer(ty::TyVar(v)) => {
+ ty::TyInfer(ty::TyVar(v)) => {
// Not entirely obvious: if `typ` is a type variable,
// it can be resolved to an int/float variable, which
// can then be recursively resolved, hence the
.unwrap_or(typ)
}
- ty::ty_infer(ty::IntVar(v)) => {
+ ty::TyInfer(ty::IntVar(v)) => {
self.int_unification_table
.borrow_mut()
.probe(v)
.unwrap_or(typ)
}
- ty::ty_infer(ty::FloatVar(v)) => {
+ ty::TyInfer(ty::FloatVar(v)) => {
self.float_unification_table
.borrow_mut()
.probe(v)
}
// [Note-Type-error-reporting]
- // An invariant is that anytime the expected or actual type is ty_err (the special
+ // An invariant is that anytime the expected or actual type is TyError (the special
// error type, meaning that an error occurred when typechecking this expression),
// this is a derived error. The error cascaded from another error (that was already
// reported), so it's not useful to display it to the user.
// The following four methods -- type_error_message_str, type_error_message_str_with_expected,
// type_error_message, and report_mismatched_types -- implement this logic.
- // They check if either the actual or expected type is ty_err, and don't print the error
+ // They check if either the actual or expected type is TyError, and don't print the error
// in this case. The typechecker should only ever report type errors involving mismatched
// types using one of these four methods, and should not call span_err directly for such
// errors.
Some(t) if ty::type_is_error(t) => (),
_ => {
let error_str = err.map_or("".to_string(), |t_err| {
- format!(" ({})", ty::type_err_to_str(self.tcx, t_err))
+ format!(" ({})", t_err)
});
self.tcx.sess.span_err(sp, &format!("{}{}",
{
let actual_ty = self.resolve_type_vars_if_possible(&actual_ty);
- // Don't report an error if actual type is ty_err.
+ // Don't report an error if actual type is TyError.
if ty::type_is_error(actual_ty) {
return;
}
lbrct: LateBoundRegionConversionTime,
value: &ty::Binder<T>)
-> (T, FnvHashMap<ty::BoundRegion,ty::Region>)
- where T : TypeFoldable<'tcx> + Repr<'tcx>
+ where T : TypeFoldable<'tcx>
{
- ty::replace_late_bound_regions(
+ ty_fold::replace_late_bound_regions(
self.tcx,
value,
|br| self.next_region_var(LateBoundRegion(span, br, lbrct)))
kind: GenericKind<'tcx>,
a: ty::Region,
bs: Vec<ty::Region>) {
- debug!("verify_generic_bound({}, {} <: {})",
- kind.repr(self.tcx),
- a.repr(self.tcx),
- bs.repr(self.tcx));
+ debug!("verify_generic_bound({:?}, {:?} <: {:?})",
+ kind,
+ a,
+ bs);
self.region_vars.verify_generic_bound(origin, kind, a, bs);
}
pub fn can_equate<'b,T>(&'b self, a: &T, b: &T) -> UnitResult<'tcx>
- where T: Relate<'b,'tcx> + Repr<'tcx>
+ where T: Relate<'b,'tcx> + fmt::Debug
{
- debug!("can_equate({}, {})", a.repr(self.tcx), b.repr(self.tcx));
+ debug!("can_equate({:?}, {:?})", a, b);
self.probe(|_| {
// Gin up a dummy trace, since this won't be committed
// anyhow. We should make this typetrace stuff more
}
}
-impl<'tcx> Repr<'tcx> for TypeTrace<'tcx> {
- fn repr(&self, tcx: &ty::ctxt) -> String {
- format!("TypeTrace({})", self.origin.repr(tcx))
+impl<'tcx> fmt::Debug for TypeTrace<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "TypeTrace({:?})", self.origin)
}
}
}
}
-impl<'tcx> Repr<'tcx> for TypeOrigin {
- fn repr(&self, tcx: &ty::ctxt) -> String {
- match *self {
- MethodCompatCheck(a) => {
- format!("MethodCompatCheck({})", a.repr(tcx))
- }
- ExprAssignable(a) => {
- format!("ExprAssignable({})", a.repr(tcx))
- }
- Misc(a) => format!("Misc({})", a.repr(tcx)),
- RelateTraitRefs(a) => {
- format!("RelateTraitRefs({})", a.repr(tcx))
- }
- RelateSelfType(a) => {
- format!("RelateSelfType({})", a.repr(tcx))
- }
- RelateOutputImplTypes(a) => {
- format!("RelateOutputImplTypes({})", a.repr(tcx))
- }
- MatchExpressionArm(a, b) => {
- format!("MatchExpressionArm({}, {})", a.repr(tcx), b.repr(tcx))
- }
- IfExpression(a) => {
- format!("IfExpression({})", a.repr(tcx))
- }
- IfExpressionWithNoElse(a) => {
- format!("IfExpressionWithNoElse({})", a.repr(tcx))
- }
- RangeExpression(a) => {
- format!("RangeExpression({})", a.repr(tcx))
- }
- EquatePredicate(a) => {
- format!("EquatePredicate({})", a.repr(tcx))
- }
- }
- }
-}
-
impl<'tcx> SubregionOrigin<'tcx> {
pub fn span(&self) -> Span {
match *self {
Subtype(ref a) => a.span(),
+ DefaultExistentialBound(ref a) => a.span(),
InfStackClosure(a) => a,
InvokeClosure(a) => a,
DerefPointer(a) => a,
}
}
-impl<'tcx> Repr<'tcx> for SubregionOrigin<'tcx> {
- fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
- match *self {
- Subtype(ref a) => {
- format!("Subtype({})", a.repr(tcx))
- }
- InfStackClosure(a) => {
- format!("InfStackClosure({})", a.repr(tcx))
- }
- InvokeClosure(a) => {
- format!("InvokeClosure({})", a.repr(tcx))
- }
- DerefPointer(a) => {
- format!("DerefPointer({})", a.repr(tcx))
- }
- FreeVariable(a, b) => {
- format!("FreeVariable({}, {})", a.repr(tcx), b)
- }
- IndexSlice(a) => {
- format!("IndexSlice({})", a.repr(tcx))
- }
- RelateObjectBound(a) => {
- format!("RelateObjectBound({})", a.repr(tcx))
- }
- RelateParamBound(a, b) => {
- format!("RelateParamBound({},{})",
- a.repr(tcx),
- b.repr(tcx))
- }
- RelateRegionParamBound(a) => {
- format!("RelateRegionParamBound({})",
- a.repr(tcx))
- }
- RelateDefaultParamBound(a, b) => {
- format!("RelateDefaultParamBound({},{})",
- a.repr(tcx),
- b.repr(tcx))
- }
- Reborrow(a) => format!("Reborrow({})", a.repr(tcx)),
- ReborrowUpvar(a, b) => {
- format!("ReborrowUpvar({},{:?})", a.repr(tcx), b)
- }
- ReferenceOutlivesReferent(_, a) => {
- format!("ReferenceOutlivesReferent({})", a.repr(tcx))
- }
- ExprTypeIsNotInScope(a, b) => {
- format!("ExprTypeIsNotInScope({}, {})",
- a.repr(tcx),
- b.repr(tcx))
- }
- BindingTypeIsNotValidAtDecl(a) => {
- format!("BindingTypeIsNotValidAtDecl({})", a.repr(tcx))
- }
- CallRcvr(a) => format!("CallRcvr({})", a.repr(tcx)),
- CallArg(a) => format!("CallArg({})", a.repr(tcx)),
- CallReturn(a) => format!("CallReturn({})", a.repr(tcx)),
- Operand(a) => format!("Operand({})", a.repr(tcx)),
- AddrOf(a) => format!("AddrOf({})", a.repr(tcx)),
- AutoBorrow(a) => format!("AutoBorrow({})", a.repr(tcx)),
- SafeDestructor(a) => format!("SafeDestructor({})", a.repr(tcx)),
- }
- }
-}
-
impl RegionVariableOrigin {
pub fn span(&self) -> Span {
match *self {
}
}
}
-
-impl<'tcx> Repr<'tcx> for RegionVariableOrigin {
- fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
- match *self {
- MiscVariable(a) => {
- format!("MiscVariable({})", a.repr(tcx))
- }
- PatternRegion(a) => {
- format!("PatternRegion({})", a.repr(tcx))
- }
- AddrOfRegion(a) => {
- format!("AddrOfRegion({})", a.repr(tcx))
- }
- Autoref(a) => format!("Autoref({})", a.repr(tcx)),
- Coercion(a) => format!("Coercion({})", a.repr(tcx)),
- EarlyBoundRegion(a, b) => {
- format!("EarlyBoundRegion({},{})", a.repr(tcx), b.repr(tcx))
- }
- LateBoundRegion(a, b, c) => {
- format!("LateBoundRegion({},{},{:?})", a.repr(tcx), b.repr(tcx), c)
- }
- BoundRegionInCoherence(a) => {
- format!("bound_regionInCoherence({})", a.repr(tcx))
- }
- UpvarRegion(a, b) => {
- format!("UpvarRegion({}, {})", a.repr(tcx), b.repr(tcx))
- }
- }
- }
-}
use middle::infer::SubregionOrigin;
use middle::infer::region_inference::RegionVarBindings;
use util::nodemap::{FnvHashMap, FnvHashSet};
-use util::ppaux::Repr;
use std::borrow::Cow;
use std::collections::hash_map::Entry::Vacant;
use std::fs::File;
use std::io;
use std::io::prelude::*;
-use std::sync::atomic::{AtomicBool, Ordering, ATOMIC_BOOL_INIT};
+use std::sync::atomic::{AtomicBool, Ordering};
use syntax::ast;
fn print_help_message() {
let output_path = {
let output_template = match requested_output {
Ok(ref s) if &**s == "help" => {
- static PRINTED_YET: AtomicBool = ATOMIC_BOOL_INIT;
+ static PRINTED_YET: AtomicBool = AtomicBool::new(false);
if !PRINTED_YET.load(Ordering::SeqCst) {
print_help_message();
PRINTED_YET.store(true, Ordering::SeqCst);
Node::RegionVid(n_vid) =>
dot::LabelText::label(format!("{:?}", n_vid)),
Node::Region(n_rgn) =>
- dot::LabelText::label(format!("{}", n_rgn.repr(self.tcx))),
+ dot::LabelText::label(format!("{:?}", n_rgn)),
}
}
fn edge_label(&self, e: &Edge) -> dot::LabelText {
match *e {
Edge::Constraint(ref c) =>
- dot::LabelText::label(format!("{}", self.map.get(c).unwrap().repr(self.tcx))),
+ dot::LabelText::label(format!("{:?}", self.map.get(c).unwrap())),
Edge::EnclScope(..) =>
dot::LabelText::label(format!("(enclosed)")),
}
use middle::ty_relate::RelateResult;
use util::common::indenter;
use util::nodemap::{FnvHashMap, FnvHashSet};
-use util::ppaux::{Repr, UserString};
use std::cell::{Cell, RefCell};
use std::cmp::Ordering::{self, Less, Greater, Equal};
+use std::fmt;
use std::iter::repeat;
use std::u32;
use syntax::ast;
VerifyGenericBound(GenericKind<'tcx>, SubregionOrigin<'tcx>, Region, Vec<Region>),
}
-#[derive(Clone, Debug, PartialEq, Eq)]
+#[derive(Clone, PartialEq, Eq)]
pub enum GenericKind<'tcx> {
Param(ty::ParamTy),
Projection(ty::ProjectionTy<'tcx>),
if self.in_snapshot() {
self.undo_log.borrow_mut().push(AddVar(vid));
}
- debug!("created new region variable {:?} with origin {}",
- vid, origin.repr(self.tcx));
+ debug!("created new region variable {:?} with origin {:?}",
+ vid, origin);
return vid;
}
// cannot add constraints once regions are resolved
assert!(self.values_are_none());
- debug!("RegionVarBindings: add_constraint({})",
- constraint.repr(self.tcx));
+ debug!("RegionVarBindings: add_constraint({:?})",
+ constraint);
if self.constraints.borrow_mut().insert(constraint, origin).is_none() {
if self.in_snapshot() {
// cannot add verifys once regions are resolved
assert!(self.values_are_none());
- debug!("RegionVarBindings: add_verify({})",
- verify.repr(self.tcx));
+ debug!("RegionVarBindings: add_verify({:?})",
+ verify);
let mut verifys = self.verifys.borrow_mut();
let index = verifys.len();
let mut givens = self.givens.borrow_mut();
if givens.insert((sub, sup)) {
- debug!("add_given({} <= {:?})",
- sub.repr(self.tcx),
+ debug!("add_given({:?} <= {:?})",
+ sub,
sup);
self.undo_log.borrow_mut().push(AddGiven(sub, sup));
// cannot add constraints once regions are resolved
assert!(self.values_are_none());
- debug!("RegionVarBindings: make_subregion({}, {}) due to {}",
- sub.repr(self.tcx),
- sup.repr(self.tcx),
- origin.repr(self.tcx));
+ debug!("RegionVarBindings: make_subregion({:?}, {:?}) due to {:?}",
+ sub,
+ sup,
+ origin);
match (sub, sup) {
(ReEarlyBound(..), ReEarlyBound(..)) => {
(_, ReLateBound(..)) => {
self.tcx.sess.span_bug(
origin.span(),
- &format!("cannot relate bound region: {} <= {}",
- sub.repr(self.tcx),
- sup.repr(self.tcx)));
+ &format!("cannot relate bound region: {:?} <= {:?}",
+ sub,
+ sup));
}
(_, ReStatic) => {
// all regions are subregions of static, so we can ignore this
// cannot add constraints once regions are resolved
assert!(self.values_are_none());
- debug!("RegionVarBindings: lub_regions({}, {})",
- a.repr(self.tcx),
- b.repr(self.tcx));
+ debug!("RegionVarBindings: lub_regions({:?}, {:?})",
+ a,
+ b);
match (a, b) {
(ReStatic, _) | (_, ReStatic) => {
ReStatic // nothing lives longer than static
// cannot add constraints once regions are resolved
assert!(self.values_are_none());
- debug!("RegionVarBindings: glb_regions({}, {})",
- a.repr(self.tcx),
- b.repr(self.tcx));
+ debug!("RegionVarBindings: glb_regions({:?}, {:?})",
+ a,
+ b);
match (a, b) {
(ReStatic, r) | (r, ReStatic) => {
// static lives longer than everything else
}
Some(ref values) => {
let r = lookup(values, rid);
- debug!("resolve_var({:?}) = {}", rid, r.repr(self.tcx));
+ debug!("resolve_var({:?}) = {:?}", rid, r);
r
}
}
/// made---`r0` itself will be the first entry. This is used when checking whether skolemized
/// regions are being improperly related to other regions.
pub fn tainted(&self, mark: &RegionSnapshot, r0: Region) -> Vec<Region> {
- debug!("tainted(mark={:?}, r0={})", mark, r0.repr(self.tcx));
+ debug!("tainted(mark={:?}, r0={:?})", mark, r0);
let _indenter = indenter();
// `result_set` acts as a worklist: we explore all outgoing
(ReEarlyBound(..), _) |
(_, ReEarlyBound(..)) => {
self.tcx.sess.bug(
- &format!("cannot relate bound region: LUB({}, {})",
- a.repr(self.tcx),
- b.repr(self.tcx)));
+ &format!("cannot relate bound region: LUB({:?}, {:?})",
+ a,
+ b));
}
(ReStatic, _) | (_, ReStatic) => {
(ReEarlyBound(..), _) |
(_, ReEarlyBound(..)) => {
self.tcx.sess.bug(
- &format!("cannot relate bound region: GLB({}, {})",
- a.repr(self.tcx),
- b.repr(self.tcx)));
+ &format!("cannot relate bound region: GLB({:?}, {:?})",
+ a,
+ b));
}
(ReStatic, r) | (r, ReStatic) => {
#[derive(Copy, Clone, PartialEq, Debug)]
enum Classification { Expanding, Contracting }
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug)]
pub enum VarValue { NoValue, Value(Region), ErrorValue }
struct VarData {
// Dorky hack to cause `dump_constraints` to only get called
// if debug mode is enabled:
- debug!("----() End constraint listing {:?}---", self.dump_constraints());
+ debug!("----() End constraint listing (subject={}) {:?}---",
+ subject, self.dump_constraints(subject));
graphviz::maybe_print_constraints_for(self, subject);
+ let graph = self.construct_graph();
+ self.expand_givens(&graph);
self.expansion(free_regions, &mut var_data);
self.contraction(free_regions, &mut var_data);
let values =
self.extract_values_and_collect_conflicts(free_regions,
- &var_data[..],
+ &var_data,
+ &graph,
errors);
self.collect_concrete_region_errors(free_regions, &values, errors);
values
}).collect()
}
- fn dump_constraints(&self) {
- debug!("----() Start constraint listing ()----");
+ fn dump_constraints(&self, subject: ast::NodeId) {
+ debug!("----() Start constraint listing (subject={}) ()----", subject);
for (idx, (constraint, _)) in self.constraints.borrow().iter().enumerate() {
- debug!("Constraint {} => {}", idx, constraint.repr(self.tcx));
+ debug!("Constraint {} => {:?}", idx, constraint);
+ }
+ }
+
+ fn expand_givens(&self, graph: &RegionGraph) {
+ // Givens are a kind of horrible hack to account for
+ // constraints like 'c <= '0 that are known to hold due to
+ // closure signatures (see the comment above on the `givens`
+ // field). They should go away. But until they do, the role
+ // of this fn is to account for the transitive nature:
+ //
+ // Given 'c <= '0
+ // and '0 <= '1
+ // then 'c <= '1
+
+ let mut givens = self.givens.borrow_mut();
+ let seeds: Vec<_> = givens.iter().cloned().collect();
+ for (fr, vid) in seeds {
+ let seed_index = NodeIndex(vid.index as usize);
+ for succ_index in graph.depth_traverse(seed_index) {
+ let succ_index = succ_index.0 as u32;
+ if succ_index < self.num_vars() {
+ let succ_vid = RegionVid { index: succ_index };
+ givens.insert((fr, succ_vid));
+ }
+ }
}
}
fn expansion(&self, free_regions: &FreeRegionMap, var_data: &mut [VarData]) {
self.iterate_until_fixed_point("Expansion", |constraint| {
- debug!("expansion: constraint={} origin={}",
- constraint.repr(self.tcx),
+ debug!("expansion: constraint={:?} origin={:?}",
+ constraint,
self.constraints.borrow()
.get(constraint)
.unwrap()
- .repr(self.tcx));
+ );
match *constraint {
ConstrainRegSubVar(a_region, b_vid) => {
let b_data = &mut var_data[b_vid.index as usize];
b_data: &mut VarData)
-> bool
{
- debug!("expand_node({}, {:?} == {})",
- a_region.repr(self.tcx),
+ debug!("expand_node({:?}, {:?} == {:?})",
+ a_region,
b_vid,
- b_data.value.repr(self.tcx));
+ b_data.value);
// Check if this relationship is implied by a given.
match a_region {
b_data.classification = Expanding;
match b_data.value {
NoValue => {
- debug!("Setting initial value of {:?} to {}",
- b_vid, a_region.repr(self.tcx));
+ debug!("Setting initial value of {:?} to {:?}",
+ b_vid, a_region);
b_data.value = Value(a_region);
return true;
return false;
}
- debug!("Expanding value of {:?} from {} to {}",
+ debug!("Expanding value of {:?} from {:?} to {:?}",
b_vid,
- cur_region.repr(self.tcx),
- lub.repr(self.tcx));
+ cur_region,
+ lub);
b_data.value = Value(lub);
return true;
free_regions: &FreeRegionMap,
var_data: &mut [VarData]) {
self.iterate_until_fixed_point("Contraction", |constraint| {
- debug!("contraction: constraint={} origin={}",
- constraint.repr(self.tcx),
+ debug!("contraction: constraint={:?} origin={:?}",
+ constraint,
self.constraints.borrow()
.get(constraint)
.unwrap()
- .repr(self.tcx));
+ );
match *constraint {
ConstrainRegSubVar(..) => {
// This is an expansion constraint. Ignore.
a_data: &mut VarData,
b_region: Region)
-> bool {
- debug!("contract_node({:?} == {}/{:?}, {})",
- a_vid, a_data.value.repr(self.tcx),
- a_data.classification, b_region.repr(self.tcx));
+ debug!("contract_node({:?} == {:?}/{:?}, {:?})",
+ a_vid, a_data.value,
+ a_data.classification, b_region);
return match a_data.value {
NoValue => {
-> bool
{
if !free_regions.is_subregion_of(this.tcx, a_region, b_region) {
- debug!("Setting {:?} to ErrorValue: {} not subregion of {}",
+ debug!("Setting {:?} to ErrorValue: {:?} not subregion of {:?}",
a_vid,
- a_region.repr(this.tcx),
- b_region.repr(this.tcx));
+ a_region,
+ b_region);
a_data.value = ErrorValue;
}
false
if glb == a_region {
false
} else {
- debug!("Contracting value of {:?} from {} to {}",
+ debug!("Contracting value of {:?} from {:?} to {:?}",
a_vid,
- a_region.repr(this.tcx),
- glb.repr(this.tcx));
+ a_region,
+ glb);
a_data.value = Value(glb);
true
}
}
Err(_) => {
- debug!("Setting {:?} to ErrorValue: no glb of {}, {}",
+ debug!("Setting {:?} to ErrorValue: no glb of {:?}, {:?}",
a_vid,
- a_region.repr(this.tcx),
- b_region.repr(this.tcx));
+ a_region,
+ b_region);
a_data.value = ErrorValue;
false
}
errors: &mut Vec<RegionResolutionError<'tcx>>)
{
let mut reg_reg_dups = FnvHashSet();
- for verify in &*self.verifys.borrow() {
+ for verify in self.verifys.borrow().iter() {
match *verify {
VerifyRegSubReg(ref origin, sub, sup) => {
if free_regions.is_subregion_of(self.tcx, sub, sup) {
continue;
}
- debug!("ConcreteFailure: !(sub <= sup): sub={}, sup={}",
- sub.repr(self.tcx),
- sup.repr(self.tcx));
+ debug!("ConcreteFailure: !(sub <= sup): sub={:?}, sup={:?}",
+ sub,
+ sup);
errors.push(ConcreteFailure((*origin).clone(), sub, sup));
}
&self,
free_regions: &FreeRegionMap,
var_data: &[VarData],
+ graph: &RegionGraph,
errors: &mut Vec<RegionResolutionError<'tcx>>)
-> Vec<VarValue>
{
// overlapping locations.
let mut dup_vec: Vec<_> = repeat(u32::MAX).take(self.num_vars() as usize).collect();
- let mut opt_graph = None;
-
for idx in 0..self.num_vars() as usize {
match var_data[idx].value {
Value(_) => {
starts to create problems we'll have to revisit
this portion of the code and think hard about it. =) */
- if opt_graph.is_none() {
- opt_graph = Some(self.construct_graph());
- }
- let graph = opt_graph.as_ref().unwrap();
-
let node_vid = RegionVid { index: idx as u32 };
match var_data[idx].classification {
Expanding => {
}
}
+ // Check for future hostile edges tied to a bad default
+ self.report_future_hostility(&graph);
+
(0..self.num_vars() as usize).map(|idx| var_data[idx].value).collect()
}
+ fn report_future_hostility(&self, graph: &RegionGraph) {
+ let constraints = self.constraints.borrow();
+ for edge in graph.all_edges() {
+ match constraints[&edge.data] {
+ SubregionOrigin::DefaultExistentialBound(_) => {
+ // this will become 'static in the future
+ }
+ _ => { continue; }
+ }
+
+ // this constraint will become a 'static constraint in the
+ // future, so walk outward and see if we have any hard
+ // bounds that could not be inferred to 'static
+ for nid in graph.depth_traverse(edge.target()) {
+ for (_, succ) in graph.outgoing_edges(nid) {
+ match succ.data {
+ ConstrainVarSubReg(_, r) => {
+ match r {
+ ty::ReStatic | ty::ReInfer(_) => {
+ /* OK */
+ }
+ ty::ReFree(_) | ty::ReScope(_) | ty::ReEmpty => {
+ span_warn!(
+ self.tcx.sess,
+ constraints[&edge.data].span(),
+ E0398,
+ "this code may fail to compile in Rust 1.3 due to \
+ the proposed change in object lifetime bound defaults");
+ return; // only issue the warning once per fn
+ }
+ ty::ReEarlyBound(..) | ty::ReLateBound(..) => {
+ self.tcx.sess.span_bug(
+ constraints[&succ.data].span(),
+ "relation to bound region");
+ }
+ }
+ }
+ _ => { }
+ }
+ }
+ }
+ }
+ }
+
fn construct_graph(&self) -> RegionGraph {
let num_vars = self.num_vars();
}
let dummy_idx = graph.add_node(());
- for (constraint, _) in &*constraints {
+ for (constraint, _) in constraints.iter() {
match *constraint {
ConstrainVarSubVar(a_id, b_id) => {
graph.add_edge(NodeIndex(a_id.index as usize),
self.tcx.sess.span_bug(
(*self.var_origins.borrow())[node_idx.index as usize].span(),
&format!("collect_error_for_expanding_node() could not find error \
- for var {:?}, lower_bounds={}, upper_bounds={}",
+ for var {:?}, lower_bounds={:?}, upper_bounds={:?}",
node_idx,
- lower_bounds.repr(self.tcx),
- upper_bounds.repr(self.tcx)));
+ lower_bounds,
+ upper_bounds));
}
fn collect_error_for_contracting_node(
self.tcx.sess.span_bug(
(*self.var_origins.borrow())[node_idx.index as usize].span(),
&format!("collect_error_for_contracting_node() could not find error \
- for var {:?}, upper_bounds={}",
+ for var {:?}, upper_bounds={:?}",
node_idx,
- upper_bounds.repr(self.tcx)));
+ upper_bounds));
}
fn collect_concrete_regions(&self,
changed = false;
iteration += 1;
debug!("---- {} Iteration {}{}", "#", tag, iteration);
- for (constraint, _) in &*self.constraints.borrow() {
+ for (constraint, _) in self.constraints.borrow().iter() {
let edge_changed = body(constraint);
if edge_changed {
- debug!("Updated due to constraint {}",
- constraint.repr(self.tcx));
+ debug!("Updated due to constraint {:?}",
+ constraint);
changed = true;
}
}
}
-impl<'tcx> Repr<'tcx> for Constraint {
- fn repr(&self, tcx: &ty::ctxt) -> String {
- match *self {
- ConstrainVarSubVar(a, b) => {
- format!("ConstrainVarSubVar({}, {})", a.repr(tcx), b.repr(tcx))
- }
- ConstrainRegSubVar(a, b) => {
- format!("ConstrainRegSubVar({}, {})", a.repr(tcx), b.repr(tcx))
- }
- ConstrainVarSubReg(a, b) => {
- format!("ConstrainVarSubReg({}, {})", a.repr(tcx), b.repr(tcx))
- }
- }
- }
-}
-
-impl<'tcx> Repr<'tcx> for Verify<'tcx> {
- fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
+impl<'tcx> fmt::Debug for Verify<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
VerifyRegSubReg(_, ref a, ref b) => {
- format!("VerifyRegSubReg({}, {})", a.repr(tcx), b.repr(tcx))
+ write!(f, "VerifyRegSubReg({:?}, {:?})", a, b)
}
VerifyGenericBound(_, ref p, ref a, ref bs) => {
- format!("VerifyGenericBound({}, {}, {})",
- p.repr(tcx), a.repr(tcx), bs.repr(tcx))
+ write!(f, "VerifyGenericBound({:?}, {:?}, {:?})", p, a, bs)
}
}
}
}
}
-impl<'tcx> Repr<'tcx> for VarValue {
- fn repr(&self, tcx: &ty::ctxt) -> String {
- match *self {
- NoValue => format!("NoValue"),
- Value(r) => format!("Value({})", r.repr(tcx)),
- ErrorValue => format!("ErrorValue"),
- }
- }
-}
-
-impl<'tcx> Repr<'tcx> for RegionAndOrigin<'tcx> {
- fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
- format!("RegionAndOrigin({},{})",
- self.region.repr(tcx),
- self.origin.repr(tcx))
+impl<'tcx> fmt::Debug for RegionAndOrigin<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "RegionAndOrigin({:?},{:?})",
+ self.region,
+ self.origin)
}
}
-impl<'tcx> Repr<'tcx> for GenericKind<'tcx> {
- fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
+impl<'tcx> fmt::Debug for GenericKind<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
- GenericKind::Param(ref p) => p.repr(tcx),
- GenericKind::Projection(ref p) => p.repr(tcx),
+ GenericKind::Param(ref p) => write!(f, "{:?}", p),
+ GenericKind::Projection(ref p) => write!(f, "{:?}", p),
}
}
}
-impl<'tcx> UserString<'tcx> for GenericKind<'tcx> {
- fn user_string(&self, tcx: &ty::ctxt<'tcx>) -> String {
+impl<'tcx> fmt::Display for GenericKind<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
- GenericKind::Param(ref p) => p.user_string(tcx),
- GenericKind::Projection(ref p) => p.user_string(tcx),
+ GenericKind::Param(ref p) => write!(f, "{}", p),
+ GenericKind::Projection(ref p) => write!(f, "{}", p),
}
}
}
use super::{InferCtxt, fixup_err, fres, unresolved_ty, unresolved_int_ty, unresolved_float_ty};
use middle::ty::{self, Ty};
use middle::ty_fold::{self, TypeFoldable};
-use util::ppaux::Repr;
///////////////////////////////////////////////////////////////////////////
// OPPORTUNISTIC TYPE RESOLVER
} else {
let t = self.infcx.shallow_resolve(t);
match t.sty {
- ty::ty_infer(ty::TyVar(vid)) => {
+ ty::TyInfer(ty::TyVar(vid)) => {
self.err = Some(unresolved_ty(vid));
self.tcx().types.err
}
- ty::ty_infer(ty::IntVar(vid)) => {
+ ty::TyInfer(ty::IntVar(vid)) => {
self.err = Some(unresolved_int_ty(vid));
self.tcx().types.err
}
- ty::ty_infer(ty::FloatVar(vid)) => {
+ ty::TyInfer(ty::FloatVar(vid)) => {
self.err = Some(unresolved_float_ty(vid));
self.tcx().types.err
}
- ty::ty_infer(_) => {
+ ty::TyInfer(_) => {
self.infcx.tcx.sess.bug(
- &format!("Unexpected type in full type resolver: {}",
- t.repr(self.infcx.tcx)));
+ &format!("Unexpected type in full type resolver: {:?}",
+ t));
}
_ => {
ty_fold::super_fold_ty(self, t)
use super::combine::{self, CombineFields};
use super::higher_ranked::HigherRankedRelations;
-use super::Subtype;
+use super::SubregionOrigin;
use super::type_variable::{SubtypeOf, SupertypeOf};
use middle::ty::{self, Ty};
use middle::ty::TyVar;
-use middle::ty_relate::{Relate, RelateResult, TypeRelation};
-use util::ppaux::{Repr};
+use middle::ty_relate::{Cause, Relate, RelateResult, TypeRelation};
+use std::mem;
/// "Greatest lower bound" (common subtype)
pub struct Sub<'a, 'tcx: 'a> {
- fields: CombineFields<'a, 'tcx>
+ fields: CombineFields<'a, 'tcx>,
}
impl<'a, 'tcx> Sub<'a, 'tcx> {
fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.fields.infcx.tcx }
fn a_is_expected(&self) -> bool { self.fields.a_is_expected }
+ fn with_cause<F,R>(&mut self, cause: Cause, f: F) -> R
+ where F: FnOnce(&mut Self) -> R
+ {
+ debug!("sub with_cause={:?}", cause);
+ let old_cause = mem::replace(&mut self.fields.cause, Some(cause));
+ let r = f(self);
+ debug!("sub old_cause={:?}", old_cause);
+ self.fields.cause = old_cause;
+ r
+ }
+
+ fn will_change(&mut self, a: bool, b: bool) -> bool {
+ // if we have (Foo+'a) <: (Foo+'b), this requires that 'a:'b.
+ // So if 'a becomes 'static, no additional errors can occur.
+ // OTOH, if 'a stays the same, but 'b becomes 'static, we
+ // could have a problem.
+ !a && b
+ }
+
fn relate_with_variance<T:Relate<'a,'tcx>>(&mut self,
variance: ty::Variance,
a: &T,
}
fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
- debug!("{}.tys({}, {})", self.tag(), a.repr(self.tcx()), b.repr(self.tcx()));
+ debug!("{}.tys({:?}, {:?})", self.tag(), a, b);
if a == b { return Ok(a); }
let a = infcx.type_variables.borrow().replace_if_possible(a);
let b = infcx.type_variables.borrow().replace_if_possible(b);
match (&a.sty, &b.sty) {
- (&ty::ty_infer(TyVar(a_id)), &ty::ty_infer(TyVar(b_id))) => {
+ (&ty::TyInfer(TyVar(a_id)), &ty::TyInfer(TyVar(b_id))) => {
infcx.type_variables
.borrow_mut()
.relate_vars(a_id, SubtypeOf, b_id);
Ok(a)
}
- (&ty::ty_infer(TyVar(a_id)), _) => {
+ (&ty::TyInfer(TyVar(a_id)), _) => {
try!(self.fields
.switch_expected()
.instantiate(b, SupertypeOf, a_id));
Ok(a)
}
- (_, &ty::ty_infer(TyVar(b_id))) => {
+ (_, &ty::TyInfer(TyVar(b_id))) => {
try!(self.fields.instantiate(a, SubtypeOf, b_id));
Ok(a)
}
- (&ty::ty_err, _) | (_, &ty::ty_err) => {
+ (&ty::TyError, _) | (_, &ty::TyError) => {
Ok(self.tcx().types.err)
}
}
fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> {
- debug!("{}.regions({}, {})",
- self.tag(),
- a.repr(self.tcx()),
- b.repr(self.tcx()));
- let origin = Subtype(self.fields.trace.clone());
+ debug!("{}.regions({:?}, {:?}) self.cause={:?}",
+ self.tag(), a, b, self.fields.cause);
+ let origin = match self.fields.cause {
+ Some(Cause::ExistentialRegionBound(true)) =>
+ SubregionOrigin::DefaultExistentialBound(self.fields.trace.clone()),
+ _ =>
+ SubregionOrigin::Subtype(self.fields.trace.clone()),
+ };
self.fields.infcx.region_vars.make_subregion(origin, a, b);
Ok(a)
}
pub fn replace_if_possible(&self, t: Ty<'tcx>) -> Ty<'tcx> {
match t.sty {
- ty::ty_infer(ty::TyVar(v)) => {
+ ty::TyInfer(ty::TyVar(v)) => {
match self.probe(v) {
None => t,
Some(u) => u
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use ast_map::NodeForeignItem;
use metadata::csearch;
use middle::def::DefFn;
use middle::subst::{Subst, Substs, EnumeratedItems};
-use middle::ty::{TransmuteRestriction, ctxt, ty_bare_fn};
+use middle::ty::{TransmuteRestriction, ctxt, TyBareFn};
use middle::ty::{self, Ty};
-use util::ppaux::Repr;
+
+use std::fmt;
use syntax::abi::RustIntrinsic;
use syntax::ast::DefId;
use syntax::ast;
-use syntax::ast_map::NodeForeignItem;
use syntax::codemap::Span;
use syntax::parse::token;
use syntax::visit::Visitor;
impl<'a, 'tcx> IntrinsicCheckingVisitor<'a, 'tcx> {
fn def_id_is_transmute(&self, def_id: DefId) -> bool {
let intrinsic = match ty::lookup_item_type(self.tcx, def_id).ty.sty {
- ty::ty_bare_fn(_, ref bfty) => bfty.abi == RustIntrinsic,
+ ty::TyBareFn(_, ref bfty) => bfty.abi == RustIntrinsic,
_ => return false
};
if def_id.krate == ast::LOCAL_CRATE {
match types_in_scope.next() {
None => {
- debug!("with_each_combination(substs={})",
- substs.repr(self.tcx));
+ debug!("with_each_combination(substs={:?})",
+ substs);
callback(substs);
}
Some((space, index, ¶m_ty)) => {
- debug!("with_each_combination: space={:?}, index={}, param_ty={}",
- space, index, param_ty.repr(self.tcx));
+ debug!("with_each_combination: space={:?}, index={}, param_ty={:?}",
+ space, index, param_ty);
- if !ty::type_is_sized(param_env, span, param_ty) {
+ if !ty::type_is_sized(Some(param_env), self.tcx, span, param_ty) {
debug!("with_each_combination: param_ty is not known to be sized");
substs.types.get_mut_slice(space)[index] = self.dummy_unsized_ty;
}
fn push_transmute_restriction(&self, restriction: TransmuteRestriction<'tcx>) {
- debug!("Pushing transmute restriction: {}", restriction.repr(self.tcx));
+ debug!("Pushing transmute restriction: {:?}", restriction);
self.tcx.transmute_restrictions.borrow_mut().push(restriction);
}
}
DefFn(did, _) if self.def_id_is_transmute(did) => {
let typ = ty::node_id_to_type(self.tcx, expr.id);
match typ.sty {
- ty_bare_fn(_, ref bare_fn_ty) if bare_fn_ty.abi == RustIntrinsic => {
+ TyBareFn(_, ref bare_fn_ty) if bare_fn_ty.abi == RustIntrinsic => {
if let ty::FnConverging(to) = bare_fn_ty.sig.0.output {
let from = bare_fn_ty.sig.0.inputs[0];
self.check_transmute(expr.span, from, to, expr.id);
}
}
-impl<'tcx> Repr<'tcx> for TransmuteRestriction<'tcx> {
- fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
- format!("TransmuteRestriction(id={}, original=({},{}), substituted=({},{}))",
- self.id,
- self.original_from.repr(tcx),
- self.original_to.repr(tcx),
- self.substituted_from.repr(tcx),
- self.substituted_to.repr(tcx))
+impl<'tcx> fmt::Debug for TransmuteRestriction<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "TransmuteRestriction(id={}, original=({:?},{:?}), substituted=({:?},{:?}))",
+ self.id,
+ self.original_from,
+ self.original_to,
+ self.substituted_from,
+ self.substituted_to)
}
}
fn fn_ret(&self, id: NodeId) -> ty::PolyFnOutput<'tcx> {
let fn_ty = ty::node_id_to_type(self.ir.tcx, id);
match fn_ty.sty {
- ty::ty_closure(closure_def_id, substs) =>
+ ty::TyClosure(closure_def_id, substs) =>
self.ir.tcx.closure_type(closure_def_id, substs).sig.output(),
_ =>
ty::ty_fn_ret(fn_ty),
pub use self::FieldName::*;
pub use self::ElementKind::*;
pub use self::MutabilityCategory::*;
-pub use self::InteriorSafety::*;
pub use self::AliasableReason::*;
pub use self::Note::*;
pub use self::deref_kind::*;
use self::Aliasability::*;
+use ast_map;
use middle::check_const;
use middle::def;
use middle::region;
use middle::ty::{self, Ty};
use util::nodemap::NodeMap;
-use util::ppaux::{Repr, UserString};
use syntax::ast::{MutImmutable, MutMutable};
use syntax::ast;
-use syntax::ast_map;
use syntax::codemap::Span;
-use syntax::print::pprust;
-use syntax::parse::token;
use std::cell::RefCell;
+use std::fmt;
use std::rc::Rc;
-#[derive(Clone, PartialEq, Debug)]
+#[derive(Clone, PartialEq)]
pub enum categorization<'tcx> {
cat_rvalue(ty::Region), // temporary val, argument is its scope
cat_static_item,
}
// Represents any kind of upvar
-#[derive(Clone, Copy, PartialEq, Debug)]
+#[derive(Clone, Copy, PartialEq)]
pub struct Upvar {
pub id: ty::UpvarId,
pub kind: ty::ClosureKind
}
// different kinds of pointers:
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub enum PointerKind {
/// `Box<T>`
Unique,
// We use the term "interior" to mean "something reachable from the
// base without a pointer dereference", e.g. a field
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub enum InteriorKind {
InteriorField(FieldName),
InteriorElement(InteriorOffsetKind, ElementKind),
// dereference, but its type is the type *before* the dereference
// (`@T`). So use `cmt.ty` to find the type of the value in a consistent
// fashion. For more details, see the method `cat_pattern`
-#[derive(Clone, PartialEq, Debug)]
+#[derive(Clone, PartialEq)]
pub struct cmt_<'tcx> {
pub id: ast::NodeId, // id of expr/pat producing this value
pub span: Span, // span of same expr/pat
// pointer adjustment).
fn deref_kind(t: Ty, context: DerefKindContext) -> McResult<deref_kind> {
match t.sty {
- ty::ty_uniq(_) => {
+ ty::TyBox(_) => {
Ok(deref_ptr(Unique))
}
- ty::ty_rptr(r, mt) => {
+ ty::TyRef(r, mt) => {
let kind = ty::BorrowKind::from_mutbl(mt.mutbl);
Ok(deref_ptr(BorrowedPtr(kind, *r)))
}
- ty::ty_ptr(ref mt) => {
+ ty::TyRawPtr(ref mt) => {
Ok(deref_ptr(UnsafePtr(mt.mutbl)))
}
- ty::ty_enum(..) |
- ty::ty_struct(..) => { // newtype
+ ty::TyEnum(..) |
+ ty::TyStruct(..) => { // newtype
Ok(deref_interior(InteriorField(PositionalField(0))))
}
- ty::ty_vec(_, _) | ty::ty_str => {
+ ty::TyArray(_, _) | ty::TySlice(_) | ty::TyStr => {
// no deref of indexed content without supplying InteriorOffsetKind
if let Some(context) = context {
Ok(deref_interior(InteriorElement(context, element_kind(t))))
}
fn pat_ty(&self, pat: &ast::Pat) -> McResult<Ty<'tcx>> {
- let tcx = self.typer.tcx();
let base_ty = try!(self.typer.node_ty(pat.id));
// FIXME (Issue #18207): This code detects whether we are
// looking at a `ref x`, and if so, figures out what the type
}
_ => base_ty,
};
- debug!("pat_ty(pat={}) base_ty={} ret_ty={}",
- pat.repr(tcx), base_ty.repr(tcx), ret_ty.repr(tcx));
+ debug!("pat_ty(pat={:?}) base_ty={:?} ret_ty={:?}",
+ pat, base_ty, ret_ty);
Ok(ret_ty)
}
ty::AdjustReifyFnPointer |
ty::AdjustUnsafeFnPointer |
ty::AdjustDerefRef(_) => {
- debug!("cat_expr({}): {}",
- adjustment.repr(self.tcx()),
- expr.repr(self.tcx()));
+ debug!("cat_expr({:?}): {:?}",
+ adjustment,
+ expr);
// Result is an rvalue.
let expr_ty = try!(self.expr_ty_adjusted(expr));
Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty))
autoderefs: usize)
-> McResult<cmt<'tcx>> {
let mut cmt = try!(self.cat_expr_unadjusted(expr));
- debug!("cat_expr_autoderefd: autoderefs={}, cmt={}",
+ debug!("cat_expr_autoderefd: autoderefs={}, cmt={:?}",
autoderefs,
- cmt.repr(self.tcx()));
+ cmt);
for deref in 1..autoderefs + 1 {
cmt = try!(self.cat_deref(expr, cmt, deref, None));
}
}
pub fn cat_expr_unadjusted(&self, expr: &ast::Expr) -> McResult<cmt<'tcx>> {
- debug!("cat_expr: id={} expr={}", expr.id, expr.repr(self.tcx()));
+ debug!("cat_expr: id={} expr={:?}", expr.id, expr);
let expr_ty = try!(self.expr_ty(expr));
match expr.node {
ast::ExprField(ref base, f_name) => {
let base_cmt = try!(self.cat_expr(&**base));
- debug!("cat_expr(cat_field): id={} expr={} base={}",
+ debug!("cat_expr(cat_field): id={} expr={:?} base={:?}",
expr.id,
- expr.repr(self.tcx()),
- base_cmt.repr(self.tcx()));
+ expr,
+ base_cmt);
Ok(self.cat_field(expr, base_cmt, f_name.node.name, expr_ty))
}
// The index method always returns an `&T`, so
// dereference it to find the result type.
let elem_ty = match ret_ty.sty {
- ty::ty_rptr(_, mt) => mt.ty,
+ ty::TyRef(_, mt) => mt.ty,
_ => {
- debug!("cat_expr_unadjusted: return type of overloaded index is {}?",
- ret_ty.repr(self.tcx()));
+ debug!("cat_expr_unadjusted: return type of overloaded index is {:?}?",
+ ret_ty);
return Err(());
}
};
expr_ty: Ty<'tcx>,
def: def::Def)
-> McResult<cmt<'tcx>> {
- debug!("cat_def: id={} expr={} def={:?}",
- id, expr_ty.repr(self.tcx()), def);
+ debug!("cat_def: id={} expr={:?} def={:?}",
+ id, expr_ty, def);
match def {
def::DefStruct(..) | def::DefVariant(..) | def::DefConst(..) |
def::DefUpvar(var_id, fn_node_id) => {
let ty = try!(self.node_ty(fn_node_id));
match ty.sty {
- ty::ty_closure(closure_id, _) => {
+ ty::TyClosure(closure_id, _) => {
match self.typer.closure_kind(closure_id) {
Some(kind) => {
self.cat_upvar(id, span, var_id, fn_node_id, kind)
_ => {
self.tcx().sess.span_bug(
span,
- &format!("Upvar of non-closure {} - {}",
+ &format!("Upvar of non-closure {} - {:?}",
fn_node_id,
- ty.repr(self.tcx())));
+ ty));
}
}
}
};
let ret = Rc::new(cmt_result);
- debug!("cat_upvar ret={}", ret.repr(self.tcx()));
+ debug!("cat_upvar ret={:?}", ret);
Ok(ret)
}
// that the above is actually immutable and
// has a ref type. However, nothing should
// actually look at the type, so we can get
- // away with stuffing a `ty_err` in there
+ // away with stuffing a `TyError` in there
// instead of bothering to construct a proper
// one.
let cmt_result = cmt_ {
note: NoteClosureEnv(upvar_id)
};
- debug!("env_deref ret {}", ret.repr(self.tcx()));
+ debug!("env_deref ret {:?}", ret);
ret
}
// Only promote `[T; 0]` before an RFC for rvalue promotions
// is accepted.
let qualif = match expr_ty.sty {
- ty::ty_vec(_, Some(0)) => qualif,
+ ty::TyArray(_, 0) => qualif,
_ => check_const::ConstQualif::NOT_CONST
};
ty::ReStatic
};
let ret = self.cat_rvalue(id, span, re, expr_ty);
- debug!("cat_rvalue_node ret {}", ret.repr(self.tcx()));
+ debug!("cat_rvalue_node ret {:?}", ret);
ret
}
ty:expr_ty,
note: NoteNone
});
- debug!("cat_rvalue ret {}", ret.repr(self.tcx()));
+ debug!("cat_rvalue ret {:?}", ret);
ret
}
ty: f_ty,
note: NoteNone
});
- debug!("cat_field ret {}", ret.repr(self.tcx()));
+ debug!("cat_field ret {:?}", ret);
ret
}
ty: f_ty,
note: NoteNone
});
- debug!("cat_tup_field ret {}", ret.repr(self.tcx()));
+ debug!("cat_tup_field ret {:?}", ret);
ret
}
let method_ty = self.typer.node_method_ty(method_call);
debug!("cat_deref: method_call={:?} method_ty={:?}",
- method_call, method_ty.map(|ty| ty.repr(self.tcx())));
+ method_call, method_ty.map(|ty| ty));
let base_cmt = match method_ty {
Some(method_ty) => {
mt.ty,
deref_context,
/* implicit: */ false);
- debug!("cat_deref ret {}", ret.repr(self.tcx()));
+ debug!("cat_deref ret {:?}", ret);
ret
}
None => {
- debug!("Explicit deref of non-derefable type: {}",
- base_cmt_ty.repr(self.tcx()));
+ debug!("Explicit deref of non-derefable type: {:?}",
+ base_cmt_ty);
return Err(());
}
}
ty: deref_ty,
note: NoteNone
});
- debug!("cat_deref_common ret {}", ret.repr(self.tcx()));
+ debug!("cat_deref_common ret {:?}", ret);
Ok(ret)
}
let m = base_cmt.mutbl.inherit();
let ret = interior(elt, base_cmt.clone(), base_cmt.ty,
m, context, element_ty);
- debug!("cat_index ret {}", ret.repr(self.tcx()));
+ debug!("cat_index ret {:?}", ret);
return Ok(ret);
fn interior<'tcx, N: ast_node>(elt: &N,
base_cmt
}
};
- debug!("deref_vec ret {}", ret.repr(self.tcx()));
+ debug!("deref_vec ret {:?}", ret);
Ok(ret)
}
slice_ty: Ty)
-> (ast::Mutability, ty::Region) {
match slice_ty.sty {
- ty::ty_rptr(r, ref mt) => match mt.ty.sty {
- ty::ty_vec(_, None) => (mt.mutbl, *r),
+ ty::TyRef(r, ref mt) => match mt.ty.sty {
+ ty::TySlice(_) => (mt.mutbl, *r),
_ => vec_slice_info(tcx, pat, mt.ty),
},
ty: interior_ty,
note: NoteNone
});
- debug!("cat_imm_interior ret={}", ret.repr(self.tcx()));
+ debug!("cat_imm_interior ret={:?}", ret);
ret
}
ty: downcast_ty,
note: NoteNone
});
- debug!("cat_downcast ret={}", ret.repr(self.tcx()));
+ debug!("cat_downcast ret={:?}", ret);
ret
}
// step out of sync again. So you'll see below that we always
// get the type of the *subpattern* and use that.
- debug!("cat_pattern: id={} pat={} cmt={}",
- pat.id, pprust::pat_to_string(pat),
- cmt.repr(self.tcx()));
+ debug!("cat_pattern: {:?} cmt={:?}",
+ pat,
+ cmt);
(*op)(self, cmt.clone(), pat);
}
}
-#[derive(Copy, Clone, Debug)]
-pub enum InteriorSafety {
- InteriorUnsafe,
- InteriorSafe
-}
-
#[derive(Clone, Debug)]
pub enum Aliasability {
FreelyAliasable(AliasableReason),
AliasableClosure(ast::NodeId), // Aliasable due to capture Fn closure env
AliasableOther,
UnaliasableImmutable, // Created as needed upon seeing ImmutableUnique
- AliasableStatic(InteriorSafety),
- AliasableStaticMut(InteriorSafety),
+ AliasableStatic,
+ AliasableStaticMut,
}
impl<'tcx> cmt_<'tcx> {
pub fn guarantor(&self) -> cmt<'tcx> {
- //! Returns `self` after stripping away any owned pointer derefs or
+ //! Returns `self` after stripping away any derefs or
//! interior content. The return value is basically the `cmt` which
//! determines how long the value in `self` remains live.
}
cat_static_item(..) => {
- let int_safe = if ty::type_interior_is_unsafe(ctxt, self.ty) {
- InteriorUnsafe
- } else {
- InteriorSafe
- };
-
if self.mutbl.is_mutable() {
- FreelyAliasable(AliasableStaticMut(int_safe))
+ FreelyAliasable(AliasableStaticMut)
} else {
- FreelyAliasable(AliasableStatic(int_safe))
+ FreelyAliasable(AliasableStatic)
}
}
let upvar = self.upvar();
match upvar.as_ref().map(|i| &i.cat) {
Some(&cat_upvar(ref var)) => {
- var.user_string(tcx)
+ var.to_string()
}
Some(_) => unreachable!(),
None => {
format!("`Box` content")
}
UnsafePtr(..) => {
- format!("dereference of unsafe pointer")
+ format!("dereference of raw pointer")
}
BorrowedPtr(..) => {
format!("borrowed content")
"pattern-bound indexed content".to_string()
}
cat_upvar(ref var) => {
- var.user_string(tcx)
+ var.to_string()
}
cat_downcast(ref cmt, _) => {
cmt.descriptive_string(tcx)
}
}
-impl<'tcx> Repr<'tcx> for cmt_<'tcx> {
- fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
- format!("{{{} id:{} m:{:?} ty:{}}}",
- self.cat.repr(tcx),
- self.id,
- self.mutbl,
- self.ty.repr(tcx))
+impl<'tcx> fmt::Debug for cmt_<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{{{:?} id:{} m:{:?} ty:{:?}}}",
+ self.cat,
+ self.id,
+ self.mutbl,
+ self.ty)
}
}
-impl<'tcx> Repr<'tcx> for categorization<'tcx> {
- fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
+impl<'tcx> fmt::Debug for categorization<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
- cat_static_item |
- cat_rvalue(..) |
- cat_local(..) |
- cat_upvar(..) => {
- format!("{:?}", *self)
+ cat_static_item => write!(f, "static"),
+ cat_rvalue(r) => write!(f, "rvalue({:?})", r),
+ cat_local(id) => {
+ let name = ty::tls::with(|tcx| ty::local_var_name_str(tcx, id));
+ write!(f, "local({})", name)
+ }
+ cat_upvar(upvar) => {
+ write!(f, "upvar({:?})", upvar)
}
cat_deref(ref cmt, derefs, ptr) => {
- format!("{}-{}{}->", cmt.cat.repr(tcx), ptr.repr(tcx), derefs)
+ write!(f, "{:?}-{:?}{}->", cmt.cat, ptr, derefs)
}
cat_interior(ref cmt, interior) => {
- format!("{}.{}", cmt.cat.repr(tcx), interior.repr(tcx))
+ write!(f, "{:?}.{:?}", cmt.cat, interior)
}
cat_downcast(ref cmt, _) => {
- format!("{}->(enum)", cmt.cat.repr(tcx))
+ write!(f, "{:?}->(enum)", cmt.cat)
}
}
}
}
}
-impl<'tcx> Repr<'tcx> for PointerKind {
- fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
+impl fmt::Debug for PointerKind {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
- Unique => {
- format!("Box")
- }
+ Unique => write!(f, "Box"),
BorrowedPtr(ty::ImmBorrow, ref r) |
Implicit(ty::ImmBorrow, ref r) => {
- format!("&{}", r.repr(tcx))
+ write!(f, "&{:?}", r)
}
BorrowedPtr(ty::MutBorrow, ref r) |
Implicit(ty::MutBorrow, ref r) => {
- format!("&{} mut", r.repr(tcx))
+ write!(f, "&{:?} mut", r)
}
BorrowedPtr(ty::UniqueImmBorrow, ref r) |
Implicit(ty::UniqueImmBorrow, ref r) => {
- format!("&{} uniq", r.repr(tcx))
- }
- UnsafePtr(_) => {
- format!("*")
+ write!(f, "&{:?} uniq", r)
}
+ UnsafePtr(_) => write!(f, "*")
}
}
}
-impl<'tcx> Repr<'tcx> for InteriorKind {
- fn repr(&self, _tcx: &ty::ctxt) -> String {
+impl fmt::Debug for InteriorKind {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
- InteriorField(NamedField(fld)) => {
- token::get_name(fld).to_string()
- }
- InteriorField(PositionalField(i)) => format!("#{}", i),
- InteriorElement(..) => "[]".to_string(),
+ InteriorField(NamedField(fld)) => write!(f, "{}", fld),
+ InteriorField(PositionalField(i)) => write!(f, "#{}", i),
+ InteriorElement(..) => write!(f, "[]"),
}
}
}
fn element_kind(t: Ty) -> ElementKind {
match t.sty {
- ty::ty_rptr(_, ty::mt{ty, ..}) |
- ty::ty_uniq(ty) => match ty.sty {
- ty::ty_vec(_, None) => VecElement,
+ ty::TyRef(_, ty::mt{ty, ..}) |
+ ty::TyBox(ty) => match ty.sty {
+ ty::TySlice(_) => VecElement,
_ => OtherElement
},
- ty::ty_vec(..) => VecElement,
+ ty::TyArray(..) | ty::TySlice(_) => VecElement,
_ => OtherElement
}
}
-impl<'tcx> Repr<'tcx> for ty::ClosureKind {
- fn repr(&self, _: &ty::ctxt) -> String {
- format!("Upvar({:?})", self)
- }
-}
-
-impl<'tcx> Repr<'tcx> for Upvar {
- fn repr(&self, tcx: &ty::ctxt) -> String {
- format!("Upvar({})", self.kind.repr(tcx))
+impl fmt::Debug for Upvar {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{:?}/{:?}", self.id, self.kind)
}
}
-impl<'tcx> UserString<'tcx> for Upvar {
- fn user_string(&self, _: &ty::ctxt) -> String {
+impl fmt::Display for Upvar {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let kind = match self.kind {
ty::FnClosureKind => "Fn",
ty::FnMutClosureKind => "FnMut",
ty::FnOnceClosureKind => "FnOnce",
};
- format!("captured outer variable in an `{}` closure", kind)
+ write!(f, "captured outer variable in an `{}` closure", kind)
}
}
contains_bindings
}
-/// Checks if the pattern contains any `ref` or `ref mut` bindings.
-pub fn pat_contains_ref_binding(dm: &DefMap, pat: &ast::Pat) -> bool {
- let mut result = false;
+/// Checks if the pattern contains any `ref` or `ref mut` bindings,
+/// and if yes wether its containing mutable ones or just immutables ones.
+pub fn pat_contains_ref_binding(dm: &DefMap, pat: &ast::Pat) -> Option<ast::Mutability> {
+ let mut result = None;
pat_bindings(dm, pat, |mode, _, _, _| {
match mode {
- ast::BindingMode::BindByRef(_) => { result = true; }
+ ast::BindingMode::BindByRef(m) => {
+ // Pick Mutable as maximum
+ match result {
+ None | Some(ast::MutImmutable) => result = Some(m),
+ _ => (),
+ }
+ }
ast::BindingMode::BindByValue(_) => { }
}
});
}
/// Checks if the patterns for this arm contain any `ref` or `ref mut`
-/// bindings.
-pub fn arm_contains_ref_binding(dm: &DefMap, arm: &ast::Arm) -> bool {
- arm.pats.iter().any(|pat| pat_contains_ref_binding(dm, pat))
+/// bindings, and if yes wether its containing mutable ones or just immutables ones.
+pub fn arm_contains_ref_binding(dm: &DefMap, arm: &ast::Arm) -> Option<ast::Mutability> {
+ arm.pats.iter()
+ .filter_map(|pat| pat_contains_ref_binding(dm, pat))
+ .max_by(|m| match *m {
+ ast::MutMutable => 1,
+ ast::MutImmutable => 0,
+ })
}
/// Checks if the pattern contains any patterns that bind something to
span: DUMMY_SP,
})
}
+
+/// Return variants that are necessary to exist for the pattern to match.
+pub fn necessary_variants(dm: &DefMap, pat: &ast::Pat) -> Vec<ast::NodeId> {
+ let mut variants = vec![];
+ walk_pat(pat, |p| {
+ match p.node {
+ ast::PatEnum(_, _) |
+ ast::PatIdent(_, _, None) |
+ ast::PatStruct(..) => {
+ match dm.borrow().get(&p.id) {
+ Some(&PathResolution { base_def: DefVariant(_, id, _), .. }) => {
+ variants.push(id.node);
+ }
+ _ => ()
+ }
+ }
+ _ => ()
+ }
+ true
+ });
+ variants.sort();
+ variants.dedup();
+ variants
+}
// makes all other generics or inline functions that it references
// reachable as well.
+use ast_map;
use middle::def;
use middle::ty;
use middle::privacy;
use std::collections::HashSet;
use syntax::abi;
use syntax::ast;
-use syntax::ast_map;
use syntax::ast_util::is_local;
use syntax::attr;
use syntax::visit::Visitor;
match item.node {
ast::ItemImpl(_, _, ref generics, _, _, _) |
- ast::ItemFn(_, _, _, ref generics, _) => {
+ ast::ItemFn(_, _, _, _, ref generics, _) => {
generics_require_inlining(generics)
}
_ => false,
// but all other rust-only interfaces can be private (they will not
// participate in linkage after this product is produced)
if let ast_map::NodeItem(item) = *node {
- if let ast::ItemFn(_, _, abi, _, _) = item.node {
+ if let ast::ItemFn(_, _, _, abi, _, _) = item.node {
if abi != abi::Rust {
self.reachable_symbols.insert(search_item);
}
match *node {
ast_map::NodeItem(item) => {
match item.node {
- ast::ItemFn(_, _, _, _, ref search_block) => {
+ ast::ItemFn(_, _, _, _, _, ref search_block) => {
if item_might_be_inlined(&*item) {
visit::walk_block(self, &**search_block)
}
// this properly would result in the necessity of computing *type*
// reachability, which might result in a compile time loss.
fn mark_destructors_reachable(&mut self) {
- for (_, destructor_def_id) in &*self.tcx.destructor_for_type.borrow() {
+ for (_, destructor_def_id) in self.tcx.destructor_for_type.borrow().iter() {
if destructor_def_id.krate == ast::LOCAL_CRATE {
self.reachable_symbols.insert(destructor_def_id.node);
}
//! Most of the documentation on regions can be found in
//! `middle/typeck/infer/region_inference.rs`
+use ast_map;
use session::Session;
use middle::ty::{self, Ty};
use util::nodemap::{FnvHashMap, FnvHashSet, NodeMap};
use syntax::{ast, visit};
use syntax::ast::{Block, Item, FnDecl, NodeId, Arm, Pat, Stmt, Expr, Local};
use syntax::ast_util::stmt_id;
-use syntax::ast_map;
use syntax::ptr::P;
use syntax::visit::{Visitor, FnKind};
fn visit_fn(&mut self, fk: visit::FnKind<'v>, fd: &'v ast::FnDecl,
b: &'v ast::Block, s: Span, _: ast::NodeId) {
match fk {
- visit::FkItemFn(_, generics, _, _, _) => {
+ visit::FkItemFn(_, generics, _, _, _, _) => {
self.visit_early_late(subst::FnSpace, generics, |this| {
this.walk_fn(fk, fd, b, s)
})
}
fn visit_generics(&mut self, generics: &ast::Generics) {
- for ty_param in &*generics.ty_params {
+ for ty_param in generics.ty_params.iter() {
visit::walk_ty_param_bounds_helper(self, &ty_param.bounds);
match ty_param.default {
Some(ref ty) => self.visit_ty(&**ty),
fb: &'b ast::Block,
_span: Span) {
match fk {
- visit::FkItemFn(_, generics, _, _, _) => {
+ visit::FkItemFn(_, generics, _, _, _, _) => {
visit::walk_fn_decl(self, fd);
self.visit_generics(generics);
}
let mut collector =
FreeLifetimeCollector { early_bound: &mut early_bound,
late_bound: &mut late_bound };
- for ty_param in &*generics.ty_params {
+ for ty_param in generics.ty_params.iter() {
visit::walk_ty_param_bounds_helper(&mut collector, &ty_param.bounds);
}
for predicate in &generics.where_clause.predicates {
use syntax::ast;
use syntax::ast::{Attribute, Block, Crate, DefId, FnDecl, NodeId, Variant};
use syntax::ast::{Item, Generics, StructField};
-use syntax::ast_util::is_local;
+use syntax::ast_util::{is_local, local_def};
use syntax::attr::{Stability, AttrMetaMethods};
use syntax::visit::{FnKind, Visitor};
use syntax::feature_gate::emit_feature_err;
-use util::nodemap::{NodeMap, DefIdMap, FnvHashSet, FnvHashMap};
-use util::ppaux::Repr;
+use util::nodemap::{DefIdMap, FnvHashSet, FnvHashMap};
use std::mem::replace;
/// A stability index, giving the stability level for items and methods.
-pub struct Index {
- // Indicates whether this crate has #![feature(staged_api)]
- staged_api: bool,
- // stability for crate-local items; unmarked stability == no entry
- local: NodeMap<Stability>,
- // cache for extern-crate items; unmarked stability == entry with None
- extern_cache: DefIdMap<Option<Stability>>
+pub struct Index<'tcx> {
+ /// This is mostly a cache, except the stabilities of local items
+ /// are filled by the annotator.
+ map: DefIdMap<Option<&'tcx Stability>>,
+
+ /// Maps for each crate whether it is part of the staged API.
+ staged_api: FnvHashMap<ast::CrateNum, bool>
}
// A private tree-walker for producing an Index.
-struct Annotator<'a> {
- sess: &'a Session,
- index: &'a mut Index,
- parent: Option<Stability>,
+struct Annotator<'a, 'tcx: 'a> {
+ tcx: &'a ty::ctxt<'tcx>,
+ index: &'a mut Index<'tcx>,
+ parent: Option<&'tcx Stability>,
export_map: &'a PublicItems,
}
-impl<'a> Annotator<'a> {
+impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> {
// Determine the stability for a node based on its attributes and inherited
// stability. The stability is recorded in the index and used as the parent.
fn annotate<F>(&mut self, id: NodeId, use_parent: bool,
attrs: &Vec<Attribute>, item_sp: Span, f: F, required: bool) where
F: FnOnce(&mut Annotator),
{
- if self.index.staged_api {
+ if self.index.staged_api[&ast::LOCAL_CRATE] {
debug!("annotate(id = {:?}, attrs = {:?})", id, attrs);
- match attr::find_stability(self.sess.diagnostic(), attrs, item_sp) {
+ match attr::find_stability(self.tcx.sess.diagnostic(), attrs, item_sp) {
Some(stab) => {
debug!("annotate: found {:?}", stab);
- self.index.local.insert(id, stab.clone());
+ let stab = self.tcx.intern_stability(stab);
+ self.index.map.insert(local_def(id), Some(stab));
// Don't inherit #[stable(feature = "rust1", since = "1.0.0")]
if stab.level != attr::Stable {
debug!("annotate: not found, use_parent = {:?}, parent = {:?}",
use_parent, self.parent);
if use_parent {
- if let Some(stab) = self.parent.clone() {
- self.index.local.insert(id, stab);
- } else if self.index.staged_api && required
+ if let Some(stab) = self.parent {
+ self.index.map.insert(local_def(id), Some(stab));
+ } else if self.index.staged_api[&ast::LOCAL_CRATE] && required
&& self.export_map.contains(&id)
- && !self.sess.opts.test {
- self.sess.span_err(item_sp,
- "This node does not have a stability attribute");
+ && !self.tcx.sess.opts.test {
+ self.tcx.sess.span_err(item_sp,
+ "This node does not \
+ have a stability attribute");
}
}
f(self);
let tag = attr.name();
if tag == "unstable" || tag == "stable" || tag == "deprecated" {
attr::mark_used(attr);
- self.sess.span_err(attr.span(),
+ self.tcx.sess.span_err(attr.span(),
"stability attributes may not be used outside \
of the standard library");
}
}
}
-impl<'a, 'v> Visitor<'v> for Annotator<'a> {
+impl<'a, 'tcx, 'v> Visitor<'v> for Annotator<'a, 'tcx> {
fn visit_item(&mut self, i: &Item) {
// FIXME (#18969): the following is a hack around the fact
// that we cannot currently annotate the stability of
}
}
-impl Index {
+impl<'tcx> Index<'tcx> {
/// Construct the stability index for a crate being compiled.
- pub fn build(&mut self, sess: &Session, krate: &Crate, export_map: &PublicItems) {
+ pub fn build(&mut self, tcx: &ty::ctxt<'tcx>, krate: &Crate, export_map: &PublicItems) {
let mut annotator = Annotator {
- sess: sess,
+ tcx: tcx,
index: self,
parent: None,
export_map: export_map,
}
pub fn new(krate: &Crate) -> Index {
- let mut staged_api = false;
+ let mut is_staged_api = false;
for attr in &krate.attrs {
if &attr.name()[..] == "staged_api" {
match attr.node.value.node {
ast::MetaWord(_) => {
attr::mark_used(attr);
- staged_api = true;
+ is_staged_api = true;
}
_ => (/*pass*/)
}
}
}
+ let mut staged_api = FnvHashMap();
+ staged_api.insert(ast::LOCAL_CRATE, is_staged_api);
Index {
staged_api: staged_api,
- local: NodeMap(),
- extern_cache: DefIdMap()
+ map: DefIdMap(),
}
}
}
}
impl<'a, 'tcx> Checker<'a, 'tcx> {
- fn check(&mut self, id: ast::DefId, span: Span, stab: &Option<Stability>) {
+ fn check(&mut self, id: ast::DefId, span: Span, stab: &Option<&Stability>) {
// Only the cross-crate scenario matters when checking unstable APIs
let cross_crate = !is_local(id);
if !cross_crate { return }
match *stab {
- Some(Stability { level: attr::Unstable, ref feature, ref reason, .. }) => {
+ Some(&Stability { level: attr::Unstable, ref feature, ref reason, .. }) => {
self.used_features.insert(feature.clone(), attr::Unstable);
if !self.active_features.contains(feature) {
&feature, span, &msg);
}
}
- Some(Stability { level, ref feature, .. }) => {
+ Some(&Stability { level, ref feature, .. }) => {
self.used_features.insert(feature.clone(), level);
// Stable APIs are always ok to call and deprecated APIs are
/// Helper for discovering nodes to check for stability
pub fn check_item(tcx: &ty::ctxt, item: &ast::Item, warn_about_defns: bool,
- cb: &mut FnMut(ast::DefId, Span, &Option<Stability>)) {
+ cb: &mut FnMut(ast::DefId, Span, &Option<&Stability>)) {
match item.node {
ast::ItemExternCrate(_) => {
// compiler-generated `extern crate` items have a dummy span.
/// Helper for discovering nodes to check for stability
pub fn check_expr(tcx: &ty::ctxt, e: &ast::Expr,
- cb: &mut FnMut(ast::DefId, Span, &Option<Stability>)) {
+ cb: &mut FnMut(ast::DefId, Span, &Option<&Stability>)) {
let span;
let id = match e.node {
ast::ExprMethodCall(i, _, _) => {
ast::ExprField(ref base_e, ref field) => {
span = field.span;
match ty::expr_ty_adjusted(tcx, base_e).sty {
- ty::ty_struct(did, _) => {
+ ty::TyStruct(did, _) => {
ty::lookup_struct_fields(tcx, did)
.iter()
.find(|f| f.name == field.node.name)
ast::ExprTupField(ref base_e, ref field) => {
span = field.span;
match ty::expr_ty_adjusted(tcx, base_e).sty {
- ty::ty_struct(did, _) => {
+ ty::TyStruct(did, _) => {
ty::lookup_struct_fields(tcx, did)
.get(field.node)
.unwrap_or_else(|| {
})
.id
}
- ty::ty_tup(..) => return,
+ ty::TyTuple(..) => return,
_ => tcx.sess.span_bug(e.span,
"stability::check_expr: unnamed field access on \
something other than a tuple or struct")
ast::ExprStruct(_, ref expr_fields, _) => {
let type_ = ty::expr_ty(tcx, e);
match type_.sty {
- ty::ty_struct(did, _) => {
+ ty::TyStruct(did, _) => {
let struct_fields = ty::lookup_struct_fields(tcx, did);
// check the stability of each field that appears
// in the construction expression.
// we don't look at stability attributes on
// struct-like enums (yet...), but it's definitely not
// a bug to have construct one.
- ty::ty_enum(..) => return,
+ ty::TyEnum(..) => return,
_ => {
tcx.sess.span_bug(e.span,
&format!("stability::check_expr: struct construction \
of non-struct, type {:?}",
- type_.repr(tcx)));
+ type_));
}
}
}
}
pub fn check_path(tcx: &ty::ctxt, path: &ast::Path, id: ast::NodeId,
- cb: &mut FnMut(ast::DefId, Span, &Option<Stability>)) {
+ cb: &mut FnMut(ast::DefId, Span, &Option<&Stability>)) {
match tcx.def_map.borrow().get(&id).map(|d| d.full_def()) {
Some(def::DefPrimTy(..)) => {}
Some(def) => {
}
pub fn check_pat(tcx: &ty::ctxt, pat: &ast::Pat,
- cb: &mut FnMut(ast::DefId, Span, &Option<Stability>)) {
+ cb: &mut FnMut(ast::DefId, Span, &Option<&Stability>)) {
debug!("check_pat(pat = {:?})", pat);
if is_internal(tcx, pat.span) { return; }
let did = match ty::pat_ty_opt(tcx, pat) {
- Some(&ty::TyS { sty: ty::ty_struct(did, _), .. }) => did,
+ Some(&ty::TyS { sty: ty::TyStruct(did, _), .. }) => did,
Some(_) | None => return,
};
let struct_fields = ty::lookup_struct_fields(tcx, did);
match pat.node {
// Foo(a, b, c)
ast::PatEnum(_, Some(ref pat_fields)) => {
- for (field, struct_field) in pat_fields.iter().zip(struct_fields.iter()) {
+ for (field, struct_field) in pat_fields.iter().zip(&struct_fields) {
// a .. pattern is fine, but anything positional is
// not.
if let ast::PatWild(ast::PatWildMulti) = field.node {
}
fn maybe_do_stability_check(tcx: &ty::ctxt, id: ast::DefId, span: Span,
- cb: &mut FnMut(ast::DefId, Span, &Option<Stability>)) {
+ cb: &mut FnMut(ast::DefId, Span, &Option<&Stability>)) {
if !is_staged_api(tcx, id) { return }
if is_internal(tcx, span) { return }
let ref stability = lookup(tcx, id);
if trait_method_id != id => {
is_staged_api(tcx, trait_method_id)
}
- _ if is_local(id) => {
- tcx.stability.borrow().staged_api
- }
_ => {
- csearch::is_staged_api(&tcx.sess.cstore, id)
+ *tcx.stability.borrow_mut().staged_api.entry(id.krate).or_insert_with(
+ || csearch::is_staged_api(&tcx.sess.cstore, id.krate))
}
}
}
/// Lookup the stability for a node, loading external crate
/// metadata as necessary.
-pub fn lookup(tcx: &ty::ctxt, id: DefId) -> Option<Stability> {
- debug!("lookup(id={})",
- id.repr(tcx));
+pub fn lookup<'tcx>(tcx: &ty::ctxt<'tcx>, id: DefId) -> Option<&'tcx Stability> {
+ if let Some(st) = tcx.stability.borrow().map.get(&id) {
+ return *st;
+ }
+
+ let st = lookup_uncached(tcx, id);
+ tcx.stability.borrow_mut().map.insert(id, st);
+ st
+}
+
+fn lookup_uncached<'tcx>(tcx: &ty::ctxt<'tcx>, id: DefId) -> Option<&'tcx Stability> {
+ debug!("lookup(id={:?})", id);
// is this definition the implementation of a trait method?
match ty::trait_item_of_item(tcx, id) {
}
let item_stab = if is_local(id) {
- tcx.stability.borrow().local.get(&id.node).cloned()
+ None // The stability cache is filled partially lazily
} else {
- let stab = csearch::get_stability(&tcx.sess.cstore, id);
- let mut index = tcx.stability.borrow_mut();
- (*index).extern_cache.insert(id, stab.clone());
- stab
+ csearch::get_stability(&tcx.sess.cstore, id).map(|st| tcx.intern_stability(st))
};
item_stab.or_else(|| {
- if let Some(trait_id) = ty::trait_id_of_impl(tcx, id) {
- // FIXME (#18969): for the time being, simply use the
- // stability of the trait to determine the stability of any
- // unmarked impls for it. See FIXME above for more details.
-
- debug!("lookup: trait_id={:?}", trait_id);
- lookup(tcx, trait_id)
- } else {
- None
+ if ty::is_impl(tcx, id) {
+ if let Some(trait_id) = ty::trait_id_of_impl(tcx, id) {
+ // FIXME (#18969): for the time being, simply use the
+ // stability of the trait to determine the stability of any
+ // unmarked impls for it. See FIXME above for more details.
+
+ debug!("lookup: trait_id={:?}", trait_id);
+ return lookup(tcx, trait_id);
+ }
}
+ None
})
}
let stable_msg = "this feature is stable. attribute no longer needed";
- for &span in sess.features.borrow().declared_stable_lang_features.iter() {
+ for &span in &sess.features.borrow().declared_stable_lang_features {
sess.add_lint(lint::builtin::STABLE_FEATURES,
ast::CRATE_NODE_ID,
span,
stable_msg.to_string());
}
- for (used_lib_feature, level) in lib_features_used.iter() {
+ for (used_lib_feature, level) in lib_features_used {
match remaining_lib_features.remove(used_lib_feature) {
Some(span) => {
if *level == attr::Stable {
}
}
- for (_, &span) in remaining_lib_features.iter() {
+ for &span in remaining_lib_features.values() {
sess.add_lint(lint::builtin::UNUSED_FEATURES,
ast::CRATE_NODE_ID,
span,
use middle::ty::{self, Ty};
use middle::ty_fold::{self, TypeFoldable, TypeFolder};
-use util::ppaux::Repr;
use std::fmt;
use std::iter::IntoIterator;
/// identify each in-scope parameter by an *index* and a *parameter
/// space* (which indices where the parameter is defined; see
/// `ParamSpace`).
-#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, PartialEq, Eq, Hash)]
pub struct Substs<'tcx> {
pub types: VecPerParamSpace<Ty<'tcx>>,
pub regions: RegionSubsts,
/// Represents the values to use when substituting lifetime parameters.
/// If the value is `ErasedRegions`, then this subst is occurring during
/// trans, and all region parameters will be replaced with `ty::ReStatic`.
-#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, PartialEq, Eq, Hash)]
pub enum RegionSubsts {
ErasedRegions,
NonerasedRegions(VecPerParamSpace<ty::Region>)
}
impl<T: fmt::Debug> fmt::Debug for VecPerParamSpace<T> {
- fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- try!(write!(fmt, "VecPerParamSpace {{"));
- for space in &ParamSpace::all() {
- try!(write!(fmt, "{:?}: {:?}, ", *space, self.get_slice(*space)));
- }
- try!(write!(fmt, "}}"));
- Ok(())
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "[{:?};{:?};{:?}]",
+ self.get_slice(TypeSpace),
+ self.get_slice(SelfSpace),
+ self.get_slice(FnSpace))
}
}
let self_limit = type_limit + s.len();
let mut content = t;
- content.extend(s.into_iter());
- content.extend(f.into_iter());
+ content.extend(s);
+ content.extend(f);
VecPerParamSpace {
type_limit: type_limit,
self.self_limit)
}
- pub fn map_move<U, F>(self, mut pred: F) -> VecPerParamSpace<U> where
- F: FnMut(T) -> U,
- {
- let SeparateVecsPerParamSpace {
- types: t,
- selfs: s,
- fns: f
- } = self.split();
-
- VecPerParamSpace::new(t.into_iter().map(|p| pred(p)).collect(),
- s.into_iter().map(|p| pred(p)).collect(),
- f.into_iter().map(|p| pred(p)).collect())
- }
-
pub fn split(self) -> SeparateVecsPerParamSpace<T> {
let VecPerParamSpace { type_limit, self_limit, content } = self;
self.tcx().sess.span_bug(
span,
&format!("Type parameter out of range \
- when substituting in region {} (root type={}) \
+ when substituting in region {} (root type={:?}) \
(space={:?}, index={})",
- data.name.as_str(),
- self.root_ty.repr(self.tcx()),
+ data.name,
+ self.root_ty,
data.space,
data.index));
}
self.ty_stack_depth += 1;
let t1 = match t.sty {
- ty::ty_param(p) => {
+ ty::TyParam(p) => {
self.ty_for_param(p, t)
}
_ => {
let span = self.span.unwrap_or(DUMMY_SP);
self.tcx().sess.span_bug(
span,
- &format!("Type parameter `{}` ({}/{:?}/{}) out of range \
- when substituting (root type={}) substs={}",
- p.repr(self.tcx()),
- source_ty.repr(self.tcx()),
+ &format!("Type parameter `{:?}` ({:?}/{:?}/{}) out of range \
+ when substituting (root type={:?}) substs={:?}",
+ p,
+ source_ty,
p.space,
p.idx,
- self.root_ty.repr(self.tcx()),
- self.substs.repr(self.tcx())));
+ self.root_ty,
+ self.substs));
}
};
/// is that only in the second case have we passed through a fn binder.
fn shift_regions_through_binders(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
debug!("shift_regions(ty={:?}, region_binders_passed={:?}, type_has_escaping_regions={:?})",
- ty.repr(self.tcx()), self.region_binders_passed, ty::type_has_escaping_regions(ty));
+ ty, self.region_binders_passed, ty::type_has_escaping_regions(ty));
if self.region_binders_passed == 0 || !ty::type_has_escaping_regions(ty) {
return ty;
}
let result = ty_fold::shift_regions(self.tcx(), self.region_binders_passed, &ty);
- debug!("shift_regions: shifted result = {:?}", result.repr(self.tcx()));
+ debug!("shift_regions: shifted result = {:?}", result);
result
}
```rust
impl Convert<uint> for int { ... } // int -> uint
-impl Convert<int> for uint { ... } // uint -> uint
+impl Convert<int> for uint { ... } // uint -> int
```
Now imagine there is some code like the following:
use middle::infer::{self, InferCtxt};
use syntax::ast;
use syntax::codemap::{DUMMY_SP, Span};
-use util::ppaux::Repr;
#[derive(Copy, Clone)]
struct InferIsLocal(bool);
-> bool
{
debug!("impl_can_satisfy(\
- impl1_def_id={}, \
- impl2_def_id={})",
- impl1_def_id.repr(infcx.tcx),
- impl2_def_id.repr(infcx.tcx));
+ impl1_def_id={:?}, \
+ impl2_def_id={:?})",
+ impl1_def_id,
+ impl2_def_id);
let param_env = &ty::empty_parameter_environment(infcx.tcx);
let selcx = &mut SelectionContext::intercrate(infcx, param_env);
b_def_id: ast::DefId)
-> bool
{
- debug!("overlap(a_def_id={}, b_def_id={})",
- a_def_id.repr(selcx.tcx()),
- b_def_id.repr(selcx.tcx()));
+ debug!("overlap(a_def_id={:?}, b_def_id={:?})",
+ a_def_id,
+ b_def_id);
let (a_trait_ref, a_obligations) = impl_trait_ref_and_oblig(selcx,
a_def_id,
b_def_id,
util::fresh_type_vars_for_impl);
- debug!("overlap: a_trait_ref={}", a_trait_ref.repr(selcx.tcx()));
+ debug!("overlap: a_trait_ref={:?}", a_trait_ref);
- debug!("overlap: b_trait_ref={}", b_trait_ref.repr(selcx.tcx()));
+ debug!("overlap: b_trait_ref={:?}", b_trait_ref);
// Does `a <: b` hold? If not, no overlap.
if let Err(_) = infer::mk_sub_poly_trait_refs(selcx.infcx(),
debug!("overlap: subtraitref check succeeded");
// Are any of the obligations unsatisfiable? If so, no overlap.
- let tcx = selcx.tcx();
let infcx = selcx.infcx();
let opt_failing_obligation =
a_obligations.iter()
- .chain(b_obligations.iter())
+ .chain(&b_obligations)
.map(|o| infcx.resolve_type_vars_if_possible(o))
.find(|o| !selcx.evaluate_obligation(o));
if let Some(failing_obligation) = opt_failing_obligation {
- debug!("overlap: obligation unsatisfiable {}", failing_obligation.repr(tcx));
+ debug!("overlap: obligation unsatisfiable {:?}", failing_obligation);
return false
}
pub fn trait_ref_is_knowable<'tcx>(tcx: &ty::ctxt<'tcx>, trait_ref: &ty::TraitRef<'tcx>) -> bool
{
- debug!("trait_ref_is_knowable(trait_ref={})", trait_ref.repr(tcx));
+ debug!("trait_ref_is_knowable(trait_ref={:?})", trait_ref);
// if the orphan rules pass, that means that no ancestor crate can
// impl this, so it's up to us.
let Normalized { value: predicates, obligations: normalization_obligations2 } =
project::normalize(selcx, ObligationCause::dummy(), &predicates);
let impl_obligations =
- util::predicates_for_generics(selcx.tcx(), ObligationCause::dummy(), 0, &predicates);
+ util::predicates_for_generics(ObligationCause::dummy(), 0, &predicates);
let impl_obligations: Vec<_> =
impl_obligations.into_iter()
- .chain(normalization_obligations1.into_iter())
- .chain(normalization_obligations2.into_iter())
+ .chain(normalization_obligations1)
+ .chain(normalization_obligations2)
.collect();
(impl_trait_ref, impl_obligations)
impl_def_id: ast::DefId)
-> Result<(), OrphanCheckErr<'tcx>>
{
- debug!("orphan_check({})", impl_def_id.repr(tcx));
+ debug!("orphan_check({:?})", impl_def_id);
// We only except this routine to be invoked on implementations
// of a trait, not inherent implementations.
let trait_ref = ty::impl_trait_ref(tcx, impl_def_id).unwrap();
- debug!("orphan_check: trait_ref={}", trait_ref.repr(tcx));
+ debug!("orphan_check: trait_ref={:?}", trait_ref);
// If the *trait* is local to the crate, ok.
if trait_ref.def_id.krate == ast::LOCAL_CRATE {
- debug!("trait {} is local to current crate",
- trait_ref.def_id.repr(tcx));
+ debug!("trait {:?} is local to current crate",
+ trait_ref.def_id);
return Ok(());
}
infer_is_local: InferIsLocal)
-> Result<(), OrphanCheckErr<'tcx>>
{
- debug!("orphan_check_trait_ref(trait_ref={}, infer_is_local={})",
- trait_ref.repr(tcx), infer_is_local.0);
+ debug!("orphan_check_trait_ref(trait_ref={:?}, infer_is_local={})",
+ trait_ref, infer_is_local.0);
// First, create an ordered iterator over all the type parameters to the trait, with the self
// type appearing first.
let input_tys = Some(trait_ref.self_ty());
- let input_tys = input_tys.iter().chain(trait_ref.substs.types.get_slice(TypeSpace).iter());
+ let input_tys = input_tys.iter().chain(trait_ref.substs.types.get_slice(TypeSpace));
// Find the first input type that either references a type parameter OR
// some local type.
for input_ty in input_tys {
if ty_is_local(tcx, input_ty, infer_is_local) {
- debug!("orphan_check_trait_ref: ty_is_local `{}`", input_ty.repr(tcx));
+ debug!("orphan_check_trait_ref: ty_is_local `{:?}`", input_ty);
// First local input type. Check that there are no
// uncovered type parameters.
let uncovered_tys = uncovered_tys(tcx, input_ty, infer_is_local);
for uncovered_ty in uncovered_tys {
if let Some(param) = uncovered_ty.walk().find(|t| is_type_parameter(t)) {
- debug!("orphan_check_trait_ref: uncovered type `{}`", param.repr(tcx));
+ debug!("orphan_check_trait_ref: uncovered type `{:?}`", param);
return Err(OrphanCheckErr::UncoveredTy(param));
}
}
// parameters reachable.
if !infer_is_local.0 {
if let Some(param) = input_ty.walk().find(|t| is_type_parameter(t)) {
- debug!("orphan_check_trait_ref: uncovered type `{}`", param.repr(tcx));
+ debug!("orphan_check_trait_ref: uncovered type `{:?}`", param);
return Err(OrphanCheckErr::UncoveredTy(param));
}
}
vec![]
} else if fundamental_ty(tcx, ty) {
ty.walk_shallow()
- .flat_map(|t| uncovered_tys(tcx, t, infer_is_local).into_iter())
+ .flat_map(|t| uncovered_tys(tcx, t, infer_is_local))
.collect()
} else {
vec![ty]
fn is_type_parameter<'tcx>(ty: Ty<'tcx>) -> bool {
match ty.sty {
// FIXME(#20590) straighten story about projection types
- ty::ty_projection(..) | ty::ty_param(..) => true,
+ ty::TyProjection(..) | ty::TyParam(..) => true,
_ => false,
}
}
fn fundamental_ty<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool
{
match ty.sty {
- ty::ty_uniq(..) | ty::ty_rptr(..) =>
+ ty::TyBox(..) | ty::TyRef(..) =>
true,
- ty::ty_enum(def_id, _) | ty::ty_struct(def_id, _) =>
+ ty::TyEnum(def_id, _) | ty::TyStruct(def_id, _) =>
ty::has_attr(tcx, def_id, "fundamental"),
- ty::ty_trait(ref data) =>
+ ty::TyTrait(ref data) =>
ty::has_attr(tcx, data.principal_def_id(), "fundamental"),
_ =>
false
infer_is_local: InferIsLocal)
-> bool
{
- debug!("ty_is_local_constructor({})", ty.repr(tcx));
+ debug!("ty_is_local_constructor({:?})", ty);
match ty.sty {
- ty::ty_bool |
- ty::ty_char |
- ty::ty_int(..) |
- ty::ty_uint(..) |
- ty::ty_float(..) |
- ty::ty_str(..) |
- ty::ty_bare_fn(..) |
- ty::ty_vec(..) |
- ty::ty_ptr(..) |
- ty::ty_rptr(..) |
- ty::ty_tup(..) |
- ty::ty_param(..) |
- ty::ty_projection(..) => {
+ ty::TyBool |
+ ty::TyChar |
+ ty::TyInt(..) |
+ ty::TyUint(..) |
+ ty::TyFloat(..) |
+ ty::TyStr(..) |
+ ty::TyBareFn(..) |
+ ty::TyArray(..) |
+ ty::TySlice(..) |
+ ty::TyRawPtr(..) |
+ ty::TyRef(..) |
+ ty::TyTuple(..) |
+ ty::TyParam(..) |
+ ty::TyProjection(..) => {
false
}
- ty::ty_infer(..) => {
+ ty::TyInfer(..) => {
infer_is_local.0
}
- ty::ty_enum(def_id, _) |
- ty::ty_struct(def_id, _) => {
+ ty::TyEnum(def_id, _) |
+ ty::TyStruct(def_id, _) => {
def_id.krate == ast::LOCAL_CRATE
}
- ty::ty_uniq(_) => { // Box<T>
+ ty::TyBox(_) => { // Box<T>
let krate = tcx.lang_items.owned_box().map(|d| d.krate);
krate == Some(ast::LOCAL_CRATE)
}
- ty::ty_trait(ref tt) => {
+ ty::TyTrait(ref tt) => {
tt.principal_def_id().krate == ast::LOCAL_CRATE
}
- ty::ty_closure(..) |
- ty::ty_err => {
+ ty::TyClosure(..) |
+ ty::TyError => {
tcx.sess.bug(
- &format!("ty_is_local invoked on unexpected type: {}",
- ty.repr(tcx)))
+ &format!("ty_is_local invoked on unexpected type: {:?}",
+ ty))
}
}
}
use middle::ty::{self, AsPredicate, ReferencesError, ToPolyTraitRef, TraitRef};
use middle::ty_fold::TypeFoldable;
use std::collections::HashMap;
+use std::fmt;
use syntax::codemap::{DUMMY_SP, Span};
use syntax::attr::{AttributeMethods, AttrMetaMethods};
-use util::ppaux::{Repr, UserString};
pub fn report_fulfillment_errors<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
errors: &Vec<FulfillmentError<'tcx>>) {
{
let predicate =
infcx.resolve_type_vars_if_possible(&obligation.predicate);
- // The ty_err created by normalize_to_error can end up being unified
+ // The TyError created by normalize_to_error can end up being unified
// into all obligations: for example, if our obligation is something
// like `$X = <() as Foo<$X>>::Out` and () does not implement Foo<_>,
- // then $X will be unified with ty_err, but the error still needs to be
+ // then $X will be unified with TyError, but the error still needs to be
// reported.
if !infcx.tcx.sess.has_errors() || !predicate.references_error() {
span_err!(infcx.tcx.sess, obligation.cause.span, E0271,
"type mismatch resolving `{}`: {}",
- predicate.user_string(infcx.tcx),
- ty::type_err_to_str(infcx.tcx, &error.err));
+ predicate,
+ error.err);
note_obligation_cause(infcx, obligation);
}
}
span: Span) -> Option<String> {
let def_id = trait_ref.def_id;
let mut report = None;
- for item in &*ty::get_attrs(infcx.tcx, def_id) {
+ for item in ty::get_attrs(infcx.tcx, def_id).iter() {
if item.check_name("rustc_on_unimplemented") {
let err_sp = if item.meta().span == DUMMY_SP {
span
item.meta().span
};
let def = ty::lookup_trait_def(infcx.tcx, def_id);
- let trait_str = def.trait_ref.user_string(infcx.tcx);
+ let trait_str = def.trait_ref.to_string();
if let Some(ref istring) = item.value_str() {
let mut generic_map = def.generics.types.iter_enumerated()
.map(|(param, i, gen)| {
(gen.name.as_str().to_string(),
trait_ref.substs.types.get(param, i)
- .user_string(infcx.tcx))
+ .to_string())
}).collect::<HashMap<String, String>>();
generic_map.insert("Self".to_string(),
- trait_ref.self_ty().user_string(infcx.tcx));
+ trait_ref.self_ty().to_string());
let parser = Parser::new(&istring);
let mut errored = false;
let err: String = parser.filter_map(|p| {
pub fn report_overflow_error<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
obligation: &Obligation<'tcx, T>)
-> !
- where T: UserString<'tcx> + TypeFoldable<'tcx>
+ where T: fmt::Display + TypeFoldable<'tcx>
{
let predicate =
infcx.resolve_type_vars_if_possible(&obligation.predicate);
span_err!(infcx.tcx.sess, obligation.cause.span, E0275,
"overflow evaluating the requirement `{}`",
- predicate.user_string(infcx.tcx));
+ predicate);
suggest_new_overflow_limit(infcx.tcx, obligation.cause.span);
span_err!(infcx.tcx.sess, obligation.cause.span, E0276,
"the requirement `{}` appears on the impl \
method but not on the corresponding trait method",
- obligation.predicate.user_string(infcx.tcx));;
+ obligation.predicate);;
}
_ => {
match obligation.predicate {
let trait_ref = trait_predicate.to_poly_trait_ref();
span_err!(infcx.tcx.sess, obligation.cause.span, E0277,
"the trait `{}` is not implemented for the type `{}`",
- trait_ref.user_string(infcx.tcx),
- trait_ref.self_ty().user_string(infcx.tcx));
+ trait_ref,
+ trait_ref.self_ty());
// Check if it has a custom "#[rustc_on_unimplemented]"
// error message, report with that message if it does
let custom_note = report_on_unimplemented(infcx, &trait_ref.0,
&predicate).err().unwrap();
span_err!(infcx.tcx.sess, obligation.cause.span, E0278,
"the requirement `{}` is not satisfied (`{}`)",
- predicate.user_string(infcx.tcx),
- ty::type_err_to_str(infcx.tcx, &err));
+ predicate,
+ err);
}
ty::Predicate::RegionOutlives(ref predicate) => {
&predicate).err().unwrap();
span_err!(infcx.tcx.sess, obligation.cause.span, E0279,
"the requirement `{}` is not satisfied (`{}`)",
- predicate.user_string(infcx.tcx),
- ty::type_err_to_str(infcx.tcx, &err));
+ predicate,
+ err);
}
ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => {
infcx.resolve_type_vars_if_possible(&obligation.predicate);
span_err!(infcx.tcx.sess, obligation.cause.span, E0280,
"the requirement `{}` is not satisfied",
- predicate.user_string(infcx.tcx));
+ predicate);
}
}
}
span_err!(infcx.tcx.sess, obligation.cause.span, E0281,
"type mismatch: the type `{}` implements the trait `{}`, \
but the trait `{}` is required ({})",
- expected_trait_ref.self_ty().user_string(infcx.tcx),
- expected_trait_ref.user_string(infcx.tcx),
- actual_trait_ref.user_string(infcx.tcx),
- ty::type_err_to_str(infcx.tcx, e));
+ expected_trait_ref.self_ty(),
+ expected_trait_ref,
+ actual_trait_ref,
+ e);
note_obligation_cause(infcx, obligation);
}
}
infcx.tcx.sess.span_note(
obligation.cause.span,
&format!("method `{}` has no receiver",
- method.name.user_string(infcx.tcx)));
+ method.name));
}
ObjectSafetyViolation::Method(method,
obligation.cause.span,
&format!("method `{}` references the `Self` type \
in its arguments or return type",
- method.name.user_string(infcx.tcx)));
+ method.name));
}
ObjectSafetyViolation::Method(method,
infcx.tcx.sess.span_note(
obligation.cause.span,
&format!("method `{}` has generic type parameters",
- method.name.user_string(infcx.tcx)));
+ method.name));
}
}
}
let predicate = infcx.resolve_type_vars_if_possible(&obligation.predicate);
- debug!("maybe_report_ambiguity(predicate={}, obligation={})",
- predicate.repr(infcx.tcx),
- obligation.repr(infcx.tcx));
+ debug!("maybe_report_ambiguity(predicate={:?}, obligation={:?})",
+ predicate,
+ obligation);
match predicate {
ty::Predicate::Trait(ref data) => {
span_err!(infcx.tcx.sess, obligation.cause.span, E0282,
"unable to infer enough type information about `{}`; \
type annotations or generic parameter binding required",
- self_ty.user_string(infcx.tcx));
+ self_ty);
} else {
span_err!(infcx.tcx.sess, obligation.cause.span, E0283,
"type annotations required: cannot resolve `{}`",
- predicate.user_string(infcx.tcx));;
+ predicate);;
note_obligation_cause(infcx, obligation);
}
}
"coherence failed to report ambiguity: \
cannot locate the impl of the trait `{}` for \
the type `{}`",
- trait_ref.user_string(infcx.tcx),
- self_ty.user_string(infcx.tcx)));
+ trait_ref,
+ self_ty));
}
}
if !infcx.tcx.sess.has_errors() {
span_err!(infcx.tcx.sess, obligation.cause.span, E0284,
"type annotations required: cannot resolve `{}`",
- predicate.user_string(infcx.tcx));;
+ predicate);;
note_obligation_cause(infcx, obligation);
}
}
fn note_obligation_cause<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
obligation: &Obligation<'tcx, T>)
- where T: UserString<'tcx>
+ where T: fmt::Display
{
note_obligation_cause_code(infcx,
&obligation.predicate,
predicate: &T,
cause_span: Span,
cause_code: &ObligationCauseCode<'tcx>)
- where T: UserString<'tcx>
+ where T: fmt::Display
{
let tcx = infcx.tcx;
match *cause_code {
let parent_trait_ref = infcx.resolve_type_vars_if_possible(&data.parent_trait_ref);
span_note!(tcx.sess, cause_span,
"required because it appears within the type `{}`",
- parent_trait_ref.0.self_ty().user_string(infcx.tcx));
+ parent_trait_ref.0.self_ty());
let parent_predicate = parent_trait_ref.as_predicate();
note_obligation_cause_code(infcx, &parent_predicate, cause_span, &*data.parent_code);
}
let parent_trait_ref = infcx.resolve_type_vars_if_possible(&data.parent_trait_ref);
span_note!(tcx.sess, cause_span,
"required because of the requirements on the impl of `{}` for `{}`",
- parent_trait_ref.user_string(infcx.tcx),
- parent_trait_ref.0.self_ty().user_string(infcx.tcx));
+ parent_trait_ref,
+ parent_trait_ref.0.self_ty());
let parent_predicate = parent_trait_ref.as_predicate();
note_obligation_cause_code(infcx, &parent_predicate, cause_span, &*data.parent_code);
}
span_note!(tcx.sess, cause_span,
"the requirement `{}` appears on the impl method \
but not on the corresponding trait method",
- predicate.user_string(infcx.tcx));
+ predicate);
}
}
}
use middle::infer::InferCtxt;
use middle::ty::{self, RegionEscape, Ty};
+
use std::collections::HashSet;
-use std::default::Default;
+use std::fmt;
use syntax::ast;
use util::common::ErrorReported;
-use util::ppaux::Repr;
use util::nodemap::NodeMap;
use super::CodeAmbiguity;
use super::Unimplemented;
use super::util::predicate_for_builtin_bound;
+pub struct FulfilledPredicates<'tcx> {
+ set: HashSet<ty::Predicate<'tcx>>
+}
+
/// The fulfillment context is used to drive trait resolution. It
/// consists of a list of obligations that must be (eventually)
/// satisfied. The job is to track which are satisfied, which yielded
// than the `SelectionCache`: it avoids duplicate errors and
// permits recursive obligations, which are often generated from
// traits like `Send` et al.
- duplicate_set: HashSet<ty::Predicate<'tcx>>,
+ duplicate_set: FulfilledPredicates<'tcx>,
// A list of all obligations that have been registered with this
// fulfillment context.
// obligations (otherwise, it's easy to fail to walk to a
// particular node-id).
region_obligations: NodeMap<Vec<RegionObligation<'tcx>>>,
+
+ errors_will_be_reported: bool,
}
#[derive(Clone)]
}
impl<'tcx> FulfillmentContext<'tcx> {
- pub fn new() -> FulfillmentContext<'tcx> {
+ /// Creates a new fulfillment context.
+ ///
+ /// `errors_will_be_reported` indicates whether ALL errors that
+ /// are generated by this fulfillment context will be reported to
+ /// the end user. This is used to inform caching, because it
+ /// allows us to conclude that traits that resolve successfully
+ /// will in fact always resolve successfully (in particular, it
+ /// guarantees that if some dependent obligation encounters a
+ /// problem, compilation will be aborted). If you're not sure of
+ /// the right value here, pass `false`, as that is the more
+ /// conservative option.
+ ///
+ /// FIXME -- a better option would be to hold back on modifying
+ /// the global cache until we know that all dependent obligations
+ /// are also satisfied. In that case, we could actually remove
+ /// this boolean flag, and we'd also avoid the problem of squelching
+ /// duplicate errors that occur across fns.
+ pub fn new(errors_will_be_reported: bool) -> FulfillmentContext<'tcx> {
FulfillmentContext {
- duplicate_set: HashSet::new(),
+ duplicate_set: FulfilledPredicates::new(),
predicates: Vec::new(),
attempted_mark: 0,
region_obligations: NodeMap(),
+ errors_will_be_reported: errors_will_be_reported,
}
}
cause: ObligationCause<'tcx>)
-> Ty<'tcx>
{
- debug!("normalize_associated_type(projection_ty={})",
- projection_ty.repr(infcx.tcx));
+ debug!("normalize_associated_type(projection_ty={:?})",
+ projection_ty);
assert!(!projection_ty.has_escaping_regions());
self.register_predicate_obligation(infcx, obligation);
}
- debug!("normalize_associated_type: result={}", normalized.value.repr(infcx.tcx));
+ debug!("normalize_associated_type: result={:?}", normalized.value);
normalized.value
}
}
pub fn register_region_obligation<'a>(&mut self,
- infcx: &InferCtxt<'a,'tcx>,
t_a: Ty<'tcx>,
r_b: ty::Region,
cause: ObligationCause<'tcx>)
{
- register_region_obligation(infcx.tcx, t_a, r_b, cause, &mut self.region_obligations);
+ register_region_obligation(t_a, r_b, cause, &mut self.region_obligations);
}
pub fn register_predicate_obligation<'a>(&mut self,
assert!(!obligation.has_escaping_regions());
- if !self.duplicate_set.insert(obligation.predicate.clone()) {
- debug!("register_predicate({}) -- already seen, skip", obligation.repr(infcx.tcx));
+ if self.is_duplicate_or_add(infcx.tcx, &obligation.predicate) {
+ debug!("register_predicate({:?}) -- already seen, skip", obligation);
return;
}
- debug!("register_predicate({})", obligation.repr(infcx.tcx));
+ debug!("register_predicate({:?})", obligation);
self.predicates.push(obligation);
}
&self.predicates
}
+ fn is_duplicate_or_add(&mut self, tcx: &ty::ctxt<'tcx>,
+ predicate: &ty::Predicate<'tcx>)
+ -> bool {
+ // This is a kind of dirty hack to allow us to avoid "rederiving"
+ // things that we have already proven in other methods.
+ //
+ // The idea is that any predicate that doesn't involve type
+ // parameters and which only involves the 'static region (and
+ // no other regions) is universally solvable, since impls are global.
+ //
+ // This is particularly important since even if we have a
+ // cache hit in the selection context, we still wind up
+ // evaluating the 'nested obligations'. This cache lets us
+ // skip those.
+
+ if self.errors_will_be_reported && predicate.is_global() {
+ tcx.fulfilled_predicates.borrow_mut().is_duplicate_or_add(predicate)
+ } else {
+ self.duplicate_set.is_duplicate_or_add(predicate)
+ }
+ }
+
/// Attempts to select obligations using `selcx`. If `only_new_obligations` is true, then it
/// only attempts to select obligations that haven't been seen before.
fn select<'a>(&mut self,
* type inference.
*/
- let tcx = selcx.tcx();
match obligation.predicate {
ty::Predicate::Trait(ref data) => {
let trait_obligation = obligation.with(data.clone());
false
}
Ok(Some(s)) => {
- s.map_move_nested(|p| new_obligations.push(p));
+ new_obligations.append(&mut s.nested_obligations());
true
}
Err(selection_err) => {
- debug!("predicate: {} error: {}",
- obligation.repr(tcx),
- selection_err.repr(tcx));
+ debug!("predicate: {:?} error: {:?}",
+ obligation,
+ selection_err);
errors.push(
FulfillmentError::new(
obligation.clone(),
CodeSelectionError(Unimplemented)));
} else {
let ty::OutlivesPredicate(t_a, r_b) = binder.0;
- register_region_obligation(tcx, t_a, r_b,
+ register_region_obligation(t_a, r_b,
obligation.cause.clone(),
region_obligations);
}
ty::Predicate::Projection(ref data) => {
let project_obligation = obligation.with(data.clone());
let result = project::poly_project_and_unify_type(selcx, &project_obligation);
- debug!("process_predicate: poly_project_and_unify_type({}) returned {}",
- project_obligation.repr(tcx),
- result.repr(tcx));
+ debug!("process_predicate: poly_project_and_unify_type({:?}) returned {:?}",
+ project_obligation,
+ result);
match result {
Ok(Some(obligations)) => {
- new_obligations.extend(obligations.into_iter());
+ new_obligations.extend(obligations);
true
}
Ok(None) => {
}
}
-impl<'tcx> Repr<'tcx> for RegionObligation<'tcx> {
- fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
- format!("RegionObligation(sub_region={}, sup_type={})",
- self.sub_region.repr(tcx),
- self.sup_type.repr(tcx))
+impl<'tcx> fmt::Debug for RegionObligation<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "RegionObligation(sub_region={:?}, sup_type={:?})",
+ self.sub_region,
+ self.sup_type)
}
}
-fn register_region_obligation<'tcx>(tcx: &ty::ctxt<'tcx>,
- t_a: Ty<'tcx>,
+fn register_region_obligation<'tcx>(t_a: Ty<'tcx>,
r_b: ty::Region,
cause: ObligationCause<'tcx>,
region_obligations: &mut NodeMap<Vec<RegionObligation<'tcx>>>)
sub_region: r_b,
cause: cause };
- debug!("register_region_obligation({})",
- region_obligation.repr(tcx));
+ debug!("register_region_obligation({:?})",
+ region_obligation);
region_obligations.entry(region_obligation.cause.body_id).or_insert(vec![])
.push(region_obligation);
}
+
+impl<'tcx> FulfilledPredicates<'tcx> {
+ pub fn new() -> FulfilledPredicates<'tcx> {
+ FulfilledPredicates {
+ set: HashSet::new()
+ }
+ }
+
+ pub fn is_duplicate(&self, p: &ty::Predicate<'tcx>) -> bool {
+ self.set.contains(p)
+ }
+
+ fn is_duplicate_or_add(&mut self, p: &ty::Predicate<'tcx>) -> bool {
+ !self.set.insert(p.clone())
+ }
+}
+
+
use middle::ty::{self, HasProjectionTypes, Ty};
use middle::ty_fold::TypeFoldable;
use middle::infer::{self, fixup_err_to_string, InferCtxt};
-use std::slice::Iter;
use std::rc::Rc;
use syntax::ast;
use syntax::codemap::{Span, DUMMY_SP};
-use util::ppaux::Repr;
pub use self::error_reporting::report_fulfillment_errors;
pub use self::error_reporting::report_overflow_error;
pub use self::coherence::orphan_check;
pub use self::coherence::overlapping_impls;
pub use self::coherence::OrphanCheckErr;
-pub use self::fulfill::{FulfillmentContext, RegionObligation};
+pub use self::fulfill::{FulfillmentContext, FulfilledPredicates, RegionObligation};
pub use self::project::MismatchedProjectionTypes;
pub use self::project::normalize;
pub use self::project::Normalized;
parent_code: Rc<ObligationCauseCode<'tcx>>
}
-pub type Obligations<'tcx, O> = subst::VecPerParamSpace<Obligation<'tcx, O>>;
-pub type PredicateObligations<'tcx> = subst::VecPerParamSpace<PredicateObligation<'tcx>>;
-pub type TraitObligations<'tcx> = subst::VecPerParamSpace<TraitObligation<'tcx>>;
+pub type Obligations<'tcx, O> = Vec<Obligation<'tcx, O>>;
+pub type PredicateObligations<'tcx> = Vec<PredicateObligation<'tcx>>;
+pub type TraitObligations<'tcx> = Vec<TraitObligation<'tcx>>;
pub type Selection<'tcx> = Vtable<'tcx, PredicateObligation<'tcx>>;
/// ### The type parameter `N`
///
/// See explanation on `VtableImplData`.
-#[derive(Debug,Clone)]
+#[derive(Clone)]
pub enum Vtable<'tcx, N> {
/// Vtable identifying a particular impl.
VtableImpl(VtableImplData<'tcx, N>),
/// Vtable automatically generated for a closure. The def ID is the ID
/// of the closure expression. This is a `VtableImpl` in spirit, but the
/// impl is generated by the compiler and does not appear in the source.
- VtableClosure(ast::DefId, subst::Substs<'tcx>),
+ VtableClosure(VtableClosureData<'tcx, N>),
/// Same as above, but for a fn pointer type with the given signature.
VtableFnPointer(ty::Ty<'tcx>),
pub struct VtableImplData<'tcx, N> {
pub impl_def_id: ast::DefId,
pub substs: subst::Substs<'tcx>,
- pub nested: subst::VecPerParamSpace<N>
+ pub nested: Vec<N>
+}
+
+#[derive(Clone, PartialEq, Eq)]
+pub struct VtableClosureData<'tcx, N> {
+ pub closure_def_id: ast::DefId,
+ pub substs: subst::Substs<'tcx>,
+ /// Nested obligations. This can be non-empty if the closure
+ /// signature contains associated types.
+ pub nested: Vec<N>
}
-#[derive(Debug,Clone)]
+#[derive(Clone)]
pub struct VtableDefaultImplData<N> {
pub trait_def_id: ast::DefId,
pub nested: Vec<N>
}
-#[derive(Debug,Clone)]
+#[derive(Clone)]
pub struct VtableBuiltinData<N> {
- pub nested: subst::VecPerParamSpace<N>
+ pub nested: Vec<N>
}
/// A vtable for some object-safe trait `Foo` automatically derived
}
/// Creates predicate obligations from the generic bounds.
-pub fn predicates_for_generics<'tcx>(tcx: &ty::ctxt<'tcx>,
- cause: ObligationCause<'tcx>,
+pub fn predicates_for_generics<'tcx>(cause: ObligationCause<'tcx>,
generic_bounds: &ty::InstantiatedPredicates<'tcx>)
-> PredicateObligations<'tcx>
{
- util::predicates_for_generics(tcx, cause, 0, generic_bounds)
+ util::predicates_for_generics(cause, 0, generic_bounds)
}
/// Determines whether the type `ty` is known to meet `bound` and
/// `bound` or is not known to meet bound (note that this is
/// conservative towards *no impl*, which is the opposite of the
/// `evaluate` methods).
-pub fn evaluate_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
- typer: &ty::ClosureTyper<'tcx>,
- ty: Ty<'tcx>,
- bound: ty::BuiltinBound,
- span: Span)
- -> SelectionResult<'tcx, ()>
+pub fn type_known_to_meet_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
+ typer: &ty::ClosureTyper<'tcx>,
+ ty: Ty<'tcx>,
+ bound: ty::BuiltinBound,
+ span: Span)
+ -> bool
{
- debug!("type_known_to_meet_builtin_bound(ty={}, bound={:?})",
- ty.repr(infcx.tcx),
+ debug!("type_known_to_meet_builtin_bound(ty={:?}, bound={:?})",
+ ty,
bound);
- let mut fulfill_cx = FulfillmentContext::new();
+ let mut fulfill_cx = FulfillmentContext::new(false);
// We can use a dummy node-id here because we won't pay any mind
// to region obligations that arise (there shouldn't really be any
// Note: we only assume something is `Copy` if we can
// *definitively* show that it implements `Copy`. Otherwise,
// assume it is move; linear is always ok.
- let result = match fulfill_cx.select_all_or_error(infcx, typer) {
- Ok(()) => Ok(Some(())), // Success, we know it implements Copy.
- Err(errors) => {
- // If there were any hard errors, propagate an arbitrary
- // one of those. If no hard errors at all, report
- // ambiguity.
- let sel_error =
- errors.iter()
- .filter_map(|err| {
- match err.code {
- CodeAmbiguity => None,
- CodeSelectionError(ref e) => Some(e.clone()),
- CodeProjectionError(_) => {
- infcx.tcx.sess.span_bug(
- span,
- "projection error while selecting?")
- }
- }
- })
- .next();
- match sel_error {
- None => { Ok(None) }
- Some(e) => { Err(e) }
- }
- }
- };
-
- debug!("type_known_to_meet_builtin_bound: ty={} bound={:?} result={:?}",
- ty.repr(infcx.tcx),
- bound,
- result);
-
- result
-}
-
-pub fn type_known_to_meet_builtin_bound<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
- typer: &ty::ClosureTyper<'tcx>,
- ty: Ty<'tcx>,
- bound: ty::BuiltinBound,
- span: Span)
- -> bool
-{
- match evaluate_builtin_bound(infcx, typer, ty, bound, span) {
- Ok(Some(())) => {
- // definitely impl'd
+ match fulfill_cx.select_all_or_error(infcx, typer) {
+ Ok(()) => {
+ debug!("type_known_to_meet_builtin_bound: ty={:?} bound={:?} success",
+ ty,
+ bound);
true
}
- Ok(None) => {
- // ambiguous: if coherence check was successful, shouldn't
- // happen, but we might have reported an error and been
- // soldering on, so just treat this like not implemented
- false
- }
- Err(_) => {
- // errors: not implemented.
+ Err(e) => {
+ debug!("type_known_to_meet_builtin_bound: ty={:?} bound={:?} errors={:?}",
+ ty,
+ bound,
+ e);
false
}
}
let span = cause.span;
let body_id = cause.body_id;
- debug!("normalize_param_env_or_error(unnormalized_env={})",
- unnormalized_env.repr(tcx));
+ debug!("normalize_param_env_or_error(unnormalized_env={:?})",
+ unnormalized_env);
+
+ let predicates: Vec<_> =
+ util::elaborate_predicates(tcx, unnormalized_env.caller_bounds.clone())
+ .filter(|p| !p.is_global()) // (*)
+ .collect();
+
+ // (*) Any predicate like `i32: Trait<u32>` or whatever doesn't
+ // need to be in the *environment* to be proven, so screen those
+ // out. This is important for the soundness of inter-fn
+ // caching. Note though that we should probably check that these
+ // predicates hold at the point where the environment is
+ // constructed, but I am not currently doing so out of laziness.
+ // -nmatsakis
+
+ debug!("normalize_param_env_or_error: elaborated-predicates={:?}",
+ predicates);
+
+ let elaborated_env = unnormalized_env.with_caller_bounds(predicates);
let infcx = infer::new_infer_ctxt(tcx);
- let predicates = match fully_normalize(&infcx, &unnormalized_env, cause,
- &unnormalized_env.caller_bounds) {
+ let predicates = match fully_normalize(&infcx, &elaborated_env, cause,
+ &elaborated_env.caller_bounds) {
Ok(predicates) => predicates,
Err(errors) => {
report_fulfillment_errors(&infcx, &errors);
// all things considered.
let err_msg = fixup_err_to_string(fixup_err);
tcx.sess.span_err(span, &err_msg);
- return unnormalized_env; // an unnormalized env is better than nothing
+ return elaborated_env; // an unnormalized env is better than nothing
}
};
- debug!("normalize_param_env_or_error: predicates={}",
- predicates.repr(tcx));
-
- unnormalized_env.with_caller_bounds(predicates)
+ elaborated_env.with_caller_bounds(predicates)
}
pub fn fully_normalize<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
cause: ObligationCause<'tcx>,
value: &T)
-> Result<T, Vec<FulfillmentError<'tcx>>>
- where T : TypeFoldable<'tcx> + HasProjectionTypes + Clone + Repr<'tcx>
+ where T : TypeFoldable<'tcx> + HasProjectionTypes
{
- let tcx = closure_typer.tcx();
-
- debug!("normalize_param_env(value={})", value.repr(tcx));
+ debug!("normalize_param_env(value={:?})", value);
let mut selcx = &mut SelectionContext::new(infcx, closure_typer);
- let mut fulfill_cx = FulfillmentContext::new();
+ let mut fulfill_cx = FulfillmentContext::new(false);
let Normalized { value: normalized_value, obligations } =
project::normalize(selcx, cause, value);
- debug!("normalize_param_env: normalized_value={} obligations={}",
- normalized_value.repr(tcx),
- obligations.repr(tcx));
+ debug!("normalize_param_env: normalized_value={:?} obligations={:?}",
+ normalized_value,
+ obligations);
for obligation in obligations {
fulfill_cx.register_predicate_obligation(selcx.infcx(), obligation);
}
try!(fulfill_cx.select_all_or_error(infcx, closure_typer));
let resolved_value = infcx.resolve_type_vars_if_possible(&normalized_value);
- debug!("normalize_param_env: resolved_value={}", resolved_value.repr(tcx));
+ debug!("normalize_param_env: resolved_value={:?}", resolved_value);
Ok(resolved_value)
}
}
impl<'tcx, N> Vtable<'tcx, N> {
- pub fn iter_nested(&self) -> Iter<N> {
- match *self {
- VtableImpl(ref i) => i.iter_nested(),
- VtableParam(ref n) => n.iter(),
- VtableBuiltin(ref i) => i.iter_nested(),
- VtableObject(_) |
- VtableDefaultImpl(..) | VtableFnPointer(..) |
- VtableClosure(..) => (&[]).iter(),
- }
- }
-
- pub fn map_nested<M, F>(&self, op: F) -> Vtable<'tcx, M> where
- F: FnMut(&N) -> M,
- {
- match *self {
- VtableImpl(ref i) => VtableImpl(i.map_nested(op)),
- VtableDefaultImpl(ref t) => VtableDefaultImpl(t.map_nested(op)),
- VtableFnPointer(ref sig) => VtableFnPointer((*sig).clone()),
- VtableClosure(d, ref s) => VtableClosure(d, s.clone()),
- VtableParam(ref n) => VtableParam(n.iter().map(op).collect()),
- VtableObject(ref p) => VtableObject(p.clone()),
- VtableBuiltin(ref b) => VtableBuiltin(b.map_nested(op)),
- }
- }
-
- pub fn map_move_nested<M, F>(self, op: F) -> Vtable<'tcx, M> where
- F: FnMut(N) -> M,
- {
+ pub fn nested_obligations(self) -> Vec<N> {
match self {
- VtableImpl(i) => VtableImpl(i.map_move_nested(op)),
- VtableFnPointer(sig) => VtableFnPointer(sig),
- VtableClosure(d, s) => VtableClosure(d, s),
- VtableDefaultImpl(t) => VtableDefaultImpl(t.map_move_nested(op)),
- VtableParam(n) => VtableParam(n.into_iter().map(op).collect()),
- VtableObject(p) => VtableObject(p),
- VtableBuiltin(no) => VtableBuiltin(no.map_move_nested(op)),
- }
- }
-}
-
-impl<'tcx, N> VtableImplData<'tcx, N> {
- pub fn iter_nested(&self) -> Iter<N> {
- self.nested.iter()
- }
-
- pub fn map_nested<M, F>(&self, op: F) -> VtableImplData<'tcx, M> where
- F: FnMut(&N) -> M,
- {
- VtableImplData {
- impl_def_id: self.impl_def_id,
- substs: self.substs.clone(),
- nested: self.nested.map(op)
- }
- }
-
- pub fn map_move_nested<M, F>(self, op: F) -> VtableImplData<'tcx, M> where
- F: FnMut(N) -> M,
- {
- let VtableImplData { impl_def_id, substs, nested } = self;
- VtableImplData {
- impl_def_id: impl_def_id,
- substs: substs,
- nested: nested.map_move(op)
- }
- }
-}
-
-impl<N> VtableDefaultImplData<N> {
- pub fn iter_nested(&self) -> Iter<N> {
- self.nested.iter()
- }
-
- pub fn map_nested<M, F>(&self, op: F) -> VtableDefaultImplData<M> where
- F: FnMut(&N) -> M,
- {
- VtableDefaultImplData {
- trait_def_id: self.trait_def_id,
- nested: self.nested.iter().map(op).collect()
+ VtableImpl(i) => i.nested,
+ VtableParam(n) => n,
+ VtableBuiltin(i) => i.nested,
+ VtableDefaultImpl(d) => d.nested,
+ VtableClosure(c) => c.nested,
+ VtableObject(_) | VtableFnPointer(..) => vec![]
}
}
- pub fn map_move_nested<M, F>(self, op: F) -> VtableDefaultImplData<M> where
- F: FnMut(N) -> M,
- {
- let VtableDefaultImplData { trait_def_id, nested } = self;
- VtableDefaultImplData {
- trait_def_id: trait_def_id,
- nested: nested.into_iter().map(op).collect()
- }
- }
-}
-
-impl<N> VtableBuiltinData<N> {
- pub fn iter_nested(&self) -> Iter<N> {
- self.nested.iter()
- }
-
- pub fn map_nested<M, F>(&self, op: F) -> VtableBuiltinData<M> where F: FnMut(&N) -> M {
- VtableBuiltinData {
- nested: self.nested.map(op)
- }
- }
-
- pub fn map_move_nested<M, F>(self, op: F) -> VtableBuiltinData<M> where
- F: FnMut(N) -> M,
- {
- VtableBuiltinData {
- nested: self.nested.map_move(op)
+ pub fn map<M, F>(self, f: F) -> Vtable<'tcx, M> where F: FnMut(N) -> M {
+ match self {
+ VtableImpl(i) => VtableImpl(VtableImplData {
+ impl_def_id: i.impl_def_id,
+ substs: i.substs,
+ nested: i.nested.into_iter().map(f).collect()
+ }),
+ VtableParam(n) => VtableParam(n.into_iter().map(f).collect()),
+ VtableBuiltin(i) => VtableBuiltin(VtableBuiltinData {
+ nested: i.nested.into_iter().map(f).collect()
+ }),
+ VtableObject(o) => VtableObject(o),
+ VtableDefaultImpl(d) => VtableDefaultImpl(VtableDefaultImplData {
+ trait_def_id: d.trait_def_id,
+ nested: d.nested.into_iter().map(f).collect()
+ }),
+ VtableFnPointer(f) => VtableFnPointer(f),
+ VtableClosure(c) => VtableClosure(VtableClosureData {
+ closure_def_id: c.closure_def_id,
+ substs: c.substs,
+ nested: c.nested.into_iter().map(f).collect()
+ })
}
}
}
use middle::ty::{self, ToPolyTraitRef, Ty};
use std::rc::Rc;
use syntax::ast;
-use util::ppaux::Repr;
+#[derive(Debug)]
pub enum ObjectSafetyViolation<'tcx> {
/// Self : Sized declared on the trait
SizedSelf,
result
});
- debug!("is_object_safe({}) = {}", trait_def_id.repr(tcx), result);
+ debug!("is_object_safe({:?}) = {}", trait_def_id, result);
result
}
-> Vec<ObjectSafetyViolation<'tcx>>
{
traits::supertrait_def_ids(tcx, trait_def_id)
- .flat_map(|def_id| object_safety_violations_for_trait(tcx, def_id).into_iter())
+ .flat_map(|def_id| object_safety_violations_for_trait(tcx, def_id))
.collect()
}
violations.push(ObjectSafetyViolation::SupertraitSelf);
}
- debug!("object_safety_violations_for_trait(trait_def_id={}) = {}",
- trait_def_id.repr(tcx),
- violations.repr(tcx));
+ debug!("object_safety_violations_for_trait(trait_def_id={:?}) = {:?}",
+ trait_def_id,
+ violations);
violations
}
let mut error = false;
ty::maybe_walk_ty(ty, |ty| {
match ty.sty {
- ty::ty_param(ref param_ty) => {
+ ty::TyParam(ref param_ty) => {
if param_ty.space == SelfSpace {
error = true;
}
false // no contained types to walk
}
- ty::ty_projection(ref data) => {
+ ty::TyProjection(ref data) => {
// This is a projected type `<Foo as SomeTrait>::X`.
// Compute supertraits of current trait lazily.
error
}
-impl<'tcx> Repr<'tcx> for ObjectSafetyViolation<'tcx> {
- fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
- match *self {
- ObjectSafetyViolation::SizedSelf =>
- format!("SizedSelf"),
- ObjectSafetyViolation::SupertraitSelf =>
- format!("SupertraitSelf"),
- ObjectSafetyViolation::Method(ref m, code) =>
- format!("Method({},{:?})", m.repr(tcx), code),
- }
- }
-}
-
fn is_self<'tcx>(ty: Ty<'tcx>) -> bool {
match ty.sty {
- ty::ty_param(ref data) => data.space == subst::SelfSpace,
+ ty::TyParam(ref data) => data.space == subst::SelfSpace,
_ => false,
}
}
use super::PredicateObligation;
use super::SelectionContext;
use super::SelectionError;
+use super::VtableClosureData;
use super::VtableImplData;
use super::util;
use middle::infer;
-use middle::subst::{Subst, Substs};
+use middle::subst::Subst;
use middle::ty::{self, AsPredicate, ReferencesError, RegionEscape,
HasProjectionTypes, ToPolyTraitRef, Ty};
use middle::ty_fold::{self, TypeFoldable, TypeFolder};
-use syntax::ast;
use syntax::parse::token;
use util::common::FN_OUTPUT_NAME;
-use util::ppaux::Repr;
+
+use std::fmt;
pub type PolyProjectionObligation<'tcx> =
Obligation<'tcx, ty::PolyProjectionPredicate<'tcx>>;
Obligation<'tcx, ty::ProjectionTy<'tcx>>;
/// When attempting to resolve `<T as TraitRef>::Name` ...
+#[derive(Debug)]
pub enum ProjectionTyError<'tcx> {
/// ...we found multiple sources of information and couldn't resolve the ambiguity.
TooManyCandidates,
pub err: ty::type_err<'tcx>
}
-#[derive(PartialEq, Eq)]
+#[derive(PartialEq, Eq, Debug)]
enum ProjectionTyCandidate<'tcx> {
ParamEnv(ty::PolyProjectionPredicate<'tcx>),
Impl(VtableImplData<'tcx, PredicateObligation<'tcx>>),
- Closure(ast::DefId, Substs<'tcx>),
+ Closure(VtableClosureData<'tcx, PredicateObligation<'tcx>>),
FnPointer(Ty<'tcx>),
}
obligation: &PolyProjectionObligation<'tcx>)
-> Result<Option<Vec<PredicateObligation<'tcx>>>, MismatchedProjectionTypes<'tcx>>
{
- debug!("poly_project_and_unify_type(obligation={})",
- obligation.repr(selcx.tcx()));
+ debug!("poly_project_and_unify_type(obligation={:?})",
+ obligation);
let infcx = selcx.infcx();
infcx.commit_if_ok(|snapshot| {
obligation: &ProjectionObligation<'tcx>)
-> Result<Option<Vec<PredicateObligation<'tcx>>>, MismatchedProjectionTypes<'tcx>>
{
- debug!("project_and_unify_type(obligation={})",
- obligation.repr(selcx.tcx()));
+ debug!("project_and_unify_type(obligation={:?})",
+ obligation);
let Normalized { value: normalized_ty, obligations } =
match opt_normalize_projection_type(selcx,
}
};
- debug!("project_and_unify_type: normalized_ty={} obligations={}",
- normalized_ty.repr(selcx.tcx()),
- obligations.repr(selcx.tcx()));
+ debug!("project_and_unify_type: normalized_ty={:?} obligations={:?}",
+ normalized_ty,
+ obligations);
let infcx = selcx.infcx();
let origin = infer::RelateOutputImplTypes(obligation.cause.span);
fn consider_unification_despite_ambiguity<'cx,'tcx>(selcx: &mut SelectionContext<'cx,'tcx>,
obligation: &ProjectionObligation<'tcx>) {
- debug!("consider_unification_despite_ambiguity(obligation={})",
- obligation.repr(selcx.tcx()));
+ debug!("consider_unification_despite_ambiguity(obligation={:?})",
+ obligation);
let def_id = obligation.predicate.projection_ty.trait_ref.def_id;
match selcx.tcx().lang_items.fn_trait_kind(def_id) {
debug!("consider_unification_despite_ambiguity: self_ty.sty={:?}",
self_ty.sty);
match self_ty.sty {
- ty::ty_closure(closure_def_id, substs) => {
+ ty::TyClosure(closure_def_id, substs) => {
let closure_typer = selcx.closure_typer();
let closure_type = closure_typer.closure_type(closure_def_id, substs);
let ty::Binder((_, ret_type)) =
self_ty,
&closure_type.sig,
util::TupleArgumentsFlag::No);
+ // We don't have to normalize the return type here - this is only
+ // reached for TyClosure: Fn inputs where the closure kind is
+ // still unknown, which should only occur in typeck where the
+ // closure type is already normalized.
let (ret_type, _) =
infcx.replace_late_bound_regions_with_fresh_var(
obligation.cause.span,
infer::AssocTypeProjection(obligation.predicate.projection_ty.item_name),
&ty::Binder(ret_type));
+
debug!("consider_unification_despite_ambiguity: ret_type={:?}",
- ret_type.repr(selcx.tcx()));
+ ret_type);
let origin = infer::RelateOutputImplTypes(obligation.cause.span);
let obligation_ty = obligation.predicate.ty;
match infer::mk_eqty(infcx, true, origin, obligation_ty, ret_type) {
cause: ObligationCause<'tcx>,
value: &T)
-> Normalized<'tcx, T>
- where T : TypeFoldable<'tcx> + HasProjectionTypes + Clone + Repr<'tcx>
+ where T : TypeFoldable<'tcx> + HasProjectionTypes
{
normalize_with_depth(selcx, cause, 0, value)
}
depth: usize,
value: &T)
-> Normalized<'tcx, T>
- where T : TypeFoldable<'tcx> + HasProjectionTypes + Clone + Repr<'tcx>
+ where T : TypeFoldable<'tcx> + HasProjectionTypes
{
let mut normalizer = AssociatedTypeNormalizer::new(selcx, cause, depth);
let result = normalizer.fold(value);
+
Normalized {
value: result,
obligations: normalizer.obligations,
}
}
- fn fold<T:TypeFoldable<'tcx> + HasProjectionTypes + Clone>(&mut self, value: &T) -> T {
+ fn fold<T:TypeFoldable<'tcx> + HasProjectionTypes>(&mut self, value: &T) -> T {
let value = self.selcx.infcx().resolve_type_vars_if_possible(value);
if !value.has_projection_types() {
let ty = ty_fold::super_fold_ty(self, ty);
match ty.sty {
- ty::ty_projection(ref data) if !data.has_escaping_regions() => { // (*)
+ ty::TyProjection(ref data) if !data.has_escaping_regions() => { // (*)
// (*) This is kind of hacky -- we need to be able to
// handle normalization within binders because
data.clone(),
self.cause.clone(),
self.depth);
- self.obligations.extend(obligations.into_iter());
+ self.obligations.extend(obligations);
ty
}
-> Option<NormalizedTy<'tcx>>
{
debug!("normalize_projection_type(\
- projection_ty={}, \
+ projection_ty={:?}, \
depth={})",
- projection_ty.repr(selcx.tcx()),
+ projection_ty,
depth);
let obligation = Obligation::with_depth(cause.clone(), depth, projection_ty.clone());
// an impl, where-clause etc) and hence we must
// re-normalize it
- debug!("normalize_projection_type: projected_ty={} depth={} obligations={}",
- projected_ty.repr(selcx.tcx()),
+ debug!("normalize_projection_type: projected_ty={:?} depth={} obligations={:?}",
+ projected_ty,
depth,
- obligations.repr(selcx.tcx()));
+ obligations);
if ty::type_has_projection(projected_ty) {
- let tcx = selcx.tcx();
let mut normalizer = AssociatedTypeNormalizer::new(selcx, cause, depth);
let normalized_ty = normalizer.fold(&projected_ty);
- debug!("normalize_projection_type: normalized_ty={} depth={}",
- normalized_ty.repr(tcx),
+ debug!("normalize_projection_type: normalized_ty={:?} depth={}",
+ normalized_ty,
depth);
- obligations.extend(normalizer.obligations.into_iter());
+ obligations.extend(normalizer.obligations);
Some(Normalized {
value: normalized_ty,
obligations: obligations,
}
}
Ok(ProjectedTy::NoProgress(projected_ty)) => {
+ debug!("normalize_projection_type: projected_ty={:?} no progress",
+ projected_ty);
Some(Normalized {
value: projected_ty,
obligations: vec!()
})
}
Err(ProjectionTyError::TooManyCandidates) => {
+ debug!("normalize_projection_type: too many candidates");
None
}
Err(ProjectionTyError::TraitSelectionError(_)) => {
+ debug!("normalize_projection_type: ERROR");
// if we got an error processing the `T as Trait` part,
// just return `ty::err` but add the obligation `T :
// Trait`, which when processed will cause the error to be
}
}
-/// in various error cases, we just set ty_err and return an obligation
+/// in various error cases, we just set TyError and return an obligation
/// that, when fulfilled, will lead to an error.
///
-/// FIXME: the ty_err created here can enter the obligation we create,
-/// leading to error messages involving ty_err.
+/// FIXME: the TyError created here can enter the obligation we create,
+/// leading to error messages involving TyError.
fn normalize_to_error<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
projection_ty: ty::ProjectionTy<'tcx>,
cause: ObligationCause<'tcx>,
obligation: &ProjectionTyObligation<'tcx>)
-> Result<ProjectedTy<'tcx>, ProjectionTyError<'tcx>>
{
- debug!("project(obligation={})",
- obligation.repr(selcx.tcx()));
+ debug!("project(obligation={:?})",
+ obligation);
let recursion_limit = selcx.tcx().sess.recursion_limit.get();
if obligation.recursion_depth >= recursion_limit {
let obligation_trait_ref =
selcx.infcx().resolve_type_vars_if_possible(&obligation.predicate.trait_ref);
- debug!("project: obligation_trait_ref={}", obligation_trait_ref.repr(selcx.tcx()));
+ debug!("project: obligation_trait_ref={:?}", obligation_trait_ref);
if obligation_trait_ref.references_error() {
return Ok(ProjectedTy::Progress(selcx.tcx().types.err, vec!()));
obligation_trait_ref: &ty::TraitRef<'tcx>,
candidate_set: &mut ProjectionTyCandidateSet<'tcx>)
{
- let env_predicates = selcx.param_env().caller_bounds.clone();
+ let env_predicates = selcx.param_env().caller_bounds.iter().cloned();
assemble_candidates_from_predicates(selcx, obligation, obligation_trait_ref,
candidate_set, env_predicates);
}
{
// Check whether the self-type is itself a projection.
let trait_ref = match obligation_trait_ref.self_ty().sty {
- ty::ty_projection(ref data) => data.trait_ref.clone(),
- ty::ty_infer(ty::TyVar(_)) => {
+ ty::TyProjection(ref data) => data.trait_ref.clone(),
+ ty::TyInfer(ty::TyVar(_)) => {
// If the self-type is an inference variable, then it MAY wind up
// being a projected type, so induce an ambiguity.
candidate_set.ambiguous = true;
// If so, extract what we know from the trait and try to come up with a good answer.
let trait_predicates = ty::lookup_predicates(selcx.tcx(), trait_ref.def_id);
let bounds = trait_predicates.instantiate(selcx.tcx(), trait_ref.substs);
+ let bounds = elaborate_predicates(selcx.tcx(), bounds.predicates.into_vec());
assemble_candidates_from_predicates(selcx, obligation, obligation_trait_ref,
- candidate_set, bounds.predicates.into_vec());
+ candidate_set, bounds)
}
-fn assemble_candidates_from_predicates<'cx,'tcx>(
+fn assemble_candidates_from_predicates<'cx,'tcx,I>(
selcx: &mut SelectionContext<'cx,'tcx>,
obligation: &ProjectionTyObligation<'tcx>,
obligation_trait_ref: &ty::TraitRef<'tcx>,
candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
- env_predicates: Vec<ty::Predicate<'tcx>>)
+ env_predicates: I)
+ where I: Iterator<Item=ty::Predicate<'tcx>>
{
- debug!("assemble_candidates_from_predicates(obligation={}, env_predicates={})",
- obligation.repr(selcx.tcx()),
- env_predicates.repr(selcx.tcx()));
+ debug!("assemble_candidates_from_predicates(obligation={:?})",
+ obligation);
let infcx = selcx.infcx();
- for predicate in elaborate_predicates(selcx.tcx(), env_predicates) {
+ for predicate in env_predicates {
+ debug!("assemble_candidates_from_predicates: predicate={:?}",
+ predicate);
match predicate {
ty::Predicate::Projection(ref data) => {
let same_name = data.item_name() == obligation.predicate.item_name;
obligation_poly_trait_ref).is_ok()
});
- debug!("assemble_candidates_from_predicates: candidate {} is_match {} same_name {}",
- data.repr(selcx.tcx()),
- is_match,
- same_name);
+ debug!("assemble_candidates_from_predicates: candidate={:?} \
+ is_match={} same_name={}",
+ data, is_match, same_name);
if is_match {
candidate_set.vec.push(
candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
object_ty: Ty<'tcx>)
{
- let infcx = selcx.infcx();
- debug!("assemble_candidates_from_object_type(object_ty={})",
- object_ty.repr(infcx.tcx));
+ debug!("assemble_candidates_from_object_type(object_ty={:?})",
+ object_ty);
let data = match object_ty.sty {
- ty::ty_trait(ref data) => data,
+ ty::TyTrait(ref data) => data,
_ => {
selcx.tcx().sess.span_bug(
obligation.cause.span,
- &format!("assemble_candidates_from_object_type called with non-object: {}",
- object_ty.repr(selcx.tcx())));
+ &format!("assemble_candidates_from_object_type called with non-object: {:?}",
+ object_ty));
}
};
let projection_bounds = data.projection_bounds_with_self_ty(selcx.tcx(), object_ty);
let env_predicates = projection_bounds.iter()
.map(|p| p.as_predicate())
.collect();
+ let env_predicates = elaborate_predicates(selcx.tcx(), env_predicates);
assemble_candidates_from_predicates(selcx, obligation, obligation_trait_ref,
candidate_set, env_predicates)
}
return Ok(());
}
Err(e) => {
- debug!("assemble_candidates_from_impls: selection error {}",
- e.repr(selcx.tcx()));
+ debug!("assemble_candidates_from_impls: selection error {:?}",
+ e);
return Err(e);
}
};
match vtable {
super::VtableImpl(data) => {
- debug!("assemble_candidates_from_impls: impl candidate {}",
- data.repr(selcx.tcx()));
+ debug!("assemble_candidates_from_impls: impl candidate {:?}",
+ data);
candidate_set.vec.push(
ProjectionTyCandidate::Impl(data));
selcx, obligation, obligation_trait_ref, candidate_set,
data.object_ty);
}
- super::VtableClosure(closure_def_id, substs) => {
+ super::VtableClosure(data) => {
candidate_set.vec.push(
- ProjectionTyCandidate::Closure(closure_def_id, substs));
+ ProjectionTyCandidate::Closure(data));
}
super::VtableFnPointer(fn_type) => {
candidate_set.vec.push(
// These traits have no associated types.
selcx.tcx().sess.span_bug(
obligation.cause.span,
- &format!("Cannot project an associated type from `{}`",
- vtable.repr(selcx.tcx())));
+ &format!("Cannot project an associated type from `{:?}`",
+ vtable));
}
}
candidate: ProjectionTyCandidate<'tcx>)
-> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
{
- let infcx = selcx.infcx();
-
- debug!("confirm_candidate(candidate={}, obligation={})",
- candidate.repr(infcx.tcx),
- obligation.repr(infcx.tcx));
+ debug!("confirm_candidate(candidate={:?}, obligation={:?})",
+ candidate,
+ obligation);
match candidate {
ProjectionTyCandidate::ParamEnv(poly_projection) => {
confirm_impl_candidate(selcx, obligation, impl_vtable)
}
- ProjectionTyCandidate::Closure(def_id, substs) => {
- confirm_closure_candidate(selcx, obligation, def_id, &substs)
+ ProjectionTyCandidate::Closure(closure_vtable) => {
+ confirm_closure_candidate(selcx, obligation, closure_vtable)
}
ProjectionTyCandidate::FnPointer(fn_type) => {
fn confirm_closure_candidate<'cx,'tcx>(
selcx: &mut SelectionContext<'cx,'tcx>,
obligation: &ProjectionTyObligation<'tcx>,
- closure_def_id: ast::DefId,
- substs: &Substs<'tcx>)
+ vtable: VtableClosureData<'tcx, PredicateObligation<'tcx>>)
-> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
{
let closure_typer = selcx.closure_typer();
- let closure_type = closure_typer.closure_type(closure_def_id, substs);
- confirm_callable_candidate(selcx, obligation, &closure_type.sig, util::TupleArgumentsFlag::No)
+ let closure_type = closure_typer.closure_type(vtable.closure_def_id, &vtable.substs);
+ let Normalized {
+ value: closure_type,
+ mut obligations
+ } = normalize_with_depth(selcx,
+ obligation.cause.clone(),
+ obligation.recursion_depth+1,
+ &closure_type);
+ let (ty, mut cc_obligations) = confirm_callable_candidate(selcx,
+ obligation,
+ &closure_type.sig,
+ util::TupleArgumentsFlag::No);
+ obligations.append(&mut cc_obligations);
+ (ty, obligations)
}
fn confirm_callable_candidate<'cx,'tcx>(
{
let tcx = selcx.tcx();
- debug!("confirm_closure_candidate({},{})",
- obligation.repr(tcx),
- fn_sig.repr(tcx));
+ debug!("confirm_callable_candidate({:?},{:?})",
+ obligation,
+ fn_sig);
// the `Output` associated type is declared on `FnOnce`
let fn_once_def_id = tcx.lang_items.fn_once_trait().unwrap();
Err(e) => {
selcx.tcx().sess.span_bug(
obligation.cause.span,
- &format!("Failed to unify `{}` and `{}` in projection: {}",
- obligation.repr(selcx.tcx()),
- projection.repr(selcx.tcx()),
- ty::type_err_to_str(selcx.tcx(), &e)));
+ &format!("Failed to unify `{:?}` and `{:?}` in projection: {}",
+ obligation,
+ projection,
+ e));
}
}
-> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
{
// there don't seem to be nicer accessors to these:
- let impl_items_map = selcx.tcx().impl_items.borrow();
let impl_or_trait_items_map = selcx.tcx().impl_or_trait_items.borrow();
- let impl_items = impl_items_map.get(&impl_vtable.impl_def_id).unwrap();
- let mut impl_ty = None;
- for impl_item in impl_items {
- let assoc_type = match *impl_or_trait_items_map.get(&impl_item.def_id()).unwrap() {
- ty::TypeTraitItem(ref assoc_type) => assoc_type.clone(),
- ty::ConstTraitItem(..) | ty::MethodTraitItem(..) => { continue; }
- };
-
- if assoc_type.name != obligation.predicate.item_name {
- continue;
- }
-
- let impl_poly_ty = ty::lookup_item_type(selcx.tcx(), assoc_type.def_id);
- impl_ty = Some(impl_poly_ty.ty.subst(selcx.tcx(), &impl_vtable.substs));
- break;
- }
-
- match impl_ty {
- Some(ty) => (ty, impl_vtable.nested.into_vec()),
- None => {
- // This means that the impl is missing a
- // definition for the associated type. This error
- // ought to be reported by the type checker method
- // `check_impl_items_against_trait`, so here we
- // just return ty_err.
- (selcx.tcx().types.err, vec!())
+ // Look for the associated type in the impl
+ for impl_item in &selcx.tcx().impl_items.borrow()[&impl_vtable.impl_def_id] {
+ if let ty::TypeTraitItem(ref assoc_ty) = impl_or_trait_items_map[&impl_item.def_id()] {
+ if assoc_ty.name == obligation.predicate.item_name {
+ return (assoc_ty.ty.unwrap().subst(selcx.tcx(), &impl_vtable.substs),
+ impl_vtable.nested);
+ }
}
}
-}
-impl<'tcx> Repr<'tcx> for ProjectionTyError<'tcx> {
- fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
- match *self {
- ProjectionTyError::TooManyCandidates =>
- format!("NoCandidate"),
- ProjectionTyError::TraitSelectionError(ref e) =>
- format!("TraitSelectionError({})", e.repr(tcx)),
+ // It is not in the impl - get the default from the trait.
+ let trait_ref = obligation.predicate.trait_ref;
+ for trait_item in ty::trait_items(selcx.tcx(), trait_ref.def_id).iter() {
+ if let &ty::TypeTraitItem(ref assoc_ty) = trait_item {
+ if assoc_ty.name == obligation.predicate.item_name {
+ if let Some(ty) = assoc_ty.ty {
+ return (ty.subst(selcx.tcx(), trait_ref.substs),
+ impl_vtable.nested);
+ } else {
+ // This means that the impl is missing a
+ // definition for the associated type. This error
+ // ought to be reported by the type checker method
+ // `check_impl_items_against_trait`, so here we
+ // just return TyError.
+ return (selcx.tcx().types.err, vec!());
+ }
+ }
}
}
-}
-impl<'tcx> Repr<'tcx> for ProjectionTyCandidate<'tcx> {
- fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
- match *self {
- ProjectionTyCandidate::ParamEnv(ref data) =>
- format!("ParamEnv({})", data.repr(tcx)),
- ProjectionTyCandidate::Impl(ref data) =>
- format!("Impl({})", data.repr(tcx)),
- ProjectionTyCandidate::Closure(ref a, ref b) =>
- format!("Closure(({},{}))", a.repr(tcx), b.repr(tcx)),
- ProjectionTyCandidate::FnPointer(a) =>
- format!("FnPointer(({}))", a.repr(tcx)),
- }
- }
+ selcx.tcx().sess.span_bug(obligation.cause.span,
+ &format!("No associated type for {:?}",
+ trait_ref));
}
impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Normalized<'tcx, T> {
}
}
-impl<'tcx, T:Repr<'tcx>> Repr<'tcx> for Normalized<'tcx, T> {
- fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
- format!("Normalized({},{})",
- self.value.repr(tcx),
- self.obligations.repr(tcx))
+impl<'tcx, T:fmt::Debug> fmt::Debug for Normalized<'tcx, T> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "Normalized({:?},{:?})",
+ self.value,
+ self.obligations)
}
}
use super::SelectionResult;
use super::{VtableBuiltin, VtableImpl, VtableParam, VtableClosure,
VtableFnPointer, VtableObject, VtableDefaultImpl};
-use super::{VtableImplData, VtableObjectData, VtableBuiltinData, VtableDefaultImplData};
+use super::{VtableImplData, VtableObjectData, VtableBuiltinData,
+ VtableClosureData, VtableDefaultImplData};
use super::object_safety;
use super::util;
use middle::fast_reject;
-use middle::subst::{Subst, Substs, TypeSpace, VecPerParamSpace};
+use middle::subst::{Subst, Substs, TypeSpace};
use middle::ty::{self, AsPredicate, RegionEscape, ToPolyTraitRef, Ty};
use middle::infer;
use middle::infer::{InferCtxt, TypeFreshener};
use middle::ty_fold::TypeFoldable;
use middle::ty_match;
use middle::ty_relate::TypeRelation;
+
use std::cell::RefCell;
+use std::fmt;
use std::rc::Rc;
use syntax::{abi, ast};
use util::common::ErrorReported;
use util::nodemap::FnvHashMap;
-use util::ppaux::Repr;
pub struct SelectionContext<'cx, 'tcx:'cx> {
infcx: &'cx InferCtxt<'cx, 'tcx>,
/// type environment by performing unification.
pub fn select(&mut self, obligation: &TraitObligation<'tcx>)
-> SelectionResult<'tcx, Selection<'tcx>> {
- debug!("select({})", obligation.repr(self.tcx()));
+ debug!("select({:?})", obligation);
assert!(!obligation.predicate.has_escaping_regions());
let stack = self.push_stack(TraitObligationStackList::empty(), obligation);
// lifetimes can appear inside the self-type.
let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder());
let (closure_def_id, substs) = match self_ty.sty {
- ty::ty_closure(id, ref substs) => (id, substs.clone()),
+ ty::TyClosure(id, ref substs) => (id, substs.clone()),
_ => { return; }
};
assert!(!substs.has_escaping_regions());
- let closure_trait_ref = self.closure_trait_ref(obligation, closure_def_id, substs);
+ // It is OK to call the unnormalized variant here - this is only
+ // reached for TyClosure: Fn inputs where the closure kind is
+ // still unknown, which should only occur in typeck where the
+ // closure type is already normalized.
+ let closure_trait_ref = self.closure_trait_ref_unnormalized(obligation,
+ closure_def_id,
+ substs);
+
match self.confirm_poly_trait_refs(obligation.cause.clone(),
obligation.predicate.to_poly_trait_ref(),
closure_trait_ref) {
obligation: &PredicateObligation<'tcx>)
-> bool
{
- debug!("evaluate_obligation({})",
- obligation.repr(self.tcx()));
+ debug!("evaluate_obligation({:?})",
+ obligation);
self.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation)
.may_apply()
obligation: &PredicateObligation<'tcx>)
-> EvaluationResult<'tcx>
{
- debug!("evaluate_predicate_recursively({})",
- obligation.repr(self.tcx()));
+ debug!("evaluate_predicate_recursively({:?})",
+ obligation);
+
+ // Check the cache from the tcx of predicates that we know
+ // have been proven elsewhere. This cache only contains
+ // predicates that are global in scope and hence unaffected by
+ // the current environment.
+ if self.tcx().fulfilled_predicates.borrow().is_duplicate(&obligation.predicate) {
+ return EvaluatedToOk;
+ }
match obligation.predicate {
ty::Predicate::Trait(ref t) => {
obligation: &TraitObligation<'tcx>)
-> EvaluationResult<'tcx>
{
- debug!("evaluate_obligation_recursively({})",
- obligation.repr(self.tcx()));
+ debug!("evaluate_obligation_recursively({:?})",
+ obligation);
let stack = self.push_stack(previous_stack, obligation);
|prev| self.match_fresh_trait_refs(&stack.fresh_trait_ref,
&prev.fresh_trait_ref)))
{
- debug!("evaluate_stack({}) --> unbound argument, recursion --> ambiguous",
- stack.fresh_trait_ref.repr(self.tcx()));
+ debug!("evaluate_stack({:?}) --> unbound argument, recursion --> ambiguous",
+ stack.fresh_trait_ref);
return EvaluatedToAmbig;
}
.skip(1) // skip top-most frame
.any(|prev| stack.fresh_trait_ref == prev.fresh_trait_ref)
{
- debug!("evaluate_stack({}) --> recursive",
- stack.fresh_trait_ref.repr(self.tcx()));
+ debug!("evaluate_stack({:?}) --> recursive",
+ stack.fresh_trait_ref);
return EvaluatedToOk;
}
obligation: &TraitObligation<'tcx>)
-> bool
{
- debug!("evaluate_impl(impl_def_id={}, obligation={})",
- impl_def_id.repr(self.tcx()),
- obligation.repr(self.tcx()));
+ debug!("evaluate_impl(impl_def_id={:?}, obligation={:?})",
+ impl_def_id,
+ obligation);
self.infcx.probe(|snapshot| {
match self.match_impl(impl_def_id, obligation, snapshot) {
// with fresh skolemized types starting from index 0.
let cache_fresh_trait_pred =
self.infcx.freshen(stack.obligation.predicate.clone());
- debug!("candidate_from_obligation(cache_fresh_trait_pred={}, obligation={})",
- cache_fresh_trait_pred.repr(self.tcx()),
- stack.repr(self.tcx()));
+ debug!("candidate_from_obligation(cache_fresh_trait_pred={:?}, obligation={:?})",
+ cache_fresh_trait_pred,
+ stack);
assert!(!stack.obligation.predicate.has_escaping_regions());
match self.check_candidate_cache(&cache_fresh_trait_pred) {
Some(c) => {
- debug!("CACHE HIT: cache_fresh_trait_pred={}, candidate={}",
- cache_fresh_trait_pred.repr(self.tcx()),
- c.repr(self.tcx()));
+ debug!("CACHE HIT: cache_fresh_trait_pred={:?}, candidate={:?}",
+ cache_fresh_trait_pred,
+ c);
return c;
}
None => { }
let candidate = self.candidate_from_obligation_no_cache(stack);
if self.should_update_candidate_cache(&cache_fresh_trait_pred, &candidate) {
- debug!("CACHE MISS: cache_fresh_trait_pred={}, candidate={}",
- cache_fresh_trait_pred.repr(self.tcx()), candidate.repr(self.tcx()));
+ debug!("CACHE MISS: cache_fresh_trait_pred={:?}, candidate={:?}",
+ cache_fresh_trait_pred, candidate);
self.insert_candidate_cache(cache_fresh_trait_pred, candidate.clone());
}
let mut candidates = candidate_set.vec;
- debug!("assembled {} candidates for {}: {}",
+ debug!("assembled {} candidates for {:?}: {:?}",
candidates.len(),
- stack.repr(self.tcx()),
- candidates.repr(self.tcx()));
+ stack,
+ candidates);
// At this point, we know that each of the entries in the
// candidate set is *individually* applicable. Now we have to
.any(|j| self.candidate_should_be_dropped_in_favor_of(&candidates[i],
&candidates[j]));
if is_dup {
- debug!("Dropping candidate #{}/{}: {}",
- i, candidates.len(), candidates[i].repr(self.tcx()));
+ debug!("Dropping candidate #{}/{}: {:?}",
+ i, candidates.len(), candidates[i]);
candidates.swap_remove(i);
} else {
- debug!("Retaining candidate #{}/{}: {}",
- i, candidates.len(), candidates[i].repr(self.tcx()));
+ debug!("Retaining candidate #{}/{}: {:?}",
+ i, candidates.len(), candidates[i]);
i += 1;
}
}
match self.tcx().lang_items.to_builtin_kind(obligation.predicate.def_id()) {
Some(ty::BoundCopy) => {
- debug!("obligation self ty is {}",
- obligation.predicate.0.self_ty().repr(self.tcx()));
+ debug!("obligation self ty is {:?}",
+ obligation.predicate.0.self_ty());
// User-defined copy impls are permitted, but only for
// structs and enums.
let poly_trait_predicate =
self.infcx().resolve_type_vars_if_possible(&obligation.predicate);
- debug!("assemble_candidates_for_projected_tys({},{})",
- obligation.repr(self.tcx()),
- poly_trait_predicate.repr(self.tcx()));
+ debug!("assemble_candidates_for_projected_tys({:?},{:?})",
+ obligation,
+ poly_trait_predicate);
// FIXME(#20297) -- just examining the self-type is very simplistic
// before we go into the whole skolemization thing, just
// quickly check if the self-type is a projection at all.
let trait_def_id = match poly_trait_predicate.0.trait_ref.self_ty().sty {
- ty::ty_projection(ref data) => data.trait_ref.def_id,
- ty::ty_infer(ty::TyVar(_)) => {
+ ty::TyProjection(ref data) => data.trait_ref.def_id,
+ ty::TyInfer(ty::TyVar(_)) => {
// If the self-type is an inference variable, then it MAY wind up
// being a projected type, so induce an ambiguity.
//
_ => { return; }
};
- debug!("assemble_candidates_for_projected_tys: trait_def_id={}",
- trait_def_id.repr(self.tcx()));
+ debug!("assemble_candidates_for_projected_tys: trait_def_id={:?}",
+ trait_def_id);
let result = self.infcx.probe(|snapshot| {
self.match_projection_obligation_against_bounds_from_trait(obligation,
let (skol_trait_predicate, skol_map) =
self.infcx().skolemize_late_bound_regions(&poly_trait_predicate, snapshot);
debug!("match_projection_obligation_against_bounds_from_trait: \
- skol_trait_predicate={} skol_map={}",
- skol_trait_predicate.repr(self.tcx()),
- skol_map.repr(self.tcx()));
+ skol_trait_predicate={:?} skol_map={:?}",
+ skol_trait_predicate,
+ skol_map);
let projection_trait_ref = match skol_trait_predicate.trait_ref.self_ty().sty {
- ty::ty_projection(ref data) => &data.trait_ref,
+ ty::TyProjection(ref data) => &data.trait_ref,
_ => {
self.tcx().sess.span_bug(
obligation.cause.span,
&format!("match_projection_obligation_against_bounds_from_trait() called \
- but self-ty not a projection: {}",
- skol_trait_predicate.trait_ref.self_ty().repr(self.tcx())));
+ but self-ty not a projection: {:?}",
+ skol_trait_predicate.trait_ref.self_ty()));
}
};
debug!("match_projection_obligation_against_bounds_from_trait: \
- projection_trait_ref={}",
- projection_trait_ref.repr(self.tcx()));
+ projection_trait_ref={:?}",
+ projection_trait_ref);
let trait_predicates = ty::lookup_predicates(self.tcx(), projection_trait_ref.def_id);
let bounds = trait_predicates.instantiate(self.tcx(), projection_trait_ref.substs);
debug!("match_projection_obligation_against_bounds_from_trait: \
- bounds={}",
- bounds.repr(self.tcx()));
+ bounds={:?}",
+ bounds);
let matching_bound =
util::elaborate_predicates(self.tcx(), bounds.predicates.into_vec())
snapshot)));
debug!("match_projection_obligation_against_bounds_from_trait: \
- matching_bound={}",
- matching_bound.repr(self.tcx()));
+ matching_bound={:?}",
+ matching_bound);
match matching_bound {
None => false,
Some(bound) => {
candidates: &mut SelectionCandidateSet<'tcx>)
-> Result<(),SelectionError<'tcx>>
{
- debug!("assemble_candidates_from_caller_bounds({})",
- stack.obligation.repr(self.tcx()));
-
- let caller_trait_refs: Vec<_> =
- self.param_env().caller_bounds.iter()
- .filter_map(|o| o.to_opt_poly_trait_ref())
- .collect();
+ debug!("assemble_candidates_from_caller_bounds({:?})",
+ stack.obligation);
let all_bounds =
- util::transitive_bounds(
- self.tcx(), &caller_trait_refs[..]);
+ self.param_env().caller_bounds
+ .iter()
+ .filter_map(|o| o.to_opt_poly_trait_ref());
let matching_bounds =
all_bounds.filter(
// type/region parameters
let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder());
let (closure_def_id, substs) = match self_ty.sty {
- ty::ty_closure(id, ref substs) => (id, substs.clone()),
- ty::ty_infer(ty::TyVar(_)) => {
+ ty::TyClosure(id, substs) => (id, substs),
+ ty::TyInfer(ty::TyVar(_)) => {
debug!("assemble_unboxed_closure_candidates: ambiguous self-type");
candidates.ambiguous = true;
return Ok(());
_ => { return Ok(()); }
};
- debug!("assemble_unboxed_candidates: self_ty={} kind={:?} obligation={}",
- self_ty.repr(self.tcx()),
+ debug!("assemble_unboxed_candidates: self_ty={:?} kind={:?} obligation={:?}",
+ self_ty,
kind,
- obligation.repr(self.tcx()));
+ obligation);
match self.closure_typer.closure_kind(closure_def_id) {
Some(closure_kind) => {
debug!("assemble_unboxed_candidates: closure_kind = {:?}", closure_kind);
if closure_kind.extends(kind) {
- candidates.vec.push(ClosureCandidate(closure_def_id, substs.clone()));
+ candidates.vec.push(ClosureCandidate(closure_def_id,
+ substs.clone()));
}
}
None => {
// ok to skip binder because what we are inspecting doesn't involve bound regions
let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder());
match self_ty.sty {
- ty::ty_infer(ty::TyVar(_)) => {
+ ty::TyInfer(ty::TyVar(_)) => {
debug!("assemble_fn_pointer_candidates: ambiguous self-type");
candidates.ambiguous = true; // could wind up being a fn() type
}
// provide an impl, but only for suitable `fn` pointers
- ty::ty_bare_fn(_, &ty::BareFnTy {
+ ty::TyBareFn(_, &ty::BareFnTy {
unsafety: ast::Unsafety::Normal,
abi: abi::Rust,
sig: ty::Binder(ty::FnSig {
candidates: &mut SelectionCandidateSet<'tcx>)
-> Result<(), SelectionError<'tcx>>
{
- debug!("assemble_candidates_from_impls(obligation={})", obligation.repr(self.tcx()));
+ debug!("assemble_candidates_from_impls(obligation={:?})", obligation);
let def = ty::lookup_trait_def(self.tcx(), obligation.predicate.def_id());
{
// OK to skip binder here because the tests we do below do not involve bound regions
let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder());
- debug!("assemble_candidates_from_default_impls(self_ty={})", self_ty.repr(self.tcx()));
+ debug!("assemble_candidates_from_default_impls(self_ty={:?})", self_ty);
let def_id = obligation.predicate.def_id();
if ty::trait_has_default_impl(self.tcx(), def_id) {
match self_ty.sty {
- ty::ty_trait(..) => {
+ ty::TyTrait(..) => {
// For object types, we don't know what the closed
// over types are. For most traits, this means we
// conservatively say nothing; a candidate may be
candidates.vec.push(DefaultImplObjectCandidate(def_id));
}
}
- ty::ty_param(..) |
- ty::ty_projection(..) => {
+ ty::TyParam(..) |
+ ty::TyProjection(..) => {
// In these cases, we don't know what the actual
// type is. Therefore, we cannot break it down
// into its constituent types. So we don't
// for an example of a test case that exercises
// this path.
}
- ty::ty_infer(ty::TyVar(_)) => {
+ ty::TyInfer(ty::TyVar(_)) => {
// the defaulted impl might apply, we don't know
candidates.ambiguous = true;
}
obligation: &TraitObligation<'tcx>,
candidates: &mut SelectionCandidateSet<'tcx>)
{
- debug!("assemble_candidates_from_object_ty(self_ty={})",
- self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()).repr(self.tcx()));
+ debug!("assemble_candidates_from_object_ty(self_ty={:?})",
+ self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()));
// Object-safety candidates are only applicable to object-safe
// traits. Including this check is useful because it helps
let (self_ty, _) =
self.infcx().skolemize_late_bound_regions(&bound_self_ty, snapshot);
let poly_trait_ref = match self_ty.sty {
- ty::ty_trait(ref data) => {
+ ty::TyTrait(ref data) => {
match self.tcx().lang_items.to_builtin_kind(obligation.predicate.def_id()) {
Some(bound @ ty::BoundSend) | Some(bound @ ty::BoundSync) => {
if data.bounds.builtin_bounds.contains(&bound) {
data.principal_trait_ref_with_self_ty(self.tcx(), self_ty)
}
- ty::ty_infer(ty::TyVar(_)) => {
+ ty::TyInfer(ty::TyVar(_)) => {
debug!("assemble_candidates_from_object_ty: ambiguous");
candidates.ambiguous = true; // could wind up being an object type
return Ok(());
}
};
- debug!("assemble_candidates_from_object_ty: poly_trait_ref={}",
- poly_trait_ref.repr(self.tcx()));
+ debug!("assemble_candidates_from_object_ty: poly_trait_ref={:?}",
+ poly_trait_ref);
// see whether the object trait can be upcast to the trait we are looking for
let upcast_trait_refs = self.upcast(poly_trait_ref, obligation);
let source = self.infcx.shallow_resolve(self_ty);
let target = self.infcx.shallow_resolve(obligation.predicate.0.input_types()[0]);
- debug!("assemble_candidates_for_unsizing(source={}, target={})",
- source.repr(self.tcx()), target.repr(self.tcx()));
+ debug!("assemble_candidates_for_unsizing(source={:?}, target={:?})",
+ source, target);
let may_apply = match (&source.sty, &target.sty) {
// Trait+Kx+'a -> Trait+Ky+'b (upcasts).
- (&ty::ty_trait(ref data_a), &ty::ty_trait(ref data_b)) => {
+ (&ty::TyTrait(ref data_a), &ty::TyTrait(ref data_b)) => {
// Upcasts permit two things:
//
// 1. Dropping builtin bounds, e.g. `Foo+Send` to `Foo`
}
// T -> Trait.
- (_, &ty::ty_trait(_)) => true,
+ (_, &ty::TyTrait(_)) => true,
// Ambiguous handling is below T -> Trait, because inference
// variables can still implement Unsize<Trait> and nested
// obligations will have the final say (likely deferred).
- (&ty::ty_infer(ty::TyVar(_)), _) |
- (_, &ty::ty_infer(ty::TyVar(_))) => {
+ (&ty::TyInfer(ty::TyVar(_)), _) |
+ (_, &ty::TyInfer(ty::TyVar(_))) => {
debug!("assemble_candidates_for_unsizing: ambiguous");
candidates.ambiguous = true;
false
}
// [T; n] -> [T].
- (&ty::ty_vec(_, Some(_)), &ty::ty_vec(_, None)) => true,
+ (&ty::TyArray(_, _), &ty::TySlice(_)) => true,
// Struct<T> -> Struct<U>.
- (&ty::ty_struct(def_id_a, _), &ty::ty_struct(def_id_b, _)) => {
+ (&ty::TyStruct(def_id_a, _), &ty::TyStruct(def_id_b, _)) => {
def_id_a == def_id_b
}
candidate: &SelectionCandidate<'tcx>)
-> EvaluationResult<'tcx>
{
- debug!("winnow_candidate: candidate={}", candidate.repr(self.tcx()));
+ debug!("winnow_candidate: candidate={:?}", candidate);
let result = self.infcx.probe(|_| {
let candidate = (*candidate).clone();
match self.confirm_candidate(stack.obligation, candidate) {
selection: Selection<'tcx>)
-> EvaluationResult<'tcx>
{
- self.evaluate_predicates_recursively(stack, selection.iter_nested())
+ self.evaluate_predicates_recursively(stack,
+ selection.nested_obligations().iter())
}
/// Returns true if `candidate_i` should be dropped in favor of
{
match self.builtin_bound(bound, stack.obligation) {
Ok(If(..)) => {
- debug!("builtin_bound: bound={}",
- bound.repr(self.tcx()));
+ debug!("builtin_bound: bound={:?}",
+ bound);
candidates.vec.push(BuiltinCandidate(bound));
Ok(())
}
let self_ty = self.infcx.shallow_resolve(obligation.predicate.0.self_ty());
return match self_ty.sty {
- ty::ty_infer(ty::IntVar(_)) |
- ty::ty_infer(ty::FloatVar(_)) |
- ty::ty_uint(_) |
- ty::ty_int(_) |
- ty::ty_bool |
- ty::ty_float(_) |
- ty::ty_bare_fn(..) |
- ty::ty_char => {
+ ty::TyInfer(ty::IntVar(_)) |
+ ty::TyInfer(ty::FloatVar(_)) |
+ ty::TyUint(_) |
+ ty::TyInt(_) |
+ ty::TyBool |
+ ty::TyFloat(_) |
+ ty::TyBareFn(..) |
+ ty::TyChar => {
// safe for everything
ok_if(Vec::new())
}
- ty::ty_uniq(_) => { // Box<T>
+ ty::TyBox(_) => { // Box<T>
match bound {
ty::BoundCopy => Err(Unimplemented),
}
}
- ty::ty_ptr(..) => { // *const T, *mut T
+ ty::TyRawPtr(..) => { // *const T, *mut T
match bound {
ty::BoundCopy | ty::BoundSized => ok_if(Vec::new()),
}
}
- ty::ty_trait(ref data) => {
+ ty::TyTrait(ref data) => {
match bound {
ty::BoundSized => Err(Unimplemented),
ty::BoundCopy => {
}
}
- ty::ty_rptr(_, ty::mt { ty: _, mutbl }) => {
+ ty::TyRef(_, ty::mt { ty: _, mutbl }) => {
// &mut T or &T
match bound {
ty::BoundCopy => {
}
}
- ty::ty_vec(element_ty, ref len) => {
- // [T, ..n] and [T]
+ ty::TyArray(element_ty, _) => {
+ // [T; n]
match bound {
- ty::BoundCopy => {
- match *len {
- // [T, ..n] is copy iff T is copy
- Some(_) => ok_if(vec![element_ty]),
-
- // [T] is unsized and hence affine
- None => Err(Unimplemented),
- }
- }
-
- ty::BoundSized => {
- if len.is_some() {
- ok_if(Vec::new())
- } else {
- Err(Unimplemented)
- }
- }
-
+ ty::BoundCopy => ok_if(vec![element_ty]),
+ ty::BoundSized => ok_if(Vec::new()),
ty::BoundSync | ty::BoundSend => {
self.tcx().sess.bug("Send/Sync shouldn't occur in builtin_bounds()");
}
}
}
- ty::ty_str => {
- // Equivalent to [u8]
+ ty::TyStr | ty::TySlice(_) => {
match bound {
ty::BoundSync | ty::BoundSend => {
self.tcx().sess.bug("Send/Sync shouldn't occur in builtin_bounds()");
}
// (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
- ty::ty_tup(ref tys) => ok_if(tys.clone()),
+ ty::TyTuple(ref tys) => ok_if(tys.clone()),
- ty::ty_closure(def_id, substs) => {
+ ty::TyClosure(def_id, substs) => {
// FIXME -- This case is tricky. In the case of by-ref
// closures particularly, we need the results of
// inference to decide how to reflect the type of each
}
}
- ty::ty_struct(def_id, substs) => {
+ ty::TyStruct(def_id, substs) => {
let types: Vec<Ty> =
ty::struct_fields(self.tcx(), def_id, substs).iter()
.map(|f| f.mt.ty)
nominal(bound, types)
}
- ty::ty_enum(def_id, substs) => {
+ ty::TyEnum(def_id, substs) => {
let types: Vec<Ty> =
ty::substd_enum_variants(self.tcx(), def_id, substs)
.iter()
- .flat_map(|variant| variant.args.iter())
+ .flat_map(|variant| &variant.args)
.cloned()
.collect();
nominal(bound, types)
}
- ty::ty_projection(_) | ty::ty_param(_) => {
+ ty::TyProjection(_) | ty::TyParam(_) => {
// Note: A type parameter is only considered to meet a
// particular bound if there is a where clause telling
// us that it does, and that case is handled by
Ok(ParameterBuiltin)
}
- ty::ty_infer(ty::TyVar(_)) => {
+ ty::TyInfer(ty::TyVar(_)) => {
// Unbound type variable. Might or might not have
// applicable impls and so forth, depending on what
// those type variables wind up being bound to.
Ok(AmbiguousBuiltin)
}
- ty::ty_err => ok_if(Vec::new()),
+ ty::TyError => ok_if(Vec::new()),
- ty::ty_infer(ty::FreshTy(_))
- | ty::ty_infer(ty::FreshIntTy(_))
- | ty::ty_infer(ty::FreshFloatTy(_)) => {
+ ty::TyInfer(ty::FreshTy(_))
+ | ty::TyInfer(ty::FreshIntTy(_))
+ | ty::TyInfer(ty::FreshFloatTy(_)) => {
self.tcx().sess.bug(
&format!(
- "asked to assemble builtin bounds of unexpected type: {}",
- self_ty.repr(self.tcx())));
+ "asked to assemble builtin bounds of unexpected type: {:?}",
+ self_ty));
}
};
/// ```
fn constituent_types_for_ty(&self, t: Ty<'tcx>) -> Option<Vec<Ty<'tcx>>> {
match t.sty {
- ty::ty_uint(_) |
- ty::ty_int(_) |
- ty::ty_bool |
- ty::ty_float(_) |
- ty::ty_bare_fn(..) |
- ty::ty_str |
- ty::ty_err |
- ty::ty_infer(ty::IntVar(_)) |
- ty::ty_infer(ty::FloatVar(_)) |
- ty::ty_char => {
+ ty::TyUint(_) |
+ ty::TyInt(_) |
+ ty::TyBool |
+ ty::TyFloat(_) |
+ ty::TyBareFn(..) |
+ ty::TyStr |
+ ty::TyError |
+ ty::TyInfer(ty::IntVar(_)) |
+ ty::TyInfer(ty::FloatVar(_)) |
+ ty::TyChar => {
Some(Vec::new())
}
- ty::ty_trait(..) |
- ty::ty_param(..) |
- ty::ty_projection(..) |
- ty::ty_infer(ty::TyVar(_)) |
- ty::ty_infer(ty::FreshTy(_)) |
- ty::ty_infer(ty::FreshIntTy(_)) |
- ty::ty_infer(ty::FreshFloatTy(_)) => {
+ ty::TyTrait(..) |
+ ty::TyParam(..) |
+ ty::TyProjection(..) |
+ ty::TyInfer(ty::TyVar(_)) |
+ ty::TyInfer(ty::FreshTy(_)) |
+ ty::TyInfer(ty::FreshIntTy(_)) |
+ ty::TyInfer(ty::FreshFloatTy(_)) => {
self.tcx().sess.bug(
&format!(
- "asked to assemble constituent types of unexpected type: {}",
- t.repr(self.tcx())));
+ "asked to assemble constituent types of unexpected type: {:?}",
+ t));
}
- ty::ty_uniq(referent_ty) => { // Box<T>
+ ty::TyBox(referent_ty) => { // Box<T>
Some(vec![referent_ty])
}
- ty::ty_ptr(ty::mt { ty: element_ty, ..}) |
- ty::ty_rptr(_, ty::mt { ty: element_ty, ..}) => {
+ ty::TyRawPtr(ty::mt { ty: element_ty, ..}) |
+ ty::TyRef(_, ty::mt { ty: element_ty, ..}) => {
Some(vec![element_ty])
},
- ty::ty_vec(element_ty, _) => {
+ ty::TyArray(element_ty, _) | ty::TySlice(element_ty) => {
Some(vec![element_ty])
}
- ty::ty_tup(ref tys) => {
+ ty::TyTuple(ref tys) => {
// (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
Some(tys.clone())
}
- ty::ty_closure(def_id, substs) => {
+ ty::TyClosure(def_id, substs) => {
assert_eq!(def_id.krate, ast::LOCAL_CRATE);
match self.closure_typer.closure_upvars(def_id, substs) {
}
// for `PhantomData<T>`, we pass `T`
- ty::ty_struct(def_id, substs)
+ ty::TyStruct(def_id, substs)
if Some(def_id) == self.tcx().lang_items.phantom_data() =>
{
Some(substs.types.get_slice(TypeSpace).to_vec())
}
- ty::ty_struct(def_id, substs) => {
+ ty::TyStruct(def_id, substs) => {
Some(ty::struct_fields(self.tcx(), def_id, substs).iter()
.map(|f| f.mt.ty)
.collect())
}
- ty::ty_enum(def_id, substs) => {
+ ty::TyEnum(def_id, substs) => {
Some(ty::substd_enum_variants(self.tcx(), def_id, substs)
.iter()
- .flat_map(|variant| variant.args.iter())
+ .flat_map(|variant| &variant.args)
.map(|&ty| ty)
.collect())
}
// Flatten those vectors (couldn't do it above due `collect`)
match obligations {
- Ok(obligations) => obligations.into_iter().flat_map(|o| o.into_iter()).collect(),
+ Ok(obligations) => obligations.into_iter().flat_map(|o| o).collect(),
Err(ErrorReported) => Vec::new(),
}
}
candidate: SelectionCandidate<'tcx>)
-> Result<Selection<'tcx>,SelectionError<'tcx>>
{
- debug!("confirm_candidate({}, {})",
- obligation.repr(self.tcx()),
- candidate.repr(self.tcx()));
+ debug!("confirm_candidate({:?}, {:?})",
+ obligation,
+ candidate);
match candidate {
BuiltinCandidate(builtin_bound) => {
PhantomFnCandidate |
ErrorCandidate => {
- Ok(VtableBuiltin(VtableBuiltinData { nested: VecPerParamSpace::empty() }))
+ Ok(VtableBuiltin(VtableBuiltinData { nested: vec![] }))
}
ParamCandidate(param) => {
}
ClosureCandidate(closure_def_id, substs) => {
- try!(self.confirm_closure_candidate(obligation, closure_def_id, &substs));
- Ok(VtableClosure(closure_def_id, substs))
+ let vtable_closure =
+ try!(self.confirm_closure_candidate(obligation, closure_def_id, &substs));
+ Ok(VtableClosure(vtable_closure))
}
BuiltinObjectCandidate => {
param: ty::PolyTraitRef<'tcx>)
-> Vec<PredicateObligation<'tcx>>
{
- debug!("confirm_param_candidate({},{})",
- obligation.repr(self.tcx()),
- param.repr(self.tcx()));
+ debug!("confirm_param_candidate({:?},{:?})",
+ obligation,
+ param);
// During evaluation, we already checked that this
// where-clause trait-ref could be unified with the obligation
Ok(obligations) => obligations,
Err(()) => {
self.tcx().sess.bug(
- &format!("Where clause `{}` was applicable to `{}` but now is not",
- param.repr(self.tcx()),
- obligation.repr(self.tcx())));
+ &format!("Where clause `{:?}` was applicable to `{:?}` but now is not",
+ param,
+ obligation));
}
}
}
-> Result<VtableBuiltinData<PredicateObligation<'tcx>>,
SelectionError<'tcx>>
{
- debug!("confirm_builtin_candidate({})",
- obligation.repr(self.tcx()));
+ debug!("confirm_builtin_candidate({:?})",
+ obligation);
match try!(self.builtin_bound(bound, obligation)) {
If(nested) => Ok(self.vtable_builtin_data(obligation, bound, nested)),
AmbiguousBuiltin | ParameterBuiltin => {
self.tcx().sess.span_bug(
obligation.cause.span,
- &format!("builtin bound for {} was ambig",
- obligation.repr(self.tcx())));
+ &format!("builtin bound for {:?} was ambig",
+ obligation));
}
}
}
let obligations = self.collect_predicates_for_types(obligation, trait_def, nested);
- let obligations = VecPerParamSpace::new(obligations, Vec::new(), Vec::new());
-
- debug!("vtable_builtin_data: obligations={}",
- obligations.repr(self.tcx()));
+ debug!("vtable_builtin_data: obligations={:?}",
+ obligations);
VtableBuiltinData { nested: obligations }
}
trait_def_id: ast::DefId)
-> VtableDefaultImplData<PredicateObligation<'tcx>>
{
- debug!("confirm_default_impl_candidate({}, {})",
- obligation.repr(self.tcx()),
- trait_def_id.repr(self.tcx()));
+ debug!("confirm_default_impl_candidate({:?}, {:?})",
+ obligation,
+ trait_def_id);
// binder is moved below
let self_ty = self.infcx.shallow_resolve(obligation.predicate.skip_binder().self_ty());
None => {
self.tcx().sess.bug(
&format!(
- "asked to confirm default implementation for ambiguous type: {}",
- self_ty.repr(self.tcx())));
+ "asked to confirm default implementation for ambiguous type: {:?}",
+ self_ty));
}
}
}
trait_def_id: ast::DefId)
-> VtableDefaultImplData<PredicateObligation<'tcx>>
{
- debug!("confirm_default_impl_object_candidate({}, {})",
- obligation.repr(self.tcx()),
- trait_def_id.repr(self.tcx()));
+ debug!("confirm_default_impl_object_candidate({:?}, {:?})",
+ obligation,
+ trait_def_id);
assert!(ty::has_attr(self.tcx(), trait_def_id, "rustc_reflect_like"));
// OK to skip binder, it is reintroduced below
let self_ty = self.infcx.shallow_resolve(obligation.predicate.skip_binder().self_ty());
match self_ty.sty {
- ty::ty_trait(ref data) => {
+ ty::TyTrait(ref data) => {
// OK to skip the binder, it is reintroduced below
let input_types = data.principal.skip_binder().substs.types.get_slice(TypeSpace);
let assoc_types = data.bounds.projection_bounds
_ => {
self.tcx().sess.bug(
&format!(
- "asked to confirm default object implementation for non-object type: {}",
- self_ty.repr(self.tcx())));
+ "asked to confirm default object implementation for non-object type: {:?}",
+ self_ty));
}
}
}
nested: ty::Binder<Vec<Ty<'tcx>>>)
-> VtableDefaultImplData<PredicateObligation<'tcx>>
{
- debug!("vtable_default_impl_data: nested={}", nested.repr(self.tcx()));
+ debug!("vtable_default_impl_data: nested={:?}", nested);
let mut obligations = self.collect_predicates_for_types(obligation,
trait_def_id,
nested);
- let trait_obligations: Result<VecPerParamSpace<_>,()> = self.infcx.commit_if_ok(|snapshot| {
+ let trait_obligations: Result<Vec<_>,()> = self.infcx.commit_if_ok(|snapshot| {
let poly_trait_ref = obligation.predicate.to_poly_trait_ref();
let (trait_ref, skol_map) =
self.infcx().skolemize_late_bound_regions(&poly_trait_ref, snapshot);
snapshot))
});
- obligations.extend(trait_obligations.unwrap().into_iter()); // no Errors in that code above
+ // no Errors in that code above
+ obligations.append(&mut trait_obligations.unwrap());
- debug!("vtable_default_impl_data: obligations={}", obligations.repr(self.tcx()));
+ debug!("vtable_default_impl_data: obligations={:?}", obligations);
VtableDefaultImplData {
trait_def_id: trait_def_id,
-> Result<VtableImplData<'tcx, PredicateObligation<'tcx>>,
SelectionError<'tcx>>
{
- debug!("confirm_impl_candidate({},{})",
- obligation.repr(self.tcx()),
- impl_def_id.repr(self.tcx()));
+ debug!("confirm_impl_candidate({:?},{:?})",
+ obligation,
+ impl_def_id);
// First, create the substitutions by matching the impl again,
// this time not in a probe.
let (substs, skol_map) =
self.rematch_impl(impl_def_id, obligation,
snapshot);
- debug!("confirm_impl_candidate substs={}", substs.repr(self.tcx()));
+ debug!("confirm_impl_candidate substs={:?}", substs);
Ok(self.vtable_impl(impl_def_id, substs, obligation.cause.clone(),
obligation.recursion_depth + 1, skol_map, snapshot))
})
fn vtable_impl(&mut self,
impl_def_id: ast::DefId,
- substs: Normalized<'tcx, Substs<'tcx>>,
+ mut substs: Normalized<'tcx, Substs<'tcx>>,
cause: ObligationCause<'tcx>,
recursion_depth: usize,
skol_map: infer::SkolemizationMap,
snapshot: &infer::CombinedSnapshot)
-> VtableImplData<'tcx, PredicateObligation<'tcx>>
{
- debug!("vtable_impl(impl_def_id={}, substs={}, recursion_depth={}, skol_map={})",
- impl_def_id.repr(self.tcx()),
- substs.repr(self.tcx()),
+ debug!("vtable_impl(impl_def_id={:?}, substs={:?}, recursion_depth={}, skol_map={:?})",
+ impl_def_id,
+ substs,
recursion_depth,
- skol_map.repr(self.tcx()));
+ skol_map);
let mut impl_obligations =
self.impl_or_trait_obligations(cause,
skol_map,
snapshot);
- debug!("vtable_impl: impl_def_id={} impl_obligations={}",
- impl_def_id.repr(self.tcx()),
- impl_obligations.repr(self.tcx()));
+ debug!("vtable_impl: impl_def_id={:?} impl_obligations={:?}",
+ impl_def_id,
+ impl_obligations);
- impl_obligations.extend(TypeSpace, substs.obligations.into_iter());
+ impl_obligations.append(&mut substs.obligations);
VtableImplData { impl_def_id: impl_def_id,
substs: substs.value,
obligation: &TraitObligation<'tcx>)
-> VtableObjectData<'tcx>
{
- debug!("confirm_object_candidate({})",
- obligation.repr(self.tcx()));
+ debug!("confirm_object_candidate({:?})",
+ obligation);
// FIXME skipping binder here seems wrong -- we should
// probably flatten the binder from the obligation and the
// case that results. -nmatsakis
let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder());
let poly_trait_ref = match self_ty.sty {
- ty::ty_trait(ref data) => {
+ ty::TyTrait(ref data) => {
data.principal_trait_ref_with_self_ty(self.tcx(), self_ty)
}
_ => {
obligation: &TraitObligation<'tcx>)
-> Result<ty::Ty<'tcx>,SelectionError<'tcx>>
{
- debug!("confirm_fn_pointer_candidate({})",
- obligation.repr(self.tcx()));
+ debug!("confirm_fn_pointer_candidate({:?})",
+ obligation);
// ok to skip binder; it is reintroduced below
let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder());
obligation: &TraitObligation<'tcx>,
closure_def_id: ast::DefId,
substs: &Substs<'tcx>)
- -> Result<(),SelectionError<'tcx>>
+ -> Result<VtableClosureData<'tcx, PredicateObligation<'tcx>>,
+ SelectionError<'tcx>>
{
- debug!("confirm_closure_candidate({},{},{})",
- obligation.repr(self.tcx()),
- closure_def_id.repr(self.tcx()),
- substs.repr(self.tcx()));
+ debug!("confirm_closure_candidate({:?},{:?},{:?})",
+ obligation,
+ closure_def_id,
+ substs);
- let trait_ref = self.closure_trait_ref(obligation,
- closure_def_id,
- substs);
+ let Normalized {
+ value: trait_ref,
+ obligations
+ } = self.closure_trait_ref(obligation, closure_def_id, substs);
- debug!("confirm_closure_candidate(closure_def_id={}, trait_ref={})",
- closure_def_id.repr(self.tcx()),
- trait_ref.repr(self.tcx()));
+ debug!("confirm_closure_candidate(closure_def_id={:?}, trait_ref={:?}, obligations={:?})",
+ closure_def_id,
+ trait_ref,
+ obligations);
- self.confirm_poly_trait_refs(obligation.cause.clone(),
- obligation.predicate.to_poly_trait_ref(),
- trait_ref)
+ try!(self.confirm_poly_trait_refs(obligation.cause.clone(),
+ obligation.predicate.to_poly_trait_ref(),
+ trait_ref));
+
+ Ok(VtableClosureData {
+ closure_def_id: closure_def_id,
+ substs: substs.clone(),
+ nested: obligations
+ })
}
/// In the case of closure types and fn pointers,
ty::no_late_bound_regions(tcx, &obligation.self_ty()).unwrap());
let target = self.infcx.shallow_resolve(obligation.predicate.0.input_types()[0]);
- debug!("confirm_builtin_unsize_candidate(source={}, target={})",
- source.repr(tcx), target.repr(tcx));
+ debug!("confirm_builtin_unsize_candidate(source={:?}, target={:?})",
+ source, target);
let mut nested = vec![];
match (&source.sty, &target.sty) {
// Trait+Kx+'a -> Trait+Ky+'b (upcasts).
- (&ty::ty_trait(ref data_a), &ty::ty_trait(ref data_b)) => {
+ (&ty::TyTrait(ref data_a), &ty::TyTrait(ref data_b)) => {
// See assemble_candidates_for_unsizing for more info.
let bounds = ty::ExistentialBounds {
region_bound: data_b.bounds.region_bound,
builtin_bounds: data_b.bounds.builtin_bounds,
projection_bounds: data_a.bounds.projection_bounds.clone(),
+ region_bound_will_change: data_b.bounds.region_bound_will_change,
};
let new_trait = ty::mk_trait(tcx, data_a.principal.clone(), bounds);
}
// T -> Trait.
- (_, &ty::ty_trait(ref data)) => {
+ (_, &ty::TyTrait(ref data)) => {
let object_did = data.principal_def_id();
if !object_safety::is_object_safe(tcx, object_did) {
return Err(TraitNotObjectSafe(object_did));
}
// [T; n] -> [T].
- (&ty::ty_vec(a, Some(_)), &ty::ty_vec(b, None)) => {
+ (&ty::TyArray(a, _), &ty::TySlice(b)) => {
let origin = infer::Misc(obligation.cause.span);
if self.infcx.sub_types(false, origin, a, b).is_err() {
return Err(Unimplemented);
}
// Struct<T> -> Struct<U>.
- (&ty::ty_struct(def_id, substs_a), &ty::ty_struct(_, substs_b)) => {
+ (&ty::TyStruct(def_id, substs_a), &ty::TyStruct(_, substs_b)) => {
let fields = ty::lookup_struct_fields(tcx, def_id).iter().map(|f| {
ty::lookup_field_type_unsubstituted(tcx, def_id, f.id)
}).collect::<Vec<_>>();
- // FIXME(#25351) The last field of the structure has to exist and be a
- // type parameter (for now, to avoid tracking edge cases).
- let i = if let Some(&ty::ty_param(p)) = fields.last().map(|ty| &ty.sty) {
- assert!(p.space == TypeSpace);
- p.idx as usize
+ // The last field of the structure has to exist and contain type parameters.
+ let field = if let Some(&field) = fields.last() {
+ field
} else {
return Err(Unimplemented);
};
+ let mut ty_params = vec![];
+ ty::walk_ty(field, |ty| {
+ if let ty::TyParam(p) = ty.sty {
+ assert!(p.space == TypeSpace);
+ let idx = p.idx as usize;
+ if !ty_params.contains(&idx) {
+ ty_params.push(idx);
+ }
+ }
+ });
+ if ty_params.is_empty() {
+ return Err(Unimplemented);
+ }
- // Replace the type parameter chosen for unsizing with
- // ty_err and ensure it does not affect any other fields.
+ // Replace type parameters used in unsizing with
+ // TyError and ensure they do not affect any other fields.
// This could be checked after type collection for any struct
// with a potentially unsized trailing field.
let mut new_substs = substs_a.clone();
- new_substs.types.get_mut_slice(TypeSpace)[i] = tcx.types.err;
+ for &i in &ty_params {
+ new_substs.types.get_mut_slice(TypeSpace)[i] = tcx.types.err;
+ }
for &ty in fields.init() {
if ty::type_is_error(ty.subst(tcx, &new_substs)) {
return Err(Unimplemented);
}
}
- // Extract T and U from Struct<T> and Struct<U>.
- let inner_source = *substs_a.types.get(TypeSpace, i);
- let inner_target = *substs_b.types.get(TypeSpace, i);
+ // Extract Field<T> and Field<U> from Struct<T> and Struct<U>.
+ let inner_source = field.subst(tcx, substs_a);
+ let inner_target = field.subst(tcx, substs_b);
- // Check that all the source structure with the unsized
- // type parameter is a subtype of the target.
- new_substs.types.get_mut_slice(TypeSpace)[i] = inner_target;
+ // Check that the source structure with the target's
+ // type parameters is a subtype of the target.
+ for &i in &ty_params {
+ let param_b = *substs_b.types.get(TypeSpace, i);
+ new_substs.types.get_mut_slice(TypeSpace)[i] = param_b;
+ }
let new_struct = ty::mk_struct(tcx, def_id, tcx.mk_substs(new_substs));
let origin = infer::Misc(obligation.cause.span);
if self.infcx.sub_types(false, origin, new_struct, target).is_err() {
return Err(Unimplemented);
}
- // Construct the nested T: Unsize<U> predicate.
+ // Construct the nested Field<T>: Unsize<Field<U>> predicate.
nested.push(util::predicate_for_trait_def(tcx,
obligation.cause.clone(),
obligation.predicate.def_id(),
_ => unreachable!()
};
- Ok(VtableBuiltinData {
- nested: VecPerParamSpace::new(nested, vec![], vec![])
- })
+ Ok(VtableBuiltinData { nested: nested })
}
///////////////////////////////////////////////////////////////////////////
Ok((substs, skol_map)) => (substs, skol_map),
Err(()) => {
self.tcx().sess.bug(
- &format!("Impl {} was matchable against {} but now is not",
- impl_def_id.repr(self.tcx()),
- obligation.repr(self.tcx())));
+ &format!("Impl {:?} was matchable against {:?} but now is not",
+ impl_def_id,
+ obligation));
}
}
}
obligation.recursion_depth + 1,
&impl_trait_ref);
- debug!("match_impl(impl_def_id={}, obligation={}, \
- impl_trait_ref={}, skol_obligation_trait_ref={})",
- impl_def_id.repr(self.tcx()),
- obligation.repr(self.tcx()),
- impl_trait_ref.repr(self.tcx()),
- skol_obligation_trait_ref.repr(self.tcx()));
+ debug!("match_impl(impl_def_id={:?}, obligation={:?}, \
+ impl_trait_ref={:?}, skol_obligation_trait_ref={:?})",
+ impl_def_id,
+ obligation,
+ impl_trait_ref,
+ skol_obligation_trait_ref);
let origin = infer::RelateOutputImplTypes(obligation.cause.span);
if let Err(e) = self.infcx.sub_trait_refs(false,
origin,
impl_trait_ref.value.clone(),
skol_obligation_trait_ref) {
- debug!("match_impl: failed sub_trait_refs due to `{}`",
- ty::type_err_to_str(self.tcx(), &e));
+ debug!("match_impl: failed sub_trait_refs due to `{}`", e);
return Err(());
}
if let Err(e) = self.infcx.leak_check(&skol_map, snapshot) {
- debug!("match_impl: failed leak check due to `{}`",
- ty::type_err_to_str(self.tcx(), &e));
+ debug!("match_impl: failed leak check due to `{}`", e);
return Err(());
}
- debug!("match_impl: success impl_substs={}", impl_substs.repr(self.tcx()));
+ debug!("match_impl: success impl_substs={:?}", impl_substs);
Ok((Normalized {
value: impl_substs,
obligations: impl_trait_ref.obligations
// simplified, do not match.
obligation.predicate.0.input_types().iter()
- .zip(impl_trait_ref.input_types().iter())
+ .zip(impl_trait_ref.input_types())
.any(|(&obligation_ty, &impl_ty)| {
let simplified_obligation_ty =
fast_reject::simplify_type(self.tcx(), obligation_ty, true);
poly_trait_ref: ty::PolyTraitRef<'tcx>)
-> Result<(),()>
{
- debug!("match_poly_trait_ref: obligation={} poly_trait_ref={}",
- obligation.repr(self.tcx()),
- poly_trait_ref.repr(self.tcx()));
+ debug!("match_poly_trait_ref: obligation={:?} poly_trait_ref={:?}",
+ obligation,
+ poly_trait_ref);
let origin = infer::RelateOutputImplTypes(obligation.cause.span);
match self.infcx.sub_poly_trait_refs(false,
let impl_self_ty = ty::lookup_item_type(self.tcx(), impl_def_id).ty;
let impl_self_ty = impl_self_ty.subst(self.tcx(), &impl_substs);
- debug!("match_impl_self_types(obligation_self_ty={}, impl_self_ty={})",
- obligation_self_ty.repr(self.tcx()),
- impl_self_ty.repr(self.tcx()));
+ debug!("match_impl_self_types(obligation_self_ty={:?}, impl_self_ty={:?})",
+ obligation_self_ty,
+ impl_self_ty);
match self.match_self_types(obligation_cause,
impl_self_ty,
obligation_self_ty) {
Ok(()) => {
- debug!("Matched impl_substs={}", impl_substs.repr(self.tcx()));
+ debug!("Matched impl_substs={:?}", impl_substs);
Ok(impl_substs)
}
Err(()) => {
}
}
- fn closure_trait_ref(&self,
- obligation: &TraitObligation<'tcx>,
- closure_def_id: ast::DefId,
- substs: &Substs<'tcx>)
- -> ty::PolyTraitRef<'tcx>
+ fn closure_trait_ref_unnormalized(&mut self,
+ obligation: &TraitObligation<'tcx>,
+ closure_def_id: ast::DefId,
+ substs: &Substs<'tcx>)
+ -> ty::PolyTraitRef<'tcx>
{
let closure_type = self.closure_typer.closure_type(closure_def_id, substs);
let ty::Binder((trait_ref, _)) =
obligation.predicate.0.self_ty(), // (1)
&closure_type.sig,
util::TupleArgumentsFlag::No);
-
// (1) Feels icky to skip the binder here, but OTOH we know
// that the self-type is an unboxed closure type and hence is
// in fact unparameterized (or at least does not reference any
ty::Binder(trait_ref)
}
+ fn closure_trait_ref(&mut self,
+ obligation: &TraitObligation<'tcx>,
+ closure_def_id: ast::DefId,
+ substs: &Substs<'tcx>)
+ -> Normalized<'tcx, ty::PolyTraitRef<'tcx>>
+ {
+ let trait_ref = self.closure_trait_ref_unnormalized(
+ obligation, closure_def_id, substs);
+
+ // A closure signature can contain associated types which
+ // must be normalized.
+ normalize_with_depth(self,
+ obligation.cause.clone(),
+ obligation.recursion_depth+1,
+ &trait_ref)
+ }
+
/// Returns the obligations that are implied by instantiating an
/// impl or trait. The obligations are substituted and fully
/// normalized. This is used when confirming an impl or default
substs: &Substs<'tcx>, // for impl or trait
skol_map: infer::SkolemizationMap,
snapshot: &infer::CombinedSnapshot)
- -> VecPerParamSpace<PredicateObligation<'tcx>>
+ -> Vec<PredicateObligation<'tcx>>
{
- debug!("impl_or_trait_obligations(def_id={})", def_id.repr(self.tcx()));
+ debug!("impl_or_trait_obligations(def_id={:?})", def_id);
let predicates = ty::lookup_predicates(self.tcx(), def_id);
let predicates = predicates.instantiate(self.tcx(), substs);
let predicates = normalize_with_depth(self, cause.clone(), recursion_depth, &predicates);
- let predicates = self.infcx().plug_leaks(skol_map, snapshot, &predicates);
+ let mut predicates = self.infcx().plug_leaks(skol_map, snapshot, &predicates);
let mut obligations =
- util::predicates_for_generics(self.tcx(),
- cause,
+ util::predicates_for_generics(cause,
recursion_depth,
&predicates.value);
- obligations.extend(TypeSpace, predicates.obligations.into_iter());
+ obligations.append(&mut predicates.obligations);
obligations
}
fn upcast(&mut self, obj_trait_ref: ty::PolyTraitRef<'tcx>, obligation: &TraitObligation<'tcx>)
-> Vec<ty::PolyTraitRef<'tcx>>
{
- debug!("upcast(obj_trait_ref={}, obligation={})",
- obj_trait_ref.repr(self.tcx()),
- obligation.repr(self.tcx()));
+ debug!("upcast(obj_trait_ref={:?}, obligation={:?})",
+ obj_trait_ref,
+ obligation);
let obligation_def_id = obligation.predicate.def_id();
let mut upcast_trait_refs = util::upcast(self.tcx(), obj_trait_ref, obligation_def_id);
self.infcx.probe(|_| self.match_poly_trait_ref(obligation, upcast_trait_ref)).is_ok()
});
- debug!("upcast: upcast_trait_refs={}", upcast_trait_refs.repr(self.tcx()));
+ debug!("upcast: upcast_trait_refs={:?}", upcast_trait_refs);
upcast_trait_refs
}
}
-impl<'tcx> Repr<'tcx> for SelectionCandidate<'tcx> {
- fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
- match *self {
- PhantomFnCandidate => format!("PhantomFnCandidate"),
- ErrorCandidate => format!("ErrorCandidate"),
- BuiltinCandidate(b) => format!("BuiltinCandidate({:?})", b),
- BuiltinObjectCandidate => format!("BuiltinObjectCandidate"),
- BuiltinUnsizeCandidate => format!("BuiltinUnsizeCandidate"),
- ParamCandidate(ref a) => format!("ParamCandidate({})", a.repr(tcx)),
- ImplCandidate(a) => format!("ImplCandidate({})", a.repr(tcx)),
- DefaultImplCandidate(t) => format!("DefaultImplCandidate({:?})", t),
- DefaultImplObjectCandidate(t) => format!("DefaultImplObjectCandidate({:?})", t),
- ProjectionCandidate => format!("ProjectionCandidate"),
- FnPointerCandidate => format!("FnPointerCandidate"),
- ObjectCandidate => format!("ObjectCandidate"),
- ClosureCandidate(c, ref s) => {
- format!("ClosureCandidate({:?},{})", c, s.repr(tcx))
- }
- }
- }
-}
-
impl<'tcx> SelectionCache<'tcx> {
pub fn new() -> SelectionCache<'tcx> {
SelectionCache {
}
}
-impl<'o,'tcx> Repr<'tcx> for TraitObligationStack<'o,'tcx> {
- fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
- format!("TraitObligationStack({})",
- self.obligation.repr(tcx))
+impl<'o,'tcx> fmt::Debug for TraitObligationStack<'o,'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "TraitObligationStack({:?})", self.obligation)
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use middle::subst::{Substs, VecPerParamSpace};
+use middle::subst::Substs;
use middle::infer::InferCtxt;
use middle::ty::{self, Ty, AsPredicate, ToPolyTraitRef};
use std::fmt;
use syntax::codemap::Span;
use util::common::ErrorReported;
use util::nodemap::FnvHashSet;
-use util::ppaux::Repr;
use super::{Obligation, ObligationCause, PredicateObligation,
VtableImpl, VtableParam, VtableImplData, VtableDefaultImplData};
.map(|p| p.subst_supertrait(self.tcx, &data.to_poly_trait_ref()))
.collect();
- debug!("super_predicates: data={} predicates={}",
- data.repr(self.tcx), predicates.repr(self.tcx));
+ debug!("super_predicates: data={:?} predicates={:?}",
+ data, predicates);
// Only keep those bounds that we haven't already
// seen. This is necessary to prevent infinite
// Sized { }`.
predicates.retain(|r| self.visited.insert(r));
- self.stack.extend(predicates.into_iter());
+ self.stack.extend(predicates);
}
ty::Predicate::Equate(..) => {
// Currently, we do not "elaborate" predicates like
infcx.fresh_substs_for_generics(span, &impl_generics)
}
-impl<'tcx, N> fmt::Debug for VtableImplData<'tcx, N> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "VtableImpl({:?})", self.impl_def_id)
- }
-}
-
-impl<'tcx> fmt::Debug for super::VtableObjectData<'tcx> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "VtableObject(...)")
- }
-}
-
/// See `super::obligations_for_generics`
-pub fn predicates_for_generics<'tcx>(tcx: &ty::ctxt<'tcx>,
- cause: ObligationCause<'tcx>,
+pub fn predicates_for_generics<'tcx>(cause: ObligationCause<'tcx>,
recursion_depth: usize,
generic_bounds: &ty::InstantiatedPredicates<'tcx>)
- -> VecPerParamSpace<PredicateObligation<'tcx>>
+ -> Vec<PredicateObligation<'tcx>>
{
- debug!("predicates_for_generics(generic_bounds={})",
- generic_bounds.repr(tcx));
+ debug!("predicates_for_generics(generic_bounds={:?})",
+ generic_bounds);
- generic_bounds.predicates.map(|predicate| {
+ generic_bounds.predicates.iter().map(|predicate| {
Obligation { cause: cause.clone(),
recursion_depth: recursion_depth,
predicate: predicate.clone() }
- })
+ }).collect()
}
pub fn trait_ref_for_builtin_bound<'tcx>(
}
let trait_items = ty::trait_items(tcx, bound_ref.def_id());
- for trait_item in &**trait_items {
+ for trait_item in trait_items.iter() {
match *trait_item {
ty::MethodTraitItem(_) => method_count += 1,
_ => {}
ty::Binder((trait_ref, sig.0.output.unwrap_or(ty::mk_nil(tcx))))
}
-impl<'tcx,O:Repr<'tcx>> Repr<'tcx> for super::Obligation<'tcx, O> {
- fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
- format!("Obligation(predicate={},depth={})",
- self.predicate.repr(tcx),
- self.recursion_depth)
+impl<'tcx,O:fmt::Debug> fmt::Debug for super::Obligation<'tcx, O> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "Obligation(predicate={:?},depth={})",
+ self.predicate,
+ self.recursion_depth)
}
}
-impl<'tcx, N:Repr<'tcx>> Repr<'tcx> for super::Vtable<'tcx, N> {
- fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
+impl<'tcx, N:fmt::Debug> fmt::Debug for super::Vtable<'tcx, N> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
super::VtableImpl(ref v) =>
- v.repr(tcx),
+ write!(f, "{:?}", v),
super::VtableDefaultImpl(ref t) =>
- t.repr(tcx),
+ write!(f, "{:?}", t),
- super::VtableClosure(ref d, ref s) =>
- format!("VtableClosure({},{})",
- d.repr(tcx),
- s.repr(tcx)),
+ super::VtableClosure(ref d) =>
+ write!(f, "{:?}", d),
super::VtableFnPointer(ref d) =>
- format!("VtableFnPointer({})",
- d.repr(tcx)),
+ write!(f, "VtableFnPointer({:?})", d),
super::VtableObject(ref d) =>
- format!("VtableObject({})",
- d.repr(tcx)),
+ write!(f, "VtableObject({:?})", d),
super::VtableParam(ref n) =>
- format!("VtableParam({})",
- n.repr(tcx)),
+ write!(f, "VtableParam({:?})", n),
super::VtableBuiltin(ref d) =>
- d.repr(tcx)
+ write!(f, "{:?}", d)
}
}
}
-impl<'tcx, N:Repr<'tcx>> Repr<'tcx> for super::VtableImplData<'tcx, N> {
- fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
- format!("VtableImpl(impl_def_id={}, substs={}, nested={})",
- self.impl_def_id.repr(tcx),
- self.substs.repr(tcx),
- self.nested.repr(tcx))
- }
-}
-
-impl<'tcx, N:Repr<'tcx>> Repr<'tcx> for super::VtableBuiltinData<N> {
- fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
- format!("VtableBuiltin(nested={})",
- self.nested.repr(tcx))
+impl<'tcx, N:fmt::Debug> fmt::Debug for super::VtableImplData<'tcx, N> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "VtableImpl(impl_def_id={:?}, substs={:?}, nested={:?})",
+ self.impl_def_id,
+ self.substs,
+ self.nested)
}
}
-impl<'tcx, N:Repr<'tcx>> Repr<'tcx> for super::VtableDefaultImplData<N> {
- fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
- format!("VtableDefaultImplData(trait_def_id={}, nested={})",
- self.trait_def_id.repr(tcx),
- self.nested.repr(tcx))
+impl<'tcx, N:fmt::Debug> fmt::Debug for super::VtableClosureData<'tcx, N> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "VtableClosure(closure_def_id={:?}, substs={:?}, nested={:?})",
+ self.closure_def_id,
+ self.substs,
+ self.nested)
}
}
-impl<'tcx> Repr<'tcx> for super::VtableObjectData<'tcx> {
- fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
- format!("VtableObject(object_ty={})",
- self.object_ty.repr(tcx))
+impl<'tcx, N:fmt::Debug> fmt::Debug for super::VtableBuiltinData<N> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "VtableBuiltin(nested={:?})", self.nested)
}
}
-impl<'tcx> Repr<'tcx> for super::SelectionError<'tcx> {
- fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
- match *self {
- super::Unimplemented =>
- format!("Unimplemented"),
-
- super::OutputTypeParameterMismatch(ref a, ref b, ref c) =>
- format!("OutputTypeParameterMismatch({},{},{})",
- a.repr(tcx),
- b.repr(tcx),
- c.repr(tcx)),
-
- super::TraitNotObjectSafe(ref tr) =>
- format!("TraitNotObjectSafe({})",
- tr.repr(tcx))
- }
+impl<'tcx, N:fmt::Debug> fmt::Debug for super::VtableDefaultImplData<N> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "VtableDefaultImplData(trait_def_id={:?}, nested={:?})",
+ self.trait_def_id,
+ self.nested)
}
}
-impl<'tcx> Repr<'tcx> for super::FulfillmentError<'tcx> {
- fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
- format!("FulfillmentError({},{})",
- self.obligation.repr(tcx),
- self.code.repr(tcx))
+impl<'tcx> fmt::Debug for super::VtableObjectData<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "VtableObject(object_ty={:?})", self.object_ty)
}
}
-impl<'tcx> Repr<'tcx> for super::FulfillmentErrorCode<'tcx> {
- fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
- match *self {
- super::CodeSelectionError(ref o) => o.repr(tcx),
- super::CodeProjectionError(ref o) => o.repr(tcx),
- super::CodeAmbiguity => format!("Ambiguity")
- }
+impl<'tcx> fmt::Debug for super::FulfillmentError<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "FulfillmentError({:?},{:?})",
+ self.obligation,
+ self.code)
}
}
}
}
-impl<'tcx> Repr<'tcx> for super::MismatchedProjectionTypes<'tcx> {
- fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
- self.err.repr(tcx)
- }
-}
-
impl<'tcx> fmt::Debug for super::MismatchedProjectionTypes<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "MismatchedProjectionTypes(..)")
+ write!(f, "MismatchedProjectionTypes({:?})", self.err)
}
}
pub use self::terr_vstore_kind::*;
pub use self::type_err::*;
-pub use self::BuiltinBound::*;
pub use self::InferTy::*;
pub use self::InferRegion::*;
pub use self::ImplOrTraitItemId::*;
pub use self::AutoAdjustment::*;
pub use self::Representability::*;
pub use self::AutoRef::*;
-pub use self::ExprKind::*;
pub use self::DtorKind::*;
pub use self::ExplicitSelfCategory::*;
pub use self::FnOutput::*;
pub use self::BorrowKind::*;
pub use self::ImplOrTraitItem::*;
pub use self::BoundRegion::*;
-pub use self::sty::*;
+pub use self::TypeVariants::*;
pub use self::IntVarValue::*;
-pub use self::vtable_origin::*;
pub use self::MethodOrigin::*;
pub use self::CopyImplementationError::*;
+pub use self::BuiltinBound::Send as BoundSend;
+pub use self::BuiltinBound::Sized as BoundSized;
+pub use self::BuiltinBound::Copy as BoundCopy;
+pub use self::BuiltinBound::Sync as BoundSync;
+
+use ast_map::{self, LinkedPath};
use back::svh::Svh;
use session::Session;
use lint;
use metadata::csearch;
use middle;
+use middle::cast;
use middle::check_const;
-use middle::const_eval;
+use middle::const_eval::{self, ConstVal};
use middle::def::{self, DefMap, ExportMap};
use middle::dependency_format;
use middle::fast_reject;
use middle::free_region::FreeRegionMap;
+use middle::infer::error_reporting::note_and_explain_region;
use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
use middle::mem_categorization as mc;
use middle::region;
use middle::ty;
use middle::ty_fold::{self, TypeFoldable, TypeFolder};
use middle::ty_walk::{self, TypeWalker};
-use util::ppaux::{note_and_explain_region, bound_region_ptr_to_string};
-use util::ppaux::ty_to_string;
-use util::ppaux::{Repr, UserString};
use util::common::{memoized, ErrorReported};
use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet};
use util::nodemap::FnvHashMap;
use std::ops;
use std::rc::Rc;
use std::vec::IntoIter;
-use collections::enum_set::{EnumSet, CLike};
+use collections::enum_set::{self, EnumSet, CLike};
use std::collections::{HashMap, HashSet};
use syntax::abi;
use syntax::ast::{CrateNum, DefId, ItemImpl, ItemTrait, LOCAL_CRATE};
use syntax::ast::{MutImmutable, MutMutable, Name, NamedField, NodeId};
use syntax::ast::{StmtExpr, StmtSemi, StructField, UnnamedField, Visibility};
-use syntax::ast_util::{self, is_local, lit_is_str, local_def};
+use syntax::ast_util::{self, is_local, local_def};
use syntax::attr::{self, AttrMetaMethods, SignedInt, UnsignedInt};
use syntax::codemap::Span;
use syntax::parse::token::{self, InternedString, special_idents};
use syntax::print::pprust;
use syntax::ptr::P;
use syntax::ast;
-use syntax::ast_map::{self, LinkedPath};
pub type Disr = u64;
/// The complete set of all analyses described in this module. This is
/// produced by the driver and fed to trans and later passes.
-pub struct CrateAnalysis<'tcx> {
+pub struct CrateAnalysis {
pub export_map: ExportMap,
pub exported_items: middle::privacy::ExportedItems,
pub public_items: middle::privacy::PublicItems,
- pub ty_cx: ty::ctxt<'tcx>,
pub reachable: NodeSet,
pub name: String,
pub glob_map: Option<GlobMap>,
}
}
-#[derive(Clone, Debug)]
+#[derive(Clone)]
pub enum ImplOrTraitItem<'tcx> {
ConstTraitItem(Rc<AssociatedConst<'tcx>>),
MethodTraitItem(Rc<Method<'tcx>>),
- TypeTraitItem(Rc<AssociatedType>),
+ TypeTraitItem(Rc<AssociatedType<'tcx>>),
}
impl<'tcx> ImplOrTraitItem<'tcx> {
}
#[derive(Clone, Copy, Debug)]
-pub struct AssociatedType {
+pub struct AssociatedType<'tcx> {
pub name: ast::Name,
+ pub ty: Option<Ty<'tcx>>,
pub vis: ast::Visibility,
pub def_id: ast::DefId,
pub container: ImplOrTraitItemContainer,
pub origin: ast::DefId, // The DefId of the struct in which the field is declared.
}
-// Contains information needed to resolve types and (in the future) look up
-// the types of AST nodes.
-#[derive(Copy, Clone, PartialEq, Eq, Hash)]
-pub struct creader_cache_key {
- pub cnum: CrateNum,
- pub pos: usize,
- pub len: usize
-}
-
#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable)]
pub struct ItemVariances {
pub types: VecPerParamSpace<Variance>,
pub regions: VecPerParamSpace<Variance>,
}
-#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable, Debug, Copy)]
+#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable, Copy)]
pub enum Variance {
Covariant, // T<A> <: T<B> iff A <: B -- e.g., function return type
Invariant, // T<A> <: T<B> iff B == A -- e.g., type of mutable cell
Bivariant, // T<A> <: T<B> -- e.g., unused type parameter
}
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone)]
pub enum AutoAdjustment<'tcx> {
AdjustReifyFnPointer, // go from a fn-item type to a fn-pointer type
AdjustUnsafeFnPointer, // go from a safe fn pointer to an unsafe fn pointer
/// unsize: Some(Box<[i32]>),
/// }
/// ```
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone)]
pub struct AutoDerefRef<'tcx> {
/// Step 1. Apply a number of dereferences, producing an lvalue.
pub autoderefs: usize,
Struct(usize)
}
-#[derive(Clone, Copy, RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Debug)]
-pub struct param_index {
- pub space: subst::ParamSpace,
- pub index: usize
-}
-
-#[derive(Clone, Debug)]
+#[derive(Clone)]
pub enum MethodOrigin<'tcx> {
// fully statically resolved method
MethodStatic(ast::DefId),
// details for a method invoked with a receiver whose type is a type parameter
// with a bounded trait.
-#[derive(Clone, Debug)]
+#[derive(Clone)]
pub struct MethodParam<'tcx> {
// the precise trait reference that occurs as a bound -- this may
// be a supertrait of what the user actually typed. Note that it
}
// details for a method invoked with a receiver whose type is an object
-#[derive(Clone, Debug)]
+#[derive(Clone)]
pub struct MethodObject<'tcx> {
// the (super)trait containing the method to be invoked
pub trait_ref: TraitRef<'tcx>,
// of the method to be invoked
pub type MethodMap<'tcx> = RefCell<FnvHashMap<MethodCall, MethodCallee<'tcx>>>;
-pub type vtable_param_res<'tcx> = Vec<vtable_origin<'tcx>>;
-
-// Resolutions for bounds of all parameters, left to right, for a given path.
-pub type vtable_res<'tcx> = VecPerParamSpace<vtable_param_res<'tcx>>;
-
-#[derive(Clone)]
-pub enum vtable_origin<'tcx> {
- /*
- Statically known vtable. def_id gives the impl item
- from whence comes the vtable, and tys are the type substs.
- vtable_res is the vtable itself.
- */
- vtable_static(ast::DefId, subst::Substs<'tcx>, vtable_res<'tcx>),
-
- /*
- Dynamic vtable, comes from a parameter that has a bound on it:
- fn foo<T:quux,baz,bar>(a: T) -- a's vtable would have a
- vtable_param origin
-
- The first argument is the param index (identifying T in the example),
- and the second is the bound number (identifying baz)
- */
- vtable_param(param_index, usize),
-
- /*
- Vtable automatically generated for a closure. The def ID is the
- ID of the closure expression.
- */
- vtable_closure(ast::DefId),
-
- /*
- Asked to determine the vtable for ty_err. This is the value used
- for the vtables of `Self` in a virtual call like `foo.bar()`
- where `foo` is of object type. The same value is also used when
- type errors occur.
- */
- vtable_error,
+// Contains information needed to resolve types and (in the future) look up
+// the types of AST nodes.
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
+pub struct creader_cache_key {
+ pub cnum: CrateNum,
+ pub pos: usize,
+ pub len: usize
}
-
-// For every explicit cast into an object type, maps from the cast
-// expr to the associated trait ref.
-pub type ObjectCastMap<'tcx> = RefCell<NodeMap<ty::PolyTraitRef<'tcx>>>;
-
/// A restriction that certain types must be the same size. The use of
/// `transmute` gives rise to these restrictions. These generally
/// cannot be checked until trans; therefore, each call to `transmute`
substs: TypedArena<Substs<'tcx>>,
bare_fn: TypedArena<BareFnTy<'tcx>>,
region: TypedArena<Region>,
+ stability: TypedArena<attr::Stability>,
// references
- trait_defs: TypedArena<TraitDef<'tcx>>
+ trait_defs: TypedArena<TraitDef<'tcx>>,
}
impl<'tcx> CtxtArenas<'tcx> {
substs: TypedArena::new(),
bare_fn: TypedArena::new(),
region: TypedArena::new(),
+ stability: TypedArena::new(),
trait_defs: TypedArena::new()
}
substs_interner: RefCell<FnvHashMap<&'tcx Substs<'tcx>, &'tcx Substs<'tcx>>>,
bare_fn_interner: RefCell<FnvHashMap<&'tcx BareFnTy<'tcx>, &'tcx BareFnTy<'tcx>>>,
region_interner: RefCell<FnvHashMap<&'tcx Region, &'tcx Region>>,
+ stability_interner: RefCell<FnvHashMap<&'tcx attr::Stability, &'tcx attr::Stability>>,
/// Common types, pre-interned for your convenience.
pub types: CommonTypes<'tcx>,
/// A cache for the trait_items() routine
pub trait_items_cache: RefCell<DefIdMap<Rc<Vec<ImplOrTraitItem<'tcx>>>>>,
- pub impl_trait_cache: RefCell<DefIdMap<Option<TraitRef<'tcx>>>>,
-
- pub impl_trait_refs: RefCell<NodeMap<TraitRef<'tcx>>>,
+ pub impl_trait_refs: RefCell<DefIdMap<Option<TraitRef<'tcx>>>>,
pub trait_defs: RefCell<DefIdMap<&'tcx TraitDef<'tcx>>>,
/// Maps from the def-id of an item (trait/struct/enum/fn) to its
/// additional acyclicity requirements).
pub super_predicates: RefCell<DefIdMap<GenericPredicates<'tcx>>>,
- /// Maps from node-id of a trait object cast (like `foo as
- /// Box<Trait>`) to the trait reference.
- pub object_cast_map: ObjectCastMap<'tcx>,
-
pub map: ast_map::Map<'tcx>,
pub freevars: RefCell<FreevarMap>,
pub tcache: RefCell<DefIdMap<TypeScheme<'tcx>>>,
pub rcache: RefCell<FnvHashMap<creader_cache_key, Ty<'tcx>>>,
- pub short_names_cache: RefCell<FnvHashMap<Ty<'tcx>, String>>,
pub tc_cache: RefCell<FnvHashMap<Ty<'tcx>, TypeContents>>,
pub ast_ty_to_ty_cache: RefCell<NodeMap<Ty<'tcx>>>,
pub enum_var_cache: RefCell<DefIdMap<Rc<Vec<Rc<VariantInfo<'tcx>>>>>>,
/// Borrows
pub upvar_capture_map: RefCell<UpvarCaptureMap>,
- /// These two caches are used by const_eval when decoding external statics
- /// and variants that are found.
+ /// These caches are used by const_eval when decoding external constants.
pub extern_const_statics: RefCell<DefIdMap<ast::NodeId>>,
pub extern_const_variants: RefCell<DefIdMap<ast::NodeId>>,
+ pub extern_const_fns: RefCell<DefIdMap<ast::NodeId>>,
pub method_map: MethodMap<'tcx>,
pub transmute_restrictions: RefCell<Vec<TransmuteRestriction<'tcx>>>,
/// Maps any item's def-id to its stability index.
- pub stability: RefCell<stability::Index>,
-
- /// Maps def IDs to true if and only if they're associated types.
- pub associated_types: RefCell<DefIdMap<bool>>,
+ pub stability: RefCell<stability::Index<'tcx>>,
/// Caches the results of trait selection. This cache is used
/// for things that do not have to do with the parameters in scope.
pub selection_cache: traits::SelectionCache<'tcx>,
+ /// A set of predicates that have been fulfilled *somewhere*.
+ /// This is used to avoid duplicate work. Predicates are only
+ /// added to this set when they mention only "global" names
+ /// (i.e., no type or lifetime parameters).
+ pub fulfilled_predicates: RefCell<traits::FulfilledPredicates<'tcx>>,
+
/// Caches the representation hints for struct definitions.
pub repr_hint_cache: RefCell<DefIdMap<Rc<Vec<attr::ReprAttr>>>>,
- /// Caches whether types are known to impl Copy. Note that type
- /// parameters are never placed into this cache, because their
- /// results are dependent on the parameter environment.
- pub type_impls_copy_cache: RefCell<HashMap<Ty<'tcx>,bool>>,
-
- /// Caches whether types are known to impl Sized. Note that type
- /// parameters are never placed into this cache, because their
- /// results are dependent on the parameter environment.
- pub type_impls_sized_cache: RefCell<HashMap<Ty<'tcx>,bool>>,
-
/// Maps Expr NodeId's to their constant qualification.
pub const_qualif_map: RefCell<NodeMap<check_const::ConstQualif>>,
/// Caches CoerceUnsized kinds for impls on custom types.
pub custom_coerce_unsized_kinds: RefCell<DefIdMap<CustomCoerceUnsized>>,
+
+ /// Maps a cast expression to its kind. This is keyed on the
+ /// *from* expression of the cast, not the cast itself.
+ pub cast_kinds: RefCell<NodeMap<cast::CastKind>>,
}
impl<'tcx> ctxt<'tcx> {
interned
}
+ pub fn intern_stability(&self, stab: attr::Stability) -> &'tcx attr::Stability {
+ if let Some(st) = self.stability_interner.borrow().get(&stab) {
+ return st;
+ }
+
+ let interned = self.arenas.stability.alloc(stab);
+ self.stability_interner.borrow_mut().insert(interned, interned);
+ interned
+ }
+
pub fn store_free_region_map(&self, id: NodeId, map: FreeRegionMap) {
self.free_region_maps.borrow_mut()
.insert(id, map);
pub fn free_region_map(&self, id: NodeId) -> FreeRegionMap {
self.free_region_maps.borrow()[&id].clone()
}
+
+ pub fn lift<T: ?Sized + Lift<'tcx>>(&self, value: &T) -> Option<T::Lifted> {
+ value.lift_to_tcx(self)
+ }
+}
+
+/// A trait implemented for all X<'a> types which can be safely and
+/// efficiently converted to X<'tcx> as long as they are part of the
+/// provided ty::ctxt<'tcx>.
+/// This can be done, for example, for Ty<'tcx> or &'tcx Substs<'tcx>
+/// by looking them up in their respective interners.
+/// None is returned if the value or one of the components is not part
+/// of the provided context.
+/// For Ty, None can be returned if either the type interner doesn't
+/// contain the TypeVariants key or if the address of the interned
+/// pointer differs. The latter case is possible if a primitive type,
+/// e.g. `()` or `u8`, was interned in a different context.
+pub trait Lift<'tcx> {
+ type Lifted;
+ fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<Self::Lifted>;
+}
+
+impl<'tcx, A: Lift<'tcx>, B: Lift<'tcx>> Lift<'tcx> for (A, B) {
+ type Lifted = (A::Lifted, B::Lifted);
+ fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<Self::Lifted> {
+ tcx.lift(&self.0).and_then(|a| tcx.lift(&self.1).map(|b| (a, b)))
+ }
+}
+
+impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for [T] {
+ type Lifted = Vec<T::Lifted>;
+ fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<Self::Lifted> {
+ let mut result = Vec::with_capacity(self.len());
+ for x in self {
+ if let Some(value) = tcx.lift(x) {
+ result.push(value);
+ } else {
+ return None;
+ }
+ }
+ Some(result)
+ }
+}
+
+impl<'tcx> Lift<'tcx> for Region {
+ type Lifted = Self;
+ fn lift_to_tcx(&self, _: &ctxt<'tcx>) -> Option<Region> {
+ Some(*self)
+ }
+}
+
+impl<'a, 'tcx> Lift<'tcx> for Ty<'a> {
+ type Lifted = Ty<'tcx>;
+ fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<Ty<'tcx>> {
+ if let Some(&ty) = tcx.interner.borrow().get(&self.sty) {
+ if *self as *const _ == ty as *const _ {
+ return Some(ty);
+ }
+ }
+ None
+ }
+}
+
+impl<'a, 'tcx> Lift<'tcx> for &'a Substs<'a> {
+ type Lifted = &'tcx Substs<'tcx>;
+ fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<&'tcx Substs<'tcx>> {
+ if let Some(&substs) = tcx.substs_interner.borrow().get(*self) {
+ if *self as *const _ == substs as *const _ {
+ return Some(substs);
+ }
+ }
+ None
+ }
+}
+
+impl<'a, 'tcx> Lift<'tcx> for TraitRef<'a> {
+ type Lifted = TraitRef<'tcx>;
+ fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<TraitRef<'tcx>> {
+ tcx.lift(&self.substs).map(|substs| TraitRef {
+ def_id: self.def_id,
+ substs: substs
+ })
+ }
+}
+
+impl<'a, 'tcx> Lift<'tcx> for TraitPredicate<'a> {
+ type Lifted = TraitPredicate<'tcx>;
+ fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<TraitPredicate<'tcx>> {
+ tcx.lift(&self.trait_ref).map(|trait_ref| TraitPredicate {
+ trait_ref: trait_ref
+ })
+ }
+}
+
+impl<'a, 'tcx> Lift<'tcx> for EquatePredicate<'a> {
+ type Lifted = EquatePredicate<'tcx>;
+ fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<EquatePredicate<'tcx>> {
+ tcx.lift(&(self.0, self.1)).map(|(a, b)| EquatePredicate(a, b))
+ }
+}
+
+impl<'tcx, A: Copy+Lift<'tcx>, B: Copy+Lift<'tcx>> Lift<'tcx> for OutlivesPredicate<A, B> {
+ type Lifted = OutlivesPredicate<A::Lifted, B::Lifted>;
+ fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<Self::Lifted> {
+ tcx.lift(&(self.0, self.1)).map(|(a, b)| OutlivesPredicate(a, b))
+ }
+}
+
+impl<'a, 'tcx> Lift<'tcx> for ProjectionPredicate<'a> {
+ type Lifted = ProjectionPredicate<'tcx>;
+ fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<ProjectionPredicate<'tcx>> {
+ tcx.lift(&(self.projection_ty.trait_ref, self.ty)).map(|(trait_ref, ty)| {
+ ProjectionPredicate {
+ projection_ty: ProjectionTy {
+ trait_ref: trait_ref,
+ item_name: self.projection_ty.item_name
+ },
+ ty: ty
+ }
+ })
+ }
+}
+
+impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Binder<T> {
+ type Lifted = Binder<T::Lifted>;
+ fn lift_to_tcx(&self, tcx: &ctxt<'tcx>) -> Option<Self::Lifted> {
+ tcx.lift(&self.0).map(|x| Binder(x))
+ }
+}
+
+pub mod tls {
+ use ast_map;
+ use middle::ty;
+ use session::Session;
+
+ use std::fmt;
+ use syntax::ast;
+ use syntax::codemap;
+
+ /// Marker type used for the scoped TLS slot.
+ /// The type context cannot be used directly because the scoped TLS
+ /// in libstd doesn't allow types generic over lifetimes.
+ struct ThreadLocalTyCx;
+
+ scoped_thread_local!(static TLS_TCX: ThreadLocalTyCx);
+
+ fn def_id_debug(def_id: ast::DefId, f: &mut fmt::Formatter) -> fmt::Result {
+ // Unfortunately, there seems to be no way to attempt to print
+ // a path for a def-id, so I'll just make a best effort for now
+ // and otherwise fallback to just printing the crate/node pair
+ with(|tcx| {
+ if def_id.krate == ast::LOCAL_CRATE {
+ match tcx.map.find(def_id.node) {
+ Some(ast_map::NodeItem(..)) |
+ Some(ast_map::NodeForeignItem(..)) |
+ Some(ast_map::NodeImplItem(..)) |
+ Some(ast_map::NodeTraitItem(..)) |
+ Some(ast_map::NodeVariant(..)) |
+ Some(ast_map::NodeStructCtor(..)) => {
+ return write!(f, "{}", ty::item_path_str(tcx, def_id));
+ }
+ _ => {}
+ }
+ }
+ Ok(())
+ })
+ }
+
+ fn span_debug(span: codemap::Span, f: &mut fmt::Formatter) -> fmt::Result {
+ with(|tcx| {
+ write!(f, "{}", tcx.sess.codemap().span_to_string(span))
+ })
+ }
+
+ pub fn enter<'tcx, F: FnOnce(&ty::ctxt<'tcx>) -> R, R>(tcx: ty::ctxt<'tcx>, f: F)
+ -> (Session, R) {
+ let result = ast::DEF_ID_DEBUG.with(|def_id_dbg| {
+ codemap::SPAN_DEBUG.with(|span_dbg| {
+ let original_def_id_debug = def_id_dbg.get();
+ def_id_dbg.set(def_id_debug);
+ let original_span_debug = span_dbg.get();
+ span_dbg.set(span_debug);
+ let tls_ptr = &tcx as *const _ as *const ThreadLocalTyCx;
+ let result = TLS_TCX.set(unsafe { &*tls_ptr }, || f(&tcx));
+ def_id_dbg.set(original_def_id_debug);
+ span_dbg.set(original_span_debug);
+ result
+ })
+ });
+ (tcx.sess, result)
+ }
+
+ pub fn with<F: FnOnce(&ty::ctxt) -> R, R>(f: F) -> R {
+ TLS_TCX.with(|tcx| f(unsafe { &*(tcx as *const _ as *const ty::ctxt) }))
+ }
}
// Flags that we track on types. These flags are propagated upwards
// recursing over the type itself.
bitflags! {
flags TypeFlags: u32 {
- const HAS_PARAMS = 1 << 0,
- const HAS_SELF = 1 << 1,
- const HAS_TY_INFER = 1 << 2,
- const HAS_RE_INFER = 1 << 3,
- const HAS_RE_LATE_BOUND = 1 << 4,
- const HAS_REGIONS = 1 << 5,
- const HAS_TY_ERR = 1 << 6,
- const HAS_PROJECTION = 1 << 7,
- const NEEDS_SUBST = TypeFlags::HAS_PARAMS.bits |
+ const HAS_PARAMS = 1 << 0,
+ const HAS_SELF = 1 << 1,
+ const HAS_TY_INFER = 1 << 2,
+ const HAS_RE_INFER = 1 << 3,
+ const HAS_RE_EARLY_BOUND = 1 << 4,
+ const HAS_FREE_REGIONS = 1 << 5,
+ const HAS_TY_ERR = 1 << 6,
+ const HAS_PROJECTION = 1 << 7,
+ const HAS_TY_CLOSURE = 1 << 8,
+
+ // true if there are "names" of types and regions and so forth
+ // that are local to a particular fn
+ const HAS_LOCAL_NAMES = 1 << 9,
+
+ const NEEDS_SUBST = TypeFlags::HAS_PARAMS.bits |
+ TypeFlags::HAS_SELF.bits |
+ TypeFlags::HAS_RE_EARLY_BOUND.bits,
+
+ // Flags representing the nominal content of a type,
+ // computed by FlagsComputation. If you add a new nominal
+ // flag, it should be added here too.
+ const NOMINAL_FLAGS = TypeFlags::HAS_PARAMS.bits |
TypeFlags::HAS_SELF.bits |
- TypeFlags::HAS_REGIONS.bits,
+ TypeFlags::HAS_TY_INFER.bits |
+ TypeFlags::HAS_RE_INFER.bits |
+ TypeFlags::HAS_RE_EARLY_BOUND.bits |
+ TypeFlags::HAS_FREE_REGIONS.bits |
+ TypeFlags::HAS_TY_ERR.bits |
+ TypeFlags::HAS_PROJECTION.bits |
+ TypeFlags::HAS_TY_CLOSURE.bits |
+ TypeFlags::HAS_LOCAL_NAMES.bits,
+
+ // Caches for type_is_sized, type_moves_by_default
+ const SIZEDNESS_CACHED = 1 << 16,
+ const IS_SIZED = 1 << 17,
+ const MOVENESS_CACHED = 1 << 18,
+ const MOVES_BY_DEFAULT = 1 << 19,
}
}
($ctxt: expr, $($variant: ident),*) => {{
// curious inner module to allow variant names to be used as
// variable names.
+ #[allow(non_snake_case)]
mod inner {
use middle::ty;
#[derive(Copy, Clone)]
$(let mut $variant = total;)*
- for (_, t) in &*tcx.interner.borrow() {
+ for (_, t) in tcx.interner.borrow().iter() {
let variant = match t.sty {
- ty::ty_bool | ty::ty_char | ty::ty_int(..) | ty::ty_uint(..) |
- ty::ty_float(..) | ty::ty_str => continue,
- ty::ty_err => /* unimportant */ continue,
+ ty::TyBool | ty::TyChar | ty::TyInt(..) | ty::TyUint(..) |
+ ty::TyFloat(..) | ty::TyStr => continue,
+ ty::TyError => /* unimportant */ continue,
$(ty::$variant(..) => &mut $variant,)*
};
- let region = t.flags.intersects(ty::TypeFlags::HAS_RE_INFER);
- let ty = t.flags.intersects(ty::TypeFlags::HAS_TY_INFER);
+ let region = t.flags.get().intersects(ty::TypeFlags::HAS_RE_INFER);
+ let ty = t.flags.get().intersects(ty::TypeFlags::HAS_TY_INFER);
variant.total += 1;
total.total += 1;
pub fn print_debug_stats(&self) {
sty_debug_print!(
self,
- ty_enum, ty_uniq, ty_vec, ty_ptr, ty_rptr, ty_bare_fn, ty_trait,
- ty_struct, ty_closure, ty_tup, ty_param, ty_infer, ty_projection);
+ TyEnum, TyBox, TyArray, TySlice, TyRawPtr, TyRef, TyBareFn, TyTrait,
+ TyStruct, TyClosure, TyTuple, TyParam, TyInfer, TyProjection);
println!("Substs interner: #{}", self.substs_interner.borrow().len());
println!("BareFnTy interner: #{}", self.bare_fn_interner.borrow().len());
println!("Region interner: #{}", self.region_interner.borrow().len());
+ println!("Stability interner: #{}", self.stability_interner.borrow().len());
}
}
-#[derive(Debug)]
pub struct TyS<'tcx> {
- pub sty: sty<'tcx>,
- pub flags: TypeFlags,
+ pub sty: TypeVariants<'tcx>,
+ pub flags: Cell<TypeFlags>,
// the maximal depth of any bound regions appearing in this type.
region_depth: u32,
}
}
-impl<'tcx> Borrow<sty<'tcx>> for InternedTy<'tcx> {
- fn borrow<'a>(&'a self) -> &'a sty<'tcx> {
+impl<'tcx> Borrow<TypeVariants<'tcx>> for InternedTy<'tcx> {
+ fn borrow<'a>(&'a self) -> &'a TypeVariants<'tcx> {
&self.ty.sty
}
}
pub fn type_has_params(ty: Ty) -> bool {
- ty.flags.intersects(TypeFlags::HAS_PARAMS)
+ ty.flags.get().intersects(TypeFlags::HAS_PARAMS)
}
pub fn type_has_self(ty: Ty) -> bool {
- ty.flags.intersects(TypeFlags::HAS_SELF)
+ ty.flags.get().intersects(TypeFlags::HAS_SELF)
}
pub fn type_has_ty_infer(ty: Ty) -> bool {
- ty.flags.intersects(TypeFlags::HAS_TY_INFER)
+ ty.flags.get().intersects(TypeFlags::HAS_TY_INFER)
}
pub fn type_needs_infer(ty: Ty) -> bool {
- ty.flags.intersects(TypeFlags::HAS_TY_INFER | TypeFlags::HAS_RE_INFER)
+ ty.flags.get().intersects(TypeFlags::HAS_TY_INFER | TypeFlags::HAS_RE_INFER)
+}
+pub fn type_is_global(ty: Ty) -> bool {
+ !ty.flags.get().intersects(TypeFlags::HAS_LOCAL_NAMES)
}
pub fn type_has_projection(ty: Ty) -> bool {
- ty.flags.intersects(TypeFlags::HAS_PROJECTION)
+ ty.flags.get().intersects(TypeFlags::HAS_PROJECTION)
+}
+pub fn type_has_ty_closure(ty: Ty) -> bool {
+ ty.flags.get().intersects(TypeFlags::HAS_TY_CLOSURE)
}
-pub fn type_has_late_bound_regions(ty: Ty) -> bool {
- ty.flags.intersects(TypeFlags::HAS_RE_LATE_BOUND)
+pub fn type_has_erasable_regions(ty: Ty) -> bool {
+ ty.flags.get().intersects(TypeFlags::HAS_RE_EARLY_BOUND |
+ TypeFlags::HAS_RE_INFER |
+ TypeFlags::HAS_FREE_REGIONS)
}
/// An "escaping region" is a bound region whose binder is not part of `t`.
pub sig: PolyFnSig<'tcx>,
}
-#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, PartialEq, Eq, Hash)]
pub struct ClosureTy<'tcx> {
pub unsafety: ast::Unsafety,
pub abi: abi::Abi,
}
}
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct ParamTy {
pub space: subst::ParamSpace,
pub idx: u32,
}
/// Representation of regions:
-#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug, Copy)]
+#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Copy)]
pub enum Region {
// Region bound in a type or fn declaration which will be
// substituted 'early' -- that is, at the same time when type
/// Upvars do not get their own node-id. Instead, we use the pair of
/// the original var id (that is, the root variable that is referenced
/// by the upvar) and the id of the closure expression.
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct UpvarId {
pub var_id: ast::NodeId,
pub closure_expr_id: ast::NodeId,
ByRef(UpvarBorrow),
}
-#[derive(PartialEq, Clone, RustcEncodable, RustcDecodable, Debug, Copy)]
+#[derive(PartialEq, Clone, RustcEncodable, RustcDecodable, Copy)]
pub struct UpvarBorrow {
/// The kind of borrow: by-ref upvars have access to shared
/// immutable borrows, which are not part of the normal language
pub type UpvarCaptureMap = FnvHashMap<UpvarId, UpvarCapture>;
impl Region {
+ pub fn is_global(&self) -> bool {
+ // does this represent a region that can be named in a global
+ // way? used in fulfillment caching.
+ match *self {
+ ty::ReStatic | ty::ReEmpty => true,
+ _ => false,
+ }
+ }
+
pub fn is_bound(&self) -> bool {
match *self {
ty::ReEarlyBound(..) => true,
}
#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash,
- RustcEncodable, RustcDecodable, Debug, Copy)]
+ RustcEncodable, RustcDecodable, Copy)]
/// A "free" region `fr` can be interpreted as "some region
/// at least as big as the scope `fr.scope`".
pub struct FreeRegion {
}
#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash,
- RustcEncodable, RustcDecodable, Debug, Copy)]
+ RustcEncodable, RustcDecodable, Copy, Debug)]
pub enum BoundRegion {
/// An anonymous region parameter for a given fn (&T)
BrAnon(u32),
// NB: If you change this, you'll probably want to change the corresponding
// AST structure in libsyntax/ast.rs as well.
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
-pub enum sty<'tcx> {
- ty_bool,
- ty_char,
- ty_int(ast::IntTy),
- ty_uint(ast::UintTy),
- ty_float(ast::FloatTy),
- /// Substs here, possibly against intuition, *may* contain `ty_param`s.
+pub enum TypeVariants<'tcx> {
+ /// The primitive boolean type. Written as `bool`.
+ TyBool,
+
+ /// The primitive character type; holds a Unicode scalar value
+ /// (a non-surrogate code point). Written as `char`.
+ TyChar,
+
+ /// A primitive signed integer type. For example, `i32`.
+ TyInt(ast::IntTy),
+
+ /// A primitive unsigned integer type. For example, `u32`.
+ TyUint(ast::UintTy),
+
+ /// A primitive floating-point type. For example, `f64`.
+ TyFloat(ast::FloatTy),
+
+ /// An enumerated type, defined with `enum`.
+ ///
+ /// Substs here, possibly against intuition, *may* contain `TyParam`s.
/// That is, even after substitution it is possible that there are type
- /// variables. This happens when the `ty_enum` corresponds to an enum
- /// definition and not a concrete use of it. To get the correct `ty_enum`
+ /// variables. This happens when the `TyEnum` corresponds to an enum
+ /// definition and not a concrete use of it. To get the correct `TyEnum`
/// from the tcx, use the `NodeId` from the `ast::Ty` and look it up in
- /// the `ast_ty_to_ty_cache`. This is probably true for `ty_struct` as
+ /// the `ast_ty_to_ty_cache`. This is probably true for `TyStruct` as
/// well.
- ty_enum(DefId, &'tcx Substs<'tcx>),
- ty_uniq(Ty<'tcx>),
- ty_str,
- ty_vec(Ty<'tcx>, Option<usize>), // Second field is length.
- ty_ptr(mt<'tcx>),
- ty_rptr(&'tcx Region, mt<'tcx>),
+ TyEnum(DefId, &'tcx Substs<'tcx>),
- // If the def-id is Some(_), then this is the type of a specific
- // fn item. Otherwise, if None(_), it a fn pointer type.
- ty_bare_fn(Option<DefId>, &'tcx BareFnTy<'tcx>),
+ /// A structure type, defined with `struct`.
+ ///
+ /// See warning about substitutions for enumerated types.
+ TyStruct(DefId, &'tcx Substs<'tcx>),
- ty_trait(Box<TyTrait<'tcx>>),
- ty_struct(DefId, &'tcx Substs<'tcx>),
+ /// `Box<T>`; this is nominally a struct in the documentation, but is
+ /// special-cased internally. For example, it is possible to implicitly
+ /// move the contents of a box out of that box, and methods of any type
+ /// can have type `Box<Self>`.
+ TyBox(Ty<'tcx>),
- ty_closure(DefId, &'tcx Substs<'tcx>),
+ /// The pointee of a string slice. Written as `str`.
+ TyStr,
- ty_tup(Vec<Ty<'tcx>>),
+ /// An array with the given length. Written as `[T; n]`.
+ TyArray(Ty<'tcx>, usize),
- ty_projection(ProjectionTy<'tcx>),
- ty_param(ParamTy), // type parameter
+ /// The pointee of an array slice. Written as `[T]`.
+ TySlice(Ty<'tcx>),
- ty_infer(InferTy), // something used only during inference/typeck
- ty_err, // Also only used during inference/typeck, to represent
- // the type of an erroneous expression (helps cut down
- // on non-useful type error messages)
+ /// A raw pointer. Written as `*mut T` or `*const T`
+ TyRawPtr(mt<'tcx>),
+
+ /// A reference; a pointer with an associated lifetime. Written as
+ /// `&a mut T` or `&'a T`.
+ TyRef(&'tcx Region, mt<'tcx>),
+
+ /// If the def-id is Some(_), then this is the type of a specific
+ /// fn item. Otherwise, if None(_), it a fn pointer type.
+ ///
+ /// FIXME: Conflating function pointers and the type of a
+ /// function is probably a terrible idea; a function pointer is a
+ /// value with a specific type, but a function can be polymorphic
+ /// or dynamically dispatched.
+ TyBareFn(Option<DefId>, &'tcx BareFnTy<'tcx>),
+
+ /// A trait, defined with `trait`.
+ TyTrait(Box<TraitTy<'tcx>>),
+
+ /// The anonymous type of a closure. Used to represent the type of
+ /// `|a| a`.
+ TyClosure(DefId, &'tcx Substs<'tcx>),
+
+ /// A tuple type. For example, `(i32, bool)`.
+ TyTuple(Vec<Ty<'tcx>>),
+
+ /// The projection of an associated type. For example,
+ /// `<T as Trait<..>>::N`.
+ TyProjection(ProjectionTy<'tcx>),
+
+ /// A type parameter; for example, `T` in `fn f<T>(x: T) {}
+ TyParam(ParamTy),
+
+ /// A type variable used during type-checking.
+ TyInfer(InferTy),
+
+ /// A placeholder for a type which could not be computed; this is
+ /// propagated to avoid useless error messages.
+ TyError,
}
-#[derive(Clone, PartialEq, Eq, Hash, Debug)]
-pub struct TyTrait<'tcx> {
+#[derive(Clone, PartialEq, Eq, Hash)]
+pub struct TraitTy<'tcx> {
pub principal: ty::PolyTraitRef<'tcx>,
pub bounds: ExistentialBounds<'tcx>,
}
-impl<'tcx> TyTrait<'tcx> {
+impl<'tcx> TraitTy<'tcx> {
pub fn principal_def_id(&self) -> ast::DefId {
self.principal.0.def_id
}
/// Note that a `TraitRef` introduces a level of region binding, to
/// account for higher-ranked trait bounds like `T : for<'a> Foo<&'a
/// U>` or higher-ranked object types.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct TraitRef<'tcx> {
pub def_id: DefId,
pub substs: &'tcx Substs<'tcx>,
terr_projection_bounds_length(expected_found<usize>),
}
-/// Bounds suitable for a named type parameter like `A` in `fn foo<A>`
-/// as well as the existential type parameter in an object type.
-#[derive(PartialEq, Eq, Hash, Clone, Debug)]
-pub struct ParamBounds<'tcx> {
- pub region_bounds: Vec<ty::Region>,
- pub builtin_bounds: BuiltinBounds,
- pub trait_bounds: Vec<PolyTraitRef<'tcx>>,
- pub projection_bounds: Vec<PolyProjectionPredicate<'tcx>>,
-}
-
/// Bounds suitable for an existentially quantified type parameter
-/// such as those that appear in object types or closure types. The
-/// major difference between this case and `ParamBounds` is that
-/// general purpose trait bounds are omitted and there must be
-/// *exactly one* region.
-#[derive(PartialEq, Eq, Hash, Clone, Debug)]
+/// such as those that appear in object types or closure types.
+#[derive(PartialEq, Eq, Hash, Clone)]
pub struct ExistentialBounds<'tcx> {
pub region_bound: ty::Region,
pub builtin_bounds: BuiltinBounds,
pub projection_bounds: Vec<PolyProjectionPredicate<'tcx>>,
+
+ // If true, this TyTrait used a "default bound" in the surface
+ // syntax. This makes no difference to the type system but is
+ // handy for error reporting.
+ pub region_bound_will_change: bool,
}
-pub type BuiltinBounds = EnumSet<BuiltinBound>;
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
+pub struct BuiltinBounds(EnumSet<BuiltinBound>);
-#[derive(Clone, RustcEncodable, PartialEq, Eq, RustcDecodable, Hash,
- Debug, Copy)]
-#[repr(usize)]
-pub enum BuiltinBound {
- BoundSend,
- BoundSized,
- BoundCopy,
- BoundSync,
+impl BuiltinBounds {
+ pub fn empty() -> BuiltinBounds {
+ BuiltinBounds(EnumSet::new())
+ }
+
+ pub fn iter(&self) -> enum_set::Iter<BuiltinBound> {
+ self.into_iter()
+ }
+
+ pub fn to_predicates<'tcx>(&self,
+ tcx: &ty::ctxt<'tcx>,
+ self_ty: Ty<'tcx>) -> Vec<Predicate<'tcx>> {
+ self.iter().filter_map(|builtin_bound|
+ match traits::trait_ref_for_builtin_bound(tcx, builtin_bound, self_ty) {
+ Ok(trait_ref) => Some(trait_ref.as_predicate()),
+ Err(ErrorReported) => { None }
+ }
+ ).collect()
+ }
+}
+
+impl ops::Deref for BuiltinBounds {
+ type Target = EnumSet<BuiltinBound>;
+ fn deref(&self) -> &Self::Target { &self.0 }
+}
+
+impl ops::DerefMut for BuiltinBounds {
+ fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
}
-pub fn empty_builtin_bounds() -> BuiltinBounds {
- EnumSet::new()
+impl<'a> IntoIterator for &'a BuiltinBounds {
+ type Item = BuiltinBound;
+ type IntoIter = enum_set::Iter<BuiltinBound>;
+ fn into_iter(self) -> Self::IntoIter {
+ (**self).into_iter()
+ }
}
-pub fn all_builtin_bounds() -> BuiltinBounds {
- let mut set = EnumSet::new();
- set.insert(BoundSend);
- set.insert(BoundSized);
- set.insert(BoundSync);
- set
+#[derive(Clone, RustcEncodable, PartialEq, Eq, RustcDecodable, Hash,
+ Debug, Copy)]
+#[repr(usize)]
+pub enum BuiltinBound {
+ Send,
+ Sized,
+ Copy,
+ Sync,
}
/// An existential bound that does not implement any traits.
pub fn region_existential_bound<'tcx>(r: ty::Region) -> ExistentialBounds<'tcx> {
ty::ExistentialBounds { region_bound: r,
- builtin_bounds: empty_builtin_bounds(),
- projection_bounds: Vec::new() }
+ builtin_bounds: BuiltinBounds::empty(),
+ projection_bounds: Vec::new(),
+ region_bound_will_change: false, }
}
impl CLike for BuiltinBound {
}
impl fmt::Debug for TyVid {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result{
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "_#{}t", self.index)
}
}
/// from `T:'a` annotations appearing in the type definition. If
/// this is `None`, then the default is inherited from the
/// surrounding context. See RFC #599 for details.
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone)]
pub enum ObjectLifetimeDefault {
/// Require an explicit annotation. Occurs when multiple
/// `T:'a` constraints are found.
Ambiguous,
+ /// Use the base default, typically 'static, but in a fn body it is a fresh variable
+ BaseDefault,
+
/// Use the given region as the default.
Specific(Region),
}
-#[derive(Clone, Debug)]
+#[derive(Clone)]
pub struct TypeParameterDef<'tcx> {
pub name: ast::Name,
pub def_id: ast::DefId,
pub space: subst::ParamSpace,
pub index: u32,
pub default: Option<Ty<'tcx>>,
- pub object_lifetime_default: Option<ObjectLifetimeDefault>,
+ pub object_lifetime_default: ObjectLifetimeDefault,
}
#[derive(RustcEncodable, RustcDecodable, Clone, Debug)]
}
/// Bounds on generics.
-#[derive(Clone, Debug)]
+#[derive(Clone)]
pub struct GenericPredicates<'tcx> {
pub predicates: VecPerParamSpace<Predicate<'tcx>>,
}
}
}
-#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, PartialEq, Eq, Hash)]
pub enum Predicate<'tcx> {
/// Corresponds to `where Foo : Bar<A,B,C>`. `Foo` here would be
/// the `Self` type of the trait reference and `A`, `B`, and `C`
Predicate::Projection(ty::Binder(data.subst(tcx, substs))),
}
}
+
+ // Indicates whether this predicate references only 'global'
+ // types/lifetimes that are the same regardless of what fn we are
+ // in. This is used for caching. Errs on the side of returning
+ // false.
+ pub fn is_global(&self) -> bool {
+ match *self {
+ ty::Predicate::Trait(ref data) => {
+ let substs = data.skip_binder().trait_ref.substs;
+
+ substs.types.iter().all(|t| ty::type_is_global(t)) && {
+ match substs.regions {
+ subst::ErasedRegions => true,
+ subst::NonerasedRegions(ref r) => r.iter().all(|r| r.is_global()),
+ }
+ }
+ }
+
+ _ => {
+ false
+ }
+ }
+ }
}
-#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, PartialEq, Eq, Hash)]
pub struct TraitPredicate<'tcx> {
pub trait_ref: TraitRef<'tcx>
}
/// equality between arbitrary types. Processing an instance of Form
/// #2 eventually yields one of these `ProjectionPredicate`
/// instances to normalize the LHS.
-#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, PartialEq, Eq, Hash)]
pub struct ProjectionPredicate<'tcx> {
pub projection_ty: ProjectionTy<'tcx>,
pub ty: Ty<'tcx>,
let trait_inputs = data.0.projection_ty.trait_ref.substs.types.as_slice();
trait_inputs.iter()
.cloned()
- .chain(Some(data.0.ty).into_iter())
+ .chain(Some(data.0.ty))
.collect()
}
};
/// `[[], [U:Bar<T>]]`. Now if there were some particular reference
/// like `Foo<isize,usize>`, then the `InstantiatedPredicates` would be `[[],
/// [usize:Bar<isize>]]`.
-#[derive(Clone, Debug)]
+#[derive(Clone)]
pub struct InstantiatedPredicates<'tcx> {
pub predicates: VecPerParamSpace<Predicate<'tcx>>,
}
/// Obligations that the caller must satisfy. This is basically
/// the set of bounds on the in-scope type parameters, translated
- /// into Obligations.
+ /// into Obligations, and elaborated and normalized.
pub caller_bounds: Vec<ty::Predicate<'tcx>>,
/// Caches the results of trait selection. This cache is used
}
Some(ast_map::NodeItem(item)) => {
match item.node {
- ast::ItemFn(_, _, _, _, ref body) => {
+ ast::ItemFn(_, _, _, _, _, ref body) => {
// We assume this is a function.
let fn_def_id = ast_util::local_def(id);
let fn_scheme = lookup_item_type(cx, fn_def_id);
tcx: &ctxt<'tcx>,
impl_def_id: DefId,
impl_trait_ref: TraitRef<'tcx>) {
- debug!("TraitDef::record_impl for {}, from {}",
- self.repr(tcx), impl_trait_ref.repr(tcx));
+ debug!("TraitDef::record_impl for {:?}, from {:?}",
+ self, impl_trait_ref);
// We don't want to borrow_mut after we already populated all impls,
// so check if an impl is present with an immutable borrow first.
-> CommonTypes<'tcx>
{
CommonTypes {
- bool: intern_ty(arena, interner, ty_bool),
- char: intern_ty(arena, interner, ty_char),
- err: intern_ty(arena, interner, ty_err),
- isize: intern_ty(arena, interner, ty_int(ast::TyIs)),
- i8: intern_ty(arena, interner, ty_int(ast::TyI8)),
- i16: intern_ty(arena, interner, ty_int(ast::TyI16)),
- i32: intern_ty(arena, interner, ty_int(ast::TyI32)),
- i64: intern_ty(arena, interner, ty_int(ast::TyI64)),
- usize: intern_ty(arena, interner, ty_uint(ast::TyUs)),
- u8: intern_ty(arena, interner, ty_uint(ast::TyU8)),
- u16: intern_ty(arena, interner, ty_uint(ast::TyU16)),
- u32: intern_ty(arena, interner, ty_uint(ast::TyU32)),
- u64: intern_ty(arena, interner, ty_uint(ast::TyU64)),
- f32: intern_ty(arena, interner, ty_float(ast::TyF32)),
- f64: intern_ty(arena, interner, ty_float(ast::TyF64)),
- }
- }
-}
-
-pub fn mk_ctxt<'tcx>(s: Session,
- arenas: &'tcx CtxtArenas<'tcx>,
- def_map: DefMap,
- named_region_map: resolve_lifetime::NamedRegionMap,
- map: ast_map::Map<'tcx>,
- freevars: RefCell<FreevarMap>,
- region_maps: RegionMaps,
- lang_items: middle::lang_items::LanguageItems,
- stability: stability::Index) -> ctxt<'tcx>
+ bool: intern_ty(arena, interner, TyBool),
+ char: intern_ty(arena, interner, TyChar),
+ err: intern_ty(arena, interner, TyError),
+ isize: intern_ty(arena, interner, TyInt(ast::TyIs)),
+ i8: intern_ty(arena, interner, TyInt(ast::TyI8)),
+ i16: intern_ty(arena, interner, TyInt(ast::TyI16)),
+ i32: intern_ty(arena, interner, TyInt(ast::TyI32)),
+ i64: intern_ty(arena, interner, TyInt(ast::TyI64)),
+ usize: intern_ty(arena, interner, TyUint(ast::TyUs)),
+ u8: intern_ty(arena, interner, TyUint(ast::TyU8)),
+ u16: intern_ty(arena, interner, TyUint(ast::TyU16)),
+ u32: intern_ty(arena, interner, TyUint(ast::TyU32)),
+ u64: intern_ty(arena, interner, TyUint(ast::TyU64)),
+ f32: intern_ty(arena, interner, TyFloat(ast::TyF32)),
+ f64: intern_ty(arena, interner, TyFloat(ast::TyF64)),
+ }
+ }
+}
+
+/// Create a type context and call the closure with a `&ty::ctxt` reference
+/// to the context. The closure enforces that the type context and any interned
+/// value (types, substs, etc.) can only be used while `ty::tls` has a valid
+/// reference to the context, to allow formatting values that need it.
+pub fn with_ctxt<'tcx, F, R>(s: Session,
+ arenas: &'tcx CtxtArenas<'tcx>,
+ def_map: DefMap,
+ named_region_map: resolve_lifetime::NamedRegionMap,
+ map: ast_map::Map<'tcx>,
+ freevars: RefCell<FreevarMap>,
+ region_maps: RegionMaps,
+ lang_items: middle::lang_items::LanguageItems,
+ stability: stability::Index<'tcx>,
+ f: F) -> (Session, R)
+ where F: FnOnce(&ctxt<'tcx>) -> R
{
let mut interner = FnvHashMap();
let common_types = CommonTypes::new(&arenas.type_, &mut interner);
- ctxt {
+ tls::enter(ctxt {
arenas: arenas,
interner: RefCell::new(interner),
substs_interner: RefCell::new(FnvHashMap()),
bare_fn_interner: RefCell::new(FnvHashMap()),
region_interner: RefCell::new(FnvHashMap()),
+ stability_interner: RefCell::new(FnvHashMap()),
types: common_types,
named_region_map: named_region_map,
region_maps: region_maps,
def_map: def_map,
node_types: RefCell::new(FnvHashMap()),
item_substs: RefCell::new(NodeMap()),
- impl_trait_refs: RefCell::new(NodeMap()),
+ impl_trait_refs: RefCell::new(DefIdMap()),
trait_defs: RefCell::new(DefIdMap()),
predicates: RefCell::new(DefIdMap()),
super_predicates: RefCell::new(DefIdMap()),
- object_cast_map: RefCell::new(NodeMap()),
+ fulfilled_predicates: RefCell::new(traits::FulfilledPredicates::new()),
map: map,
freevars: freevars,
tcache: RefCell::new(DefIdMap()),
rcache: RefCell::new(FnvHashMap()),
- short_names_cache: RefCell::new(FnvHashMap()),
tc_cache: RefCell::new(FnvHashMap()),
ast_ty_to_ty_cache: RefCell::new(NodeMap()),
enum_var_cache: RefCell::new(DefIdMap()),
impl_or_trait_items: RefCell::new(DefIdMap()),
trait_item_def_ids: RefCell::new(DefIdMap()),
trait_items_cache: RefCell::new(DefIdMap()),
- impl_trait_cache: RefCell::new(DefIdMap()),
ty_param_defs: RefCell::new(NodeMap()),
adjustments: RefCell::new(NodeMap()),
normalized_cache: RefCell::new(FnvHashMap()),
upvar_capture_map: RefCell::new(FnvHashMap()),
extern_const_statics: RefCell::new(DefIdMap()),
extern_const_variants: RefCell::new(DefIdMap()),
+ extern_const_fns: RefCell::new(DefIdMap()),
method_map: RefCell::new(FnvHashMap()),
dependency_formats: RefCell::new(FnvHashMap()),
closure_kinds: RefCell::new(DefIdMap()),
node_lint_levels: RefCell::new(FnvHashMap()),
transmute_restrictions: RefCell::new(Vec::new()),
stability: RefCell::new(stability),
- associated_types: RefCell::new(DefIdMap()),
selection_cache: traits::SelectionCache::new(),
repr_hint_cache: RefCell::new(DefIdMap()),
- type_impls_copy_cache: RefCell::new(HashMap::new()),
- type_impls_sized_cache: RefCell::new(HashMap::new()),
const_qualif_map: RefCell::new(NodeMap()),
custom_coerce_unsized_kinds: RefCell::new(DefIdMap()),
- }
+ cast_kinds: RefCell::new(NodeMap()),
+ }, f)
}
// Type constructors
self.ty_param_defs.borrow().get(&node_id).unwrap().clone()
}
- pub fn pat_contains_ref_binding(&self, pat: &ast::Pat) -> bool {
+ pub fn pat_contains_ref_binding(&self, pat: &ast::Pat) -> Option<ast::Mutability> {
pat_util::pat_contains_ref_binding(&self.def_map, pat)
}
- pub fn arm_contains_ref_binding(&self, arm: &ast::Arm) -> bool {
+ pub fn arm_contains_ref_binding(&self, arm: &ast::Arm) -> Option<ast::Mutability> {
pat_util::arm_contains_ref_binding(&self.def_map, arm)
}
}
// Interns a type/name combination, stores the resulting box in cx.interner,
// and returns the box as cast to an unsafe ptr (see comments for Ty above).
-pub fn mk_t<'tcx>(cx: &ctxt<'tcx>, st: sty<'tcx>) -> Ty<'tcx> {
+pub fn mk_t<'tcx>(cx: &ctxt<'tcx>, st: TypeVariants<'tcx>) -> Ty<'tcx> {
let mut interner = cx.interner.borrow_mut();
intern_ty(&cx.arenas.type_, &mut *interner, st)
}
fn intern_ty<'tcx>(type_arena: &'tcx TypedArena<TyS<'tcx>>,
interner: &mut FnvHashMap<InternedTy<'tcx>, Ty<'tcx>>,
- st: sty<'tcx>)
+ st: TypeVariants<'tcx>)
-> Ty<'tcx>
{
match interner.get(&st) {
let ty = match () {
() => type_arena.alloc(TyS { sty: st,
- flags: flags.flags,
+ flags: Cell::new(flags.flags),
region_depth: flags.depth, }),
};
FlagComputation { flags: TypeFlags::empty(), depth: 0 }
}
- fn for_sty(st: &sty) -> FlagComputation {
+ fn for_sty(st: &TypeVariants) -> FlagComputation {
let mut result = FlagComputation::new();
result.add_sty(st);
result
}
fn add_flags(&mut self, flags: TypeFlags) {
- self.flags = self.flags | flags;
+ self.flags = self.flags | (flags & TypeFlags::NOMINAL_FLAGS);
}
fn add_depth(&mut self, depth: u32) {
}
}
- fn add_sty(&mut self, st: &sty) {
+ fn add_sty(&mut self, st: &TypeVariants) {
match st {
- &ty_bool |
- &ty_char |
- &ty_int(_) |
- &ty_float(_) |
- &ty_uint(_) |
- &ty_str => {
+ &TyBool |
+ &TyChar |
+ &TyInt(_) |
+ &TyFloat(_) |
+ &TyUint(_) |
+ &TyStr => {
}
- // You might think that we could just return ty_err for
- // any type containing ty_err as a component, and get
+ // You might think that we could just return TyError for
+ // any type containing TyError as a component, and get
// rid of the TypeFlags::HAS_TY_ERR flag -- likewise for ty_bot (with
// the exception of function types that return bot).
// But doing so caused sporadic memory corruption, and
// neither I (tjc) nor nmatsakis could figure out why,
// so we're doing it this way.
- &ty_err => {
+ &TyError => {
self.add_flags(TypeFlags::HAS_TY_ERR)
}
- &ty_param(ref p) => {
+ &TyParam(ref p) => {
+ self.add_flags(TypeFlags::HAS_LOCAL_NAMES);
if p.space == subst::SelfSpace {
self.add_flags(TypeFlags::HAS_SELF);
} else {
}
}
- &ty_closure(_, substs) => {
+ &TyClosure(_, substs) => {
+ self.add_flags(TypeFlags::HAS_TY_CLOSURE);
+ self.add_flags(TypeFlags::HAS_LOCAL_NAMES);
self.add_substs(substs);
}
- &ty_infer(_) => {
+ &TyInfer(_) => {
+ self.add_flags(TypeFlags::HAS_LOCAL_NAMES); // it might, right?
self.add_flags(TypeFlags::HAS_TY_INFER)
}
- &ty_enum(_, substs) | &ty_struct(_, substs) => {
+ &TyEnum(_, substs) | &TyStruct(_, substs) => {
self.add_substs(substs);
}
- &ty_projection(ref data) => {
+ &TyProjection(ref data) => {
self.add_flags(TypeFlags::HAS_PROJECTION);
self.add_projection_ty(data);
}
- &ty_trait(box TyTrait { ref principal, ref bounds }) => {
+ &TyTrait(box TraitTy { ref principal, ref bounds }) => {
let mut computation = FlagComputation::new();
computation.add_substs(principal.0.substs);
for projection_bound in &bounds.projection_bounds {
let mut proj_computation = FlagComputation::new();
proj_computation.add_projection_predicate(&projection_bound.0);
- computation.add_bound_computation(&proj_computation);
+ self.add_bound_computation(&proj_computation);
}
self.add_bound_computation(&computation);
self.add_bounds(bounds);
}
- &ty_uniq(tt) | &ty_vec(tt, _) => {
+ &TyBox(tt) | &TyArray(tt, _) | &TySlice(tt) => {
self.add_ty(tt)
}
- &ty_ptr(ref m) => {
+ &TyRawPtr(ref m) => {
self.add_ty(m.ty);
}
- &ty_rptr(r, ref m) => {
+ &TyRef(r, ref m) => {
self.add_region(*r);
self.add_ty(m.ty);
}
- &ty_tup(ref ts) => {
+ &TyTuple(ref ts) => {
self.add_tys(&ts[..]);
}
- &ty_bare_fn(_, ref f) => {
+ &TyBareFn(_, ref f) => {
self.add_fn_sig(&f.sig);
}
}
}
fn add_ty(&mut self, ty: Ty) {
- self.add_flags(ty.flags);
+ self.add_flags(ty.flags.get());
self.add_depth(ty.region_depth);
}
}
fn add_region(&mut self, r: Region) {
- self.add_flags(TypeFlags::HAS_REGIONS);
match r {
ty::ReInfer(_) => { self.add_flags(TypeFlags::HAS_RE_INFER); }
- ty::ReLateBound(debruijn, _) => {
- self.add_flags(TypeFlags::HAS_RE_LATE_BOUND);
- self.add_depth(debruijn.depth);
- }
- _ => { }
+ ty::ReLateBound(debruijn, _) => { self.add_depth(debruijn.depth); }
+ ty::ReEarlyBound(..) => { self.add_flags(TypeFlags::HAS_RE_EARLY_BOUND); }
+ ty::ReStatic => {}
+ _ => { self.add_flags(TypeFlags::HAS_FREE_REGIONS); }
+ }
+
+ if !r.is_global() {
+ self.add_flags(TypeFlags::HAS_LOCAL_NAMES);
}
}
match substs.regions {
subst::ErasedRegions => {}
subst::NonerasedRegions(ref regions) => {
- for &r in regions.iter() {
+ for &r in regions {
self.add_region(r);
}
}
}
pub fn mk_str<'tcx>(cx: &ctxt<'tcx>) -> Ty<'tcx> {
- mk_t(cx, ty_str)
+ mk_t(cx, TyStr)
}
pub fn mk_str_slice<'tcx>(cx: &ctxt<'tcx>, r: &'tcx Region, m: ast::Mutability) -> Ty<'tcx> {
mk_rptr(cx, r,
mt {
- ty: mk_t(cx, ty_str),
+ ty: mk_t(cx, TyStr),
mutbl: m
})
}
pub fn mk_enum<'tcx>(cx: &ctxt<'tcx>, did: ast::DefId, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> {
// take a copy of substs so that we own the vectors inside
- mk_t(cx, ty_enum(did, substs))
+ mk_t(cx, TyEnum(did, substs))
}
-pub fn mk_uniq<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { mk_t(cx, ty_uniq(ty)) }
+pub fn mk_uniq<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { mk_t(cx, TyBox(ty)) }
-pub fn mk_ptr<'tcx>(cx: &ctxt<'tcx>, tm: mt<'tcx>) -> Ty<'tcx> { mk_t(cx, ty_ptr(tm)) }
+pub fn mk_ptr<'tcx>(cx: &ctxt<'tcx>, tm: mt<'tcx>) -> Ty<'tcx> { mk_t(cx, TyRawPtr(tm)) }
pub fn mk_rptr<'tcx>(cx: &ctxt<'tcx>, r: &'tcx Region, tm: mt<'tcx>) -> Ty<'tcx> {
- mk_t(cx, ty_rptr(r, tm))
+ mk_t(cx, TyRef(r, tm))
}
pub fn mk_mut_rptr<'tcx>(cx: &ctxt<'tcx>, r: &'tcx Region, ty: Ty<'tcx>) -> Ty<'tcx> {
}
pub fn mk_vec<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>, sz: Option<usize>) -> Ty<'tcx> {
- mk_t(cx, ty_vec(ty, sz))
+ match sz {
+ Some(n) => mk_t(cx, TyArray(ty, n)),
+ None => mk_t(cx, TySlice(ty))
+ }
}
pub fn mk_slice<'tcx>(cx: &ctxt<'tcx>, r: &'tcx Region, tm: mt<'tcx>) -> Ty<'tcx> {
}
pub fn mk_tup<'tcx>(cx: &ctxt<'tcx>, ts: Vec<Ty<'tcx>>) -> Ty<'tcx> {
- mk_t(cx, ty_tup(ts))
+ mk_t(cx, TyTuple(ts))
}
pub fn mk_nil<'tcx>(cx: &ctxt<'tcx>) -> Ty<'tcx> {
}
pub fn mk_bool<'tcx>(cx: &ctxt<'tcx>) -> Ty<'tcx> {
- mk_t(cx, ty_bool)
+ mk_t(cx, TyBool)
}
pub fn mk_bare_fn<'tcx>(cx: &ctxt<'tcx>,
opt_def_id: Option<ast::DefId>,
fty: &'tcx BareFnTy<'tcx>) -> Ty<'tcx> {
- mk_t(cx, ty_bare_fn(opt_def_id, fty))
+ mk_t(cx, TyBareFn(opt_def_id, fty))
}
pub fn mk_ctor_fn<'tcx>(cx: &ctxt<'tcx>,
{
assert!(bound_list_is_sorted(&bounds.projection_bounds));
- let inner = box TyTrait {
+ let inner = box TraitTy {
principal: principal,
bounds: bounds
};
- mk_t(cx, ty_trait(inner))
+ mk_t(cx, TyTrait(inner))
}
fn bound_list_is_sorted(bounds: &[ty::PolyProjectionPredicate]) -> bool {
-> Ty<'tcx> {
// take a copy of substs so that we own the vectors inside
let inner = ProjectionTy { trait_ref: trait_ref, item_name: item_name };
- mk_t(cx, ty_projection(inner))
+ mk_t(cx, TyProjection(inner))
}
pub fn mk_struct<'tcx>(cx: &ctxt<'tcx>, struct_id: ast::DefId,
substs: &'tcx Substs<'tcx>) -> Ty<'tcx> {
// take a copy of substs so that we own the vectors inside
- mk_t(cx, ty_struct(struct_id, substs))
+ mk_t(cx, TyStruct(struct_id, substs))
}
pub fn mk_closure<'tcx>(cx: &ctxt<'tcx>, closure_id: ast::DefId, substs: &'tcx Substs<'tcx>)
-> Ty<'tcx> {
- mk_t(cx, ty_closure(closure_id, substs))
+ mk_t(cx, TyClosure(closure_id, substs))
}
pub fn mk_var<'tcx>(cx: &ctxt<'tcx>, v: TyVid) -> Ty<'tcx> {
}
pub fn mk_infer<'tcx>(cx: &ctxt<'tcx>, it: InferTy) -> Ty<'tcx> {
- mk_t(cx, ty_infer(it))
+ mk_t(cx, TyInfer(it))
}
pub fn mk_param<'tcx>(cx: &ctxt<'tcx>,
space: subst::ParamSpace,
index: u32,
name: ast::Name) -> Ty<'tcx> {
- mk_t(cx, ty_param(ParamTy { space: space, idx: index, name: name }))
+ mk_t(cx, TyParam(ParamTy { space: space, idx: index, name: name }))
}
pub fn mk_self_type<'tcx>(cx: &ctxt<'tcx>) -> Ty<'tcx> {
pub fn as_opt_param_ty(&self) -> Option<ty::ParamTy> {
match self.sty {
- ty::ty_param(ref d) => Some(d.clone()),
+ ty::TyParam(ref d) => Some(d.clone()),
_ => None,
}
}
pub fn is_param(&self, space: ParamSpace, index: u32) -> bool {
match self.sty {
- ty::ty_param(ref data) => data.space == space && data.idx == index,
+ ty::TyParam(ref data) => data.space == space && data.idx == index,
_ => false,
}
}
}
}
-impl<'tcx> ParamBounds<'tcx> {
- pub fn empty() -> ParamBounds<'tcx> {
- ParamBounds {
- builtin_bounds: empty_builtin_bounds(),
- trait_bounds: Vec::new(),
- region_bounds: Vec::new(),
- projection_bounds: Vec::new(),
- }
- }
-}
-
// Type utilities
pub fn type_is_nil(ty: Ty) -> bool {
match ty.sty {
- ty_tup(ref tys) => tys.is_empty(),
+ TyTuple(ref tys) => tys.is_empty(),
_ => false
}
}
pub fn type_is_error(ty: Ty) -> bool {
- ty.flags.intersects(TypeFlags::HAS_TY_ERR)
+ ty.flags.get().intersects(TypeFlags::HAS_TY_ERR)
}
pub fn type_needs_subst(ty: Ty) -> bool {
- ty.flags.intersects(TypeFlags::NEEDS_SUBST)
+ ty.flags.get().intersects(TypeFlags::NEEDS_SUBST)
}
pub fn trait_ref_contains_error(tref: &ty::TraitRef) -> bool {
pub fn type_is_ty_var(ty: Ty) -> bool {
match ty.sty {
- ty_infer(TyVar(_)) => true,
+ TyInfer(TyVar(_)) => true,
_ => false
}
}
-pub fn type_is_bool(ty: Ty) -> bool { ty.sty == ty_bool }
+pub fn type_is_bool(ty: Ty) -> bool { ty.sty == TyBool }
pub fn type_is_self(ty: Ty) -> bool {
match ty.sty {
- ty_param(ref p) => p.space == subst::SelfSpace,
+ TyParam(ref p) => p.space == subst::SelfSpace,
_ => false
}
}
fn type_is_slice(ty: Ty) -> bool {
match ty.sty {
- ty_ptr(mt) | ty_rptr(_, mt) => match mt.ty.sty {
- ty_vec(_, None) | ty_str => true,
+ TyRawPtr(mt) | TyRef(_, mt) => match mt.ty.sty {
+ TySlice(_) | TyStr => true,
_ => false,
},
_ => false
}
}
-pub fn type_is_vec(ty: Ty) -> bool {
- match ty.sty {
- ty_vec(..) => true,
- ty_ptr(mt{ty, ..}) | ty_rptr(_, mt{ty, ..}) |
- ty_uniq(ty) => match ty.sty {
- ty_vec(_, None) => true,
- _ => false
- },
- _ => false
- }
-}
-
pub fn type_is_structural(ty: Ty) -> bool {
match ty.sty {
- ty_struct(..) | ty_tup(_) | ty_enum(..) |
- ty_vec(_, Some(_)) | ty_closure(..) => true,
+ TyStruct(..) | TyTuple(_) | TyEnum(..) |
+ TyArray(..) | TyClosure(..) => true,
_ => type_is_slice(ty) | type_is_trait(ty)
}
}
pub fn type_is_simd(cx: &ctxt, ty: Ty) -> bool {
match ty.sty {
- ty_struct(did, _) => lookup_simd(cx, did),
+ TyStruct(did, _) => lookup_simd(cx, did),
_ => false
}
}
pub fn sequence_element_type<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
match ty.sty {
- ty_vec(ty, _) => ty,
- ty_str => mk_mach_uint(cx, ast::TyU8),
+ TyArray(ty, _) | TySlice(ty) => ty,
+ TyStr => mk_mach_uint(cx, ast::TyU8),
_ => cx.sess.bug(&format!("sequence_element_type called on non-sequence value: {}",
- ty_to_string(cx, ty))),
+ ty)),
}
}
pub fn simd_type<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
match ty.sty {
- ty_struct(did, substs) => {
+ TyStruct(did, substs) => {
let fields = lookup_struct_fields(cx, did);
lookup_field_type(cx, did, fields[0].id, substs)
}
pub fn simd_size(cx: &ctxt, ty: Ty) -> usize {
match ty.sty {
- ty_struct(did, _) => {
+ TyStruct(did, _) => {
let fields = lookup_struct_fields(cx, did);
fields.len()
}
pub fn type_is_region_ptr(ty: Ty) -> bool {
match ty.sty {
- ty_rptr(..) => true,
+ TyRef(..) => true,
_ => false
}
}
pub fn type_is_unsafe_ptr(ty: Ty) -> bool {
match ty.sty {
- ty_ptr(_) => return true,
+ TyRawPtr(_) => return true,
_ => return false
}
}
pub fn type_is_unique(ty: Ty) -> bool {
match ty.sty {
- ty_uniq(_) => true,
+ TyBox(_) => true,
_ => false
}
}
/*
A scalar type is one that denotes an atomic datum, with no sub-components.
- (A ty_ptr is scalar because it represents a non-managed pointer, so its
+ (A TyRawPtr is scalar because it represents a non-managed pointer, so its
contents are abstract to rustc.)
*/
pub fn type_is_scalar(ty: Ty) -> bool {
match ty.sty {
- ty_bool | ty_char | ty_int(_) | ty_float(_) | ty_uint(_) |
- ty_infer(IntVar(_)) | ty_infer(FloatVar(_)) |
- ty_bare_fn(..) | ty_ptr(_) => true,
+ TyBool | TyChar | TyInt(_) | TyFloat(_) | TyUint(_) |
+ TyInfer(IntVar(_)) | TyInfer(FloatVar(_)) |
+ TyBareFn(..) | TyRawPtr(_) => true,
_ => false
}
}
/// Returns true if this type is a floating point type and false otherwise.
pub fn type_is_floating_point(ty: Ty) -> bool {
match ty.sty {
- ty_float(_) |
- ty_infer(FloatVar(_)) =>
+ TyFloat(_) |
+ TyInfer(FloatVar(_)) =>
true,
_ =>
*self & TC::ReachesAll)
}
- /// Includes only those bits that still apply when indirected through an unsafe pointer (`*`)
+ /// Includes only those bits that still apply when indirected through a raw pointer (`*`)
pub fn unsafe_pointer(&self) -> TypeContents {
*self & TC::ReachesAll
}
}
}
-pub fn type_interior_is_unsafe<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
- type_contents(cx, ty).interior_unsafe()
-}
-
pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents {
return memoized(&cx.tc_cache, ty, |ty| {
tc_ty(cx, ty, &mut FnvHashMap())
let result = match ty.sty {
// usize and isize are ffi-unsafe
- ty_uint(ast::TyUs) | ty_int(ast::TyIs) => {
+ TyUint(ast::TyUs) | TyInt(ast::TyIs) => {
TC::ReachesFfiUnsafe
}
// Scalar and unique types are sendable, and durable
- ty_infer(ty::FreshIntTy(_)) | ty_infer(ty::FreshFloatTy(_)) |
- ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) |
- ty_bare_fn(..) | ty::ty_char => {
+ TyInfer(ty::FreshIntTy(_)) | TyInfer(ty::FreshFloatTy(_)) |
+ TyBool | TyInt(_) | TyUint(_) | TyFloat(_) |
+ TyBareFn(..) | ty::TyChar => {
TC::None
}
- ty_uniq(typ) => {
+ TyBox(typ) => {
TC::ReachesFfiUnsafe | match typ.sty {
- ty_str => TC::OwnsOwned,
+ TyStr => TC::OwnsOwned,
_ => tc_ty(cx, typ, cache).owned_pointer(),
}
}
- ty_trait(box TyTrait { ref bounds, .. }) => {
+ TyTrait(box TraitTy { ref bounds, .. }) => {
object_contents(bounds) | TC::ReachesFfiUnsafe | TC::Nonsized
}
- ty_ptr(ref mt) => {
+ TyRawPtr(ref mt) => {
tc_ty(cx, mt.ty, cache).unsafe_pointer()
}
- ty_rptr(r, ref mt) => {
+ TyRef(r, ref mt) => {
TC::ReachesFfiUnsafe | match mt.ty.sty {
- ty_str => borrowed_contents(*r, ast::MutImmutable),
- ty_vec(..) => tc_ty(cx, mt.ty, cache).reference(borrowed_contents(*r,
+ TyStr => borrowed_contents(*r, ast::MutImmutable),
+ TyArray(..) |
+ TySlice(_) => tc_ty(cx, mt.ty, cache).reference(borrowed_contents(*r,
mt.mutbl)),
_ => tc_ty(cx, mt.ty, cache).reference(borrowed_contents(*r, mt.mutbl)),
}
}
- ty_vec(ty, Some(_)) => {
+ TyArray(ty, _) => {
tc_ty(cx, ty, cache)
}
- ty_vec(ty, None) => {
+ TySlice(ty) => {
tc_ty(cx, ty, cache) | TC::Nonsized
}
- ty_str => TC::Nonsized,
+ TyStr => TC::Nonsized,
- ty_struct(did, substs) => {
+ TyStruct(did, substs) => {
let flds = struct_fields(cx, did, substs);
let mut res =
TypeContents::union(&flds[..],
apply_lang_items(cx, did, res)
}
- ty_closure(did, substs) => {
+ TyClosure(did, substs) => {
// FIXME(#14449): `borrowed_contents` below assumes `&mut` closure.
let param_env = ty::empty_parameter_environment(cx);
let upvars = closure_upvars(¶m_env, did, substs).unwrap();
TypeContents::union(&upvars, |f| tc_ty(cx, &f.ty, cache))
}
- ty_tup(ref tys) => {
+ TyTuple(ref tys) => {
TypeContents::union(&tys[..],
|ty| tc_ty(cx, *ty, cache))
}
- ty_enum(did, substs) => {
+ TyEnum(did, substs) => {
let variants = substd_enum_variants(cx, did, substs);
let mut res =
TypeContents::union(&variants[..], |variant| {
if variants[data_idx].args.len() == 1 {
match variants[data_idx].args[0].sty {
- ty_bare_fn(..) => { res = res - TC::ReachesFfiUnsafe; }
+ TyBareFn(..) => { res = res - TC::ReachesFfiUnsafe; }
_ => { }
}
}
apply_lang_items(cx, did, res)
}
- ty_projection(..) |
- ty_param(_) => {
+ TyProjection(..) |
+ TyParam(_) => {
TC::All
}
- ty_infer(_) |
- ty_err => {
+ TyInfer(_) |
+ TyError => {
cx.sess.bug("asked to compute contents of error type");
}
};
}
}
-fn type_impls_bound<'a,'tcx>(param_env: &ParameterEnvironment<'a,'tcx>,
- cache: &RefCell<HashMap<Ty<'tcx>,bool>>,
+fn type_impls_bound<'a,'tcx>(param_env: Option<&ParameterEnvironment<'a,'tcx>>,
+ tcx: &ty::ctxt<'tcx>,
ty: Ty<'tcx>,
bound: ty::BuiltinBound,
span: Span)
-> bool
{
- assert!(!ty::type_needs_infer(ty));
-
- if !type_has_params(ty) && !type_has_self(ty) {
- match cache.borrow().get(&ty) {
- None => {}
- Some(&result) => {
- debug!("type_impls_bound({}, {:?}) = {:?} (cached)",
- ty.repr(param_env.tcx),
- bound,
- result);
- return result
- }
+ let pe;
+ let param_env = match param_env {
+ Some(e) => e,
+ None => {
+ pe = empty_parameter_environment(tcx);
+ &pe
}
- }
-
- let infcx = infer::new_infer_ctxt(param_env.tcx);
+ };
+ let infcx = infer::new_infer_ctxt(tcx);
let is_impld = traits::type_known_to_meet_builtin_bound(&infcx, param_env, ty, bound, span);
- debug!("type_impls_bound({}, {:?}) = {:?}",
- ty.repr(param_env.tcx),
+ debug!("type_impls_bound({:?}, {:?}) = {:?}",
+ ty,
bound,
is_impld);
- if !type_has_params(ty) && !type_has_self(ty) {
- let old_value = cache.borrow_mut().insert(ty, is_impld);
- assert!(old_value.is_none());
- }
-
is_impld
}
ty: Ty<'tcx>)
-> bool
{
- let tcx = param_env.tcx;
- !type_impls_bound(param_env, &tcx.type_impls_copy_cache, ty, ty::BoundCopy, span)
+ if ty.flags.get().intersects(TypeFlags::MOVENESS_CACHED) {
+ return ty.flags.get().intersects(TypeFlags::MOVES_BY_DEFAULT);
+ }
+
+ assert!(!ty::type_needs_infer(ty));
+
+ // Fast-path for primitive types
+ let result = match ty.sty {
+ TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) |
+ TyRawPtr(..) | TyBareFn(..) | TyRef(_, mt {
+ mutbl: ast::MutImmutable, ..
+ }) => Some(false),
+
+ TyStr | TyBox(..) | TyRef(_, mt {
+ mutbl: ast::MutMutable, ..
+ }) => Some(true),
+
+ TyArray(..) | TySlice(_) | TyTrait(..) | TyTuple(..) |
+ TyClosure(..) | TyEnum(..) | TyStruct(..) |
+ TyProjection(..) | TyParam(..) | TyInfer(..) | TyError => None
+ }.unwrap_or_else(|| !type_impls_bound(Some(param_env),
+ param_env.tcx,
+ ty,
+ ty::BoundCopy,
+ span));
+
+ if !type_has_params(ty) && !type_has_self(ty) {
+ ty.flags.set(ty.flags.get() | if result {
+ TypeFlags::MOVENESS_CACHED | TypeFlags::MOVES_BY_DEFAULT
+ } else {
+ TypeFlags::MOVENESS_CACHED
+ });
+ }
+
+ result
}
-pub fn type_is_sized<'a,'tcx>(param_env: &ParameterEnvironment<'a,'tcx>,
+#[inline]
+pub fn type_is_sized<'a,'tcx>(param_env: Option<&ParameterEnvironment<'a,'tcx>>,
+ tcx: &ty::ctxt<'tcx>,
span: Span,
ty: Ty<'tcx>)
-> bool
{
- let tcx = param_env.tcx;
- type_impls_bound(param_env, &tcx.type_impls_sized_cache, ty, ty::BoundSized, span)
+ if ty.flags.get().intersects(TypeFlags::SIZEDNESS_CACHED) {
+ let result = ty.flags.get().intersects(TypeFlags::IS_SIZED);
+ return result;
+ }
+
+ type_is_sized_uncached(param_env, tcx, span, ty)
+}
+
+fn type_is_sized_uncached<'a,'tcx>(param_env: Option<&ParameterEnvironment<'a,'tcx>>,
+ tcx: &ty::ctxt<'tcx>,
+ span: Span,
+ ty: Ty<'tcx>) -> bool {
+ assert!(!ty::type_needs_infer(ty));
+
+ // Fast-path for primitive types
+ let result = match ty.sty {
+ TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) |
+ TyBox(..) | TyRawPtr(..) | TyRef(..) | TyBareFn(..) |
+ TyArray(..) | TyTuple(..) | TyClosure(..) => Some(true),
+
+ TyStr | TyTrait(..) | TySlice(_) => Some(false),
+
+ TyEnum(..) | TyStruct(..) | TyProjection(..) | TyParam(..) |
+ TyInfer(..) | TyError => None
+ }.unwrap_or_else(|| type_impls_bound(param_env, tcx, ty, ty::BoundSized, span));
+
+ if !type_has_params(ty) && !type_has_self(ty) {
+ ty.flags.set(ty.flags.get() | if result {
+ TypeFlags::SIZEDNESS_CACHED | TypeFlags::IS_SIZED
+ } else {
+ TypeFlags::SIZEDNESS_CACHED
+ });
+ }
+
+ result
}
pub fn is_ffi_safe<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
fn type_requires<'tcx>(cx: &ctxt<'tcx>, seen: &mut Vec<DefId>,
r_ty: Ty<'tcx>, ty: Ty<'tcx>) -> bool {
debug!("type_requires({:?}, {:?})?",
- ::util::ppaux::ty_to_string(cx, r_ty),
- ::util::ppaux::ty_to_string(cx, ty));
+ r_ty, ty);
let r = r_ty == ty || subtypes_require(cx, seen, r_ty, ty);
debug!("type_requires({:?}, {:?})? {:?}",
- ::util::ppaux::ty_to_string(cx, r_ty),
- ::util::ppaux::ty_to_string(cx, ty),
- r);
+ r_ty, ty, r);
return r;
}
fn subtypes_require<'tcx>(cx: &ctxt<'tcx>, seen: &mut Vec<DefId>,
r_ty: Ty<'tcx>, ty: Ty<'tcx>) -> bool {
debug!("subtypes_require({:?}, {:?})?",
- ::util::ppaux::ty_to_string(cx, r_ty),
- ::util::ppaux::ty_to_string(cx, ty));
+ r_ty, ty);
let r = match ty.sty {
// fixed length vectors need special treatment compared to
// normal vectors, since they don't necessarily have the
// possibility to have length zero.
- ty_vec(_, Some(0)) => false, // don't need no contents
- ty_vec(ty, Some(_)) => type_requires(cx, seen, r_ty, ty),
-
- ty_bool |
- ty_char |
- ty_int(_) |
- ty_uint(_) |
- ty_float(_) |
- ty_str |
- ty_bare_fn(..) |
- ty_param(_) |
- ty_projection(_) |
- ty_vec(_, None) => {
+ TyArray(_, 0) => false, // don't need no contents
+ TyArray(ty, _) => type_requires(cx, seen, r_ty, ty),
+
+ TyBool |
+ TyChar |
+ TyInt(_) |
+ TyUint(_) |
+ TyFloat(_) |
+ TyStr |
+ TyBareFn(..) |
+ TyParam(_) |
+ TyProjection(_) |
+ TySlice(_) => {
false
}
- ty_uniq(typ) => {
+ TyBox(typ) => {
type_requires(cx, seen, r_ty, typ)
}
- ty_rptr(_, ref mt) => {
+ TyRef(_, ref mt) => {
type_requires(cx, seen, r_ty, mt.ty)
}
- ty_ptr(..) => {
+ TyRawPtr(..) => {
false // unsafe ptrs can always be NULL
}
- ty_trait(..) => {
+ TyTrait(..) => {
false
}
- ty_struct(ref did, _) if seen.contains(did) => {
+ TyStruct(ref did, _) if seen.contains(did) => {
false
}
- ty_struct(did, substs) => {
+ TyStruct(did, substs) => {
seen.push(did);
let fields = struct_fields(cx, did, substs);
let r = fields.iter().any(|f| type_requires(cx, seen, r_ty, f.mt.ty));
r
}
- ty_err |
- ty_infer(_) |
- ty_closure(..) => {
+ TyError |
+ TyInfer(_) |
+ TyClosure(..) => {
// this check is run on type definitions, so we don't expect to see
// inference by-products or closure types
cx.sess.bug(&format!("requires check invoked on inapplicable type: {:?}", ty))
}
- ty_tup(ref ts) => {
+ TyTuple(ref ts) => {
ts.iter().any(|ty| type_requires(cx, seen, r_ty, *ty))
}
- ty_enum(ref did, _) if seen.contains(did) => {
+ TyEnum(ref did, _) if seen.contains(did) => {
false
}
- ty_enum(did, substs) => {
+ TyEnum(did, substs) => {
seen.push(did);
let vs = enum_variants(cx, did);
let r = !vs.is_empty() && vs.iter().all(|variant| {
};
debug!("subtypes_require({:?}, {:?})? {:?}",
- ::util::ppaux::ty_to_string(cx, r_ty),
- ::util::ppaux::ty_to_string(cx, ty),
- r);
+ r_ty, ty, r);
return r;
}
seen: &mut Vec<Ty<'tcx>>, ty: Ty<'tcx>)
-> Representability {
match ty.sty {
- ty_tup(ref ts) => {
+ TyTuple(ref ts) => {
find_nonrepresentable(cx, sp, seen, ts.iter().cloned())
}
// Fixed-length vectors.
// FIXME(#11924) Behavior undecided for zero-length vectors.
- ty_vec(ty, Some(_)) => {
+ TyArray(ty, _) => {
is_type_structurally_recursive(cx, sp, seen, ty)
}
- ty_struct(did, substs) => {
+ TyStruct(did, substs) => {
let fields = struct_fields(cx, did, substs);
find_nonrepresentable(cx, sp, seen, fields.iter().map(|f| f.mt.ty))
}
- ty_enum(did, substs) => {
+ TyEnum(did, substs) => {
let vs = enum_variants(cx, did);
let iter = vs.iter()
- .flat_map(|variant| { variant.args.iter() })
+ .flat_map(|variant| &variant.args)
.map(|aty| { aty.subst_spanned(cx, substs, Some(sp)) });
find_nonrepresentable(cx, sp, seen, iter)
}
- ty_closure(..) => {
+ TyClosure(..) => {
// this check is run on type definitions, so we don't expect
// to see closure types
cx.sess.bug(&format!("requires check invoked on inapplicable type: {:?}", ty))
fn same_struct_or_enum_def_id(ty: Ty, did: DefId) -> bool {
match ty.sty {
- ty_struct(ty_did, _) | ty_enum(ty_did, _) => {
+ TyStruct(ty_did, _) | TyEnum(ty_did, _) => {
ty_did == did
}
_ => false
fn same_type<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
match (&a.sty, &b.sty) {
- (&ty_struct(did_a, ref substs_a), &ty_struct(did_b, ref substs_b)) |
- (&ty_enum(did_a, ref substs_a), &ty_enum(did_b, ref substs_b)) => {
+ (&TyStruct(did_a, ref substs_a), &TyStruct(did_b, ref substs_b)) |
+ (&TyEnum(did_a, ref substs_a), &TyEnum(did_b, ref substs_b)) => {
if did_a != did_b {
return false;
}
let types_a = substs_a.types.get_slice(subst::TypeSpace);
let types_b = substs_b.types.get_slice(subst::TypeSpace);
- let mut pairs = types_a.iter().zip(types_b.iter());
+ let mut pairs = types_a.iter().zip(types_b);
pairs.all(|(&a, &b)| same_type(a, b))
}
fn is_type_structurally_recursive<'tcx>(cx: &ctxt<'tcx>, sp: Span,
seen: &mut Vec<Ty<'tcx>>,
ty: Ty<'tcx>) -> Representability {
- debug!("is_type_structurally_recursive: {:?}",
- ::util::ppaux::ty_to_string(cx, ty));
+ debug!("is_type_structurally_recursive: {:?}", ty);
match ty.sty {
- ty_struct(did, _) | ty_enum(did, _) => {
+ TyStruct(did, _) | TyEnum(did, _) => {
{
// Iterate through stack of previously seen types.
let mut iter = seen.iter();
Some(&seen_type) => {
if same_struct_or_enum_def_id(seen_type, did) {
debug!("SelfRecursive: {:?} contains {:?}",
- ::util::ppaux::ty_to_string(cx, seen_type),
- ::util::ppaux::ty_to_string(cx, ty));
+ seen_type,
+ ty);
return SelfRecursive;
}
}
for &seen_type in iter {
if same_type(ty, seen_type) {
debug!("ContainsRecursive: {:?} contains {:?}",
- ::util::ppaux::ty_to_string(cx, seen_type),
- ::util::ppaux::ty_to_string(cx, ty));
+ seen_type,
+ ty);
return ContainsRecursive;
}
}
}
}
- debug!("is_type_representable: {:?}",
- ::util::ppaux::ty_to_string(cx, ty));
+ debug!("is_type_representable: {:?}", ty);
// To avoid a stack overflow when checking an enum variant or struct that
// contains a different, structurally recursive type, maintain a stack
// of seen types and check recursion for each of them (issues #3008, #3779).
let mut seen: Vec<Ty> = Vec::new();
let r = is_type_structurally_recursive(cx, sp, &mut seen, ty);
- debug!("is_type_representable: {:?} is {:?}",
- ::util::ppaux::ty_to_string(cx, ty), r);
+ debug!("is_type_representable: {:?} is {:?}", ty, r);
r
}
pub fn type_is_trait(ty: Ty) -> bool {
- type_trait_info(ty).is_some()
-}
-
-pub fn type_trait_info<'tcx>(ty: Ty<'tcx>) -> Option<&'tcx TyTrait<'tcx>> {
match ty.sty {
- ty_uniq(ty) | ty_rptr(_, mt { ty, ..}) | ty_ptr(mt { ty, ..}) => match ty.sty {
- ty_trait(ref t) => Some(&**t),
- _ => None
- },
- ty_trait(ref t) => Some(&**t),
- _ => None
+ TyTrait(..) => true,
+ _ => false
}
}
pub fn type_is_integral(ty: Ty) -> bool {
match ty.sty {
- ty_infer(IntVar(_)) | ty_int(_) | ty_uint(_) => true,
+ TyInfer(IntVar(_)) | TyInt(_) | TyUint(_) => true,
_ => false
}
}
pub fn type_is_fresh(ty: Ty) -> bool {
match ty.sty {
- ty_infer(FreshTy(_)) => true,
- ty_infer(FreshIntTy(_)) => true,
- ty_infer(FreshFloatTy(_)) => true,
+ TyInfer(FreshTy(_)) => true,
+ TyInfer(FreshIntTy(_)) => true,
+ TyInfer(FreshFloatTy(_)) => true,
_ => false
}
}
pub fn type_is_uint(ty: Ty) -> bool {
match ty.sty {
- ty_infer(IntVar(_)) | ty_uint(ast::TyUs) => true,
+ TyInfer(IntVar(_)) | TyUint(ast::TyUs) => true,
_ => false
}
}
pub fn type_is_char(ty: Ty) -> bool {
match ty.sty {
- ty_char => true,
+ TyChar => true,
_ => false
}
}
pub fn type_is_bare_fn(ty: Ty) -> bool {
match ty.sty {
- ty_bare_fn(..) => true,
+ TyBareFn(..) => true,
_ => false
}
}
pub fn type_is_bare_fn_item(ty: Ty) -> bool {
match ty.sty {
- ty_bare_fn(Some(_), _) => true,
+ TyBareFn(Some(_), _) => true,
_ => false
}
}
pub fn type_is_fp(ty: Ty) -> bool {
match ty.sty {
- ty_infer(FloatVar(_)) | ty_float(_) => true,
+ TyInfer(FloatVar(_)) | TyFloat(_) => true,
_ => false
}
}
pub fn type_is_signed(ty: Ty) -> bool {
match ty.sty {
- ty_int(_) => true,
+ TyInt(_) => true,
_ => false
}
}
pub fn type_is_machine(ty: Ty) -> bool {
match ty.sty {
- ty_int(ast::TyIs) | ty_uint(ast::TyUs) => false,
- ty_int(..) | ty_uint(..) | ty_float(..) => true,
+ TyInt(ast::TyIs) | TyUint(ast::TyUs) => false,
+ TyInt(..) | TyUint(..) | TyFloat(..) => true,
_ => false
}
}
// constructors
pub fn type_is_c_like_enum(cx: &ctxt, ty: Ty) -> bool {
match ty.sty {
- ty_enum(did, _) => {
+ TyEnum(did, _) => {
let variants = enum_variants(cx, did);
if variants.is_empty() {
false
// Some types---notably unsafe ptrs---can only be dereferenced explicitly.
pub fn deref<'tcx>(ty: Ty<'tcx>, explicit: bool) -> Option<mt<'tcx>> {
match ty.sty {
- ty_uniq(ty) => {
+ TyBox(ty) => {
Some(mt {
ty: ty,
mutbl: ast::MutImmutable,
})
},
- ty_rptr(_, mt) => Some(mt),
- ty_ptr(mt) if explicit => Some(mt),
+ TyRef(_, mt) => Some(mt),
+ TyRawPtr(mt) if explicit => Some(mt),
_ => None
}
}
pub fn type_content<'tcx>(ty: Ty<'tcx>) -> Ty<'tcx> {
match ty.sty {
- ty_uniq(ty) => ty,
- ty_rptr(_, mt) | ty_ptr(mt) => mt.ty,
+ TyBox(ty) => ty,
+ TyRef(_, mt) | TyRawPtr(mt) => mt.ty,
_ => ty
}
}
// Returns the type of ty[i]
pub fn index<'tcx>(ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
match ty.sty {
- ty_vec(ty, _) => Some(ty),
+ TyArray(ty, _) | TySlice(ty) => Some(ty),
_ => None
}
}
// which can't actually be indexed.
pub fn array_element_ty<'tcx>(tcx: &ctxt<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
match ty.sty {
- ty_vec(ty, _) => Some(ty),
- ty_str => Some(tcx.types.u8),
+ TyArray(ty, _) | TySlice(ty) => Some(ty),
+ TyStr => Some(tcx.types.u8),
_ => None
}
}
variant: Option<ast::DefId>) -> Option<Ty<'tcx>> {
match (&ty.sty, variant) {
- (&ty_tup(ref v), None) => v.get(i).cloned(),
+ (&TyTuple(ref v), None) => v.get(i).cloned(),
- (&ty_struct(def_id, substs), None) => lookup_struct_fields(cx, def_id)
+ (&TyStruct(def_id, substs), None) => lookup_struct_fields(cx, def_id)
.get(i)
.map(|&t|lookup_item_type(cx, t.id).ty.subst(cx, substs)),
- (&ty_enum(def_id, substs), Some(variant_def_id)) => {
+ (&TyEnum(def_id, substs), Some(variant_def_id)) => {
let variant_info = enum_variant_with_id(cx, def_id, variant_def_id);
variant_info.args.get(i).map(|t|t.subst(cx, substs))
}
- (&ty_enum(def_id, substs), None) => {
+ (&TyEnum(def_id, substs), None) => {
assert!(enum_is_univariant(cx, def_id));
let enum_variants = enum_variants(cx, def_id);
let variant_info = &(*enum_variants)[0];
variant: Option<ast::DefId>) -> Option<Ty<'tcx>> {
match (&ty.sty, variant) {
- (&ty_struct(def_id, substs), None) => {
+ (&TyStruct(def_id, substs), None) => {
let r = lookup_struct_fields(cx, def_id);
r.iter().find(|f| f.name == n)
.map(|&f| lookup_field_type(cx, def_id, f.id, substs))
}
- (&ty_enum(def_id, substs), Some(variant_def_id)) => {
+ (&TyEnum(def_id, substs), Some(variant_def_id)) => {
let variant_info = enum_variant_with_id(cx, def_id, variant_def_id);
variant_info.arg_names.as_ref()
.expect("must have struct enum variant if accessing a named fields")
- .iter().zip(variant_info.args.iter())
+ .iter().zip(&variant_info.args)
.find(|&(&name, _)| name == n)
.map(|(_name, arg_t)| arg_t.subst(cx, substs))
}
}
}
-pub fn impl_id_to_trait_ref<'tcx>(cx: &ctxt<'tcx>, id: ast::NodeId)
- -> ty::TraitRef<'tcx> {
- match cx.impl_trait_refs.borrow().get(&id) {
- Some(ty) => *ty,
- None => cx.sess.bug(
- &format!("impl_id_to_trait_ref: no trait ref for impl `{}`",
- cx.map.node_to_string(id)))
- }
-}
-
pub fn node_id_to_type<'tcx>(cx: &ctxt<'tcx>, id: ast::NodeId) -> Ty<'tcx> {
match node_id_to_type_opt(cx, id) {
Some(ty) => ty,
pub fn fn_is_variadic(fty: Ty) -> bool {
match fty.sty {
- ty_bare_fn(_, ref f) => f.sig.0.variadic,
+ TyBareFn(_, ref f) => f.sig.0.variadic,
ref s => {
panic!("fn_is_variadic() called on non-fn type: {:?}", s)
}
pub fn ty_fn_sig<'tcx>(fty: Ty<'tcx>) -> &'tcx PolyFnSig<'tcx> {
match fty.sty {
- ty_bare_fn(_, ref f) => &f.sig,
+ TyBareFn(_, ref f) => &f.sig,
ref s => {
panic!("ty_fn_sig() called on non-fn type: {:?}", s)
}
/// Returns the ABI of the given function.
pub fn ty_fn_abi(fty: Ty) -> abi::Abi {
match fty.sty {
- ty_bare_fn(_, ref f) => f.abi,
+ TyBareFn(_, ref f) => f.abi,
_ => panic!("ty_fn_abi() called on non-fn type"),
}
}
pub fn ty_fn_ret<'tcx>(fty: Ty<'tcx>) -> Binder<FnOutput<'tcx>> {
match fty.sty {
- ty_bare_fn(_, ref f) => f.sig.output(),
+ TyBareFn(_, ref f) => f.sig.output(),
ref s => {
panic!("ty_fn_ret() called on non-fn type: {:?}", s)
}
pub fn is_fn_ty(fty: Ty) -> bool {
match fty.sty {
- ty_bare_fn(..) => true,
+ TyBareFn(..) => true,
_ => false
}
}
span: Span,
ty: Ty) -> Region {
match ty.sty {
- ty_rptr(r, _) => *r,
+ TyRef(r, _) => *r,
ref s => {
tcx.sess.span_bug(
span,
-> Ty<'tcx> where
F: FnMut(MethodCall) -> Option<Ty<'tcx>>,
{
- if let ty_err = unadjusted_ty.sty {
+ if let TyError = unadjusted_ty.sty {
return unadjusted_ty;
}
match *adjustment {
AdjustReifyFnPointer => {
match unadjusted_ty.sty {
- ty::ty_bare_fn(Some(_), b) => {
+ ty::TyBareFn(Some(_), b) => {
ty::mk_bare_fn(cx, None, b)
}
_ => {
cx.sess.bug(
&format!("AdjustReifyFnPointer adjustment on non-fn-item: \
- {}", unadjusted_ty.repr(cx)));
+ {:?}", unadjusted_ty));
}
}
}
AdjustUnsafeFnPointer => {
match unadjusted_ty.sty {
- ty::ty_bare_fn(None, b) => cx.safe_to_unsafe_fn_ty(b),
+ ty::TyBareFn(None, b) => cx.safe_to_unsafe_fn_ty(b),
ref b => {
cx.sess.bug(
&format!("AdjustReifyFnPointer adjustment on non-fn-item: \
span,
&format!("the {}th autoderef failed: {}",
i,
- ty_to_string(cx, adjusted_ty))
+ adjusted_ty)
);
}
}
}
}
-pub fn expr_is_lval(tcx: &ctxt, e: &ast::Expr) -> bool {
- match expr_kind(tcx, e) {
- LvalueExpr => true,
- RvalueDpsExpr | RvalueDatumExpr | RvalueStmtExpr => false
- }
-}
-
-/// We categorize expressions into three kinds. The distinction between
-/// lvalue/rvalue is fundamental to the language. The distinction between the
-/// two kinds of rvalues is an artifact of trans which reflects how we will
-/// generate code for that kind of expression. See trans/expr.rs for more
-/// information.
-#[derive(Copy, Clone)]
-pub enum ExprKind {
- LvalueExpr,
- RvalueDpsExpr,
- RvalueDatumExpr,
- RvalueStmtExpr
-}
-
-pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind {
- if tcx.method_map.borrow().contains_key(&MethodCall::expr(expr.id)) {
- // Overloaded operations are generally calls, and hence they are
- // generated via DPS, but there are a few exceptions:
- return match expr.node {
- // `a += b` has a unit result.
- ast::ExprAssignOp(..) => RvalueStmtExpr,
-
- // the deref method invoked for `*a` always yields an `&T`
- ast::ExprUnary(ast::UnDeref, _) => LvalueExpr,
-
- // the index method invoked for `a[i]` always yields an `&T`
- ast::ExprIndex(..) => LvalueExpr,
-
- // in the general case, result could be any type, use DPS
- _ => RvalueDpsExpr
- };
- }
-
- match expr.node {
+pub fn expr_is_lval(tcx: &ctxt, expr: &ast::Expr) -> bool {
+ match expr.node {
ast::ExprPath(..) => {
- match resolve_expr(tcx, expr) {
- def::DefVariant(tid, vid, _) => {
- let variant_info = enum_variant_with_id(tcx, tid, vid);
- if !variant_info.args.is_empty() {
- // N-ary variant.
- RvalueDatumExpr
- } else {
- // Nullary variant.
- RvalueDpsExpr
- }
+ // We can't use resolve_expr here, as this needs to run on broken
+ // programs. We don't need to through - associated items are all
+ // rvalues.
+ match tcx.def_map.borrow().get(&expr.id) {
+ Some(&def::PathResolution {
+ base_def: def::DefStatic(..), ..
+ }) | Some(&def::PathResolution {
+ base_def: def::DefUpvar(..), ..
+ }) | Some(&def::PathResolution {
+ base_def: def::DefLocal(..), ..
+ }) => {
+ true
}
- def::DefStruct(_) => {
- match tcx.node_types.borrow().get(&expr.id) {
- Some(ty) => match ty.sty {
- ty_bare_fn(..) => RvalueDatumExpr,
- _ => RvalueDpsExpr
- },
- // See ExprCast below for why types might be missing.
- None => RvalueDatumExpr
- }
- }
+ Some(..) => false,
- // Special case: A unit like struct's constructor must be called without () at the
- // end (like `UnitStruct`) which means this is an ExprPath to a DefFn. But in case
- // of unit structs this is should not be interpreted as function pointer but as
- // call to the constructor.
- def::DefFn(_, true) => RvalueDpsExpr,
-
- // Fn pointers are just scalar values.
- def::DefFn(..) | def::DefMethod(..) => RvalueDatumExpr,
-
- // Note: there is actually a good case to be made that
- // DefArg's, particularly those of immediate type, ought to
- // considered rvalues.
- def::DefStatic(..) |
- def::DefUpvar(..) |
- def::DefLocal(..) => LvalueExpr,
-
- def::DefConst(..) |
- def::DefAssociatedConst(..) => RvalueDatumExpr,
-
- def => {
- tcx.sess.span_bug(
- expr.span,
- &format!("uncategorized def for expr {}: {:?}",
- expr.id,
- def));
- }
+ None => tcx.sess.span_bug(expr.span, &format!(
+ "no def for path {}", expr.id))
}
}
ast::ExprField(..) |
ast::ExprTupField(..) |
ast::ExprIndex(..) => {
- LvalueExpr
+ true
}
ast::ExprCall(..) |
ast::ExprClosure(..) |
ast::ExprBlock(..) |
ast::ExprRepeat(..) |
- ast::ExprVec(..) => {
- RvalueDpsExpr
- }
-
- ast::ExprIfLet(..) => {
- tcx.sess.span_bug(expr.span, "non-desugared ExprIfLet");
- }
- ast::ExprWhileLet(..) => {
- tcx.sess.span_bug(expr.span, "non-desugared ExprWhileLet");
- }
-
- ast::ExprForLoop(..) => {
- tcx.sess.span_bug(expr.span, "non-desugared ExprForLoop");
- }
-
- ast::ExprLit(ref lit) if lit_is_str(&**lit) => {
- RvalueDpsExpr
- }
-
+ ast::ExprVec(..) |
ast::ExprBreak(..) |
ast::ExprAgain(..) |
ast::ExprRet(..) |
ast::ExprLoop(..) |
ast::ExprAssign(..) |
ast::ExprInlineAsm(..) |
- ast::ExprAssignOp(..) => {
- RvalueStmtExpr
- }
-
- ast::ExprLit(_) | // Note: LitStr is carved out above
+ ast::ExprAssignOp(..) |
+ ast::ExprLit(_) |
ast::ExprUnary(..) |
- ast::ExprBox(None, _) |
+ ast::ExprBox(..) |
ast::ExprAddrOf(..) |
ast::ExprBinary(..) |
ast::ExprCast(..) => {
- RvalueDatumExpr
- }
-
- ast::ExprBox(Some(ref place), _) => {
- // Special case `Box<T>` for now:
- let def_id = match tcx.def_map.borrow().get(&place.id) {
- Some(def) => def.def_id(),
- None => panic!("no def for place"),
- };
- if tcx.lang_items.exchange_heap() == Some(def_id) {
- RvalueDatumExpr
- } else {
- RvalueDpsExpr
- }
+ false
}
- ast::ExprParen(ref e) => expr_kind(tcx, &**e),
+ ast::ExprParen(ref e) => expr_is_lval(tcx, e),
+ ast::ExprIfLet(..) |
+ ast::ExprWhileLet(..) |
+ ast::ExprForLoop(..) |
ast::ExprMac(..) => {
tcx.sess.span_bug(
expr.span,
trait_items.iter().position(|m| m.name() == id)
}
-pub fn ty_sort_string<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> String {
+pub fn ty_sort_string(cx: &ctxt, ty: Ty) -> String {
match ty.sty {
- ty_bool | ty_char | ty_int(_) |
- ty_uint(_) | ty_float(_) | ty_str => {
- ::util::ppaux::ty_to_string(cx, ty)
- }
- ty_tup(ref tys) if tys.is_empty() => ::util::ppaux::ty_to_string(cx, ty),
-
- ty_enum(id, _) => format!("enum `{}`", item_path_str(cx, id)),
- ty_uniq(_) => "box".to_string(),
- ty_vec(_, Some(n)) => format!("array of {} elements", n),
- ty_vec(_, None) => "slice".to_string(),
- ty_ptr(_) => "*-ptr".to_string(),
- ty_rptr(_, _) => "&-ptr".to_string(),
- ty_bare_fn(Some(_), _) => format!("fn item"),
- ty_bare_fn(None, _) => "fn pointer".to_string(),
- ty_trait(ref inner) => {
+ TyBool | TyChar | TyInt(_) |
+ TyUint(_) | TyFloat(_) | TyStr => ty.to_string(),
+ TyTuple(ref tys) if tys.is_empty() => ty.to_string(),
+
+ TyEnum(id, _) => format!("enum `{}`", item_path_str(cx, id)),
+ TyBox(_) => "box".to_string(),
+ TyArray(_, n) => format!("array of {} elements", n),
+ TySlice(_) => "slice".to_string(),
+ TyRawPtr(_) => "*-ptr".to_string(),
+ TyRef(_, _) => "&-ptr".to_string(),
+ TyBareFn(Some(_), _) => format!("fn item"),
+ TyBareFn(None, _) => "fn pointer".to_string(),
+ TyTrait(ref inner) => {
format!("trait {}", item_path_str(cx, inner.principal_def_id()))
}
- ty_struct(id, _) => {
+ TyStruct(id, _) => {
format!("struct `{}`", item_path_str(cx, id))
}
- ty_closure(..) => "closure".to_string(),
- ty_tup(_) => "tuple".to_string(),
- ty_infer(TyVar(_)) => "inferred type".to_string(),
- ty_infer(IntVar(_)) => "integral variable".to_string(),
- ty_infer(FloatVar(_)) => "floating-point variable".to_string(),
- ty_infer(FreshTy(_)) => "skolemized type".to_string(),
- ty_infer(FreshIntTy(_)) => "skolemized integral type".to_string(),
- ty_infer(FreshFloatTy(_)) => "skolemized floating-point type".to_string(),
- ty_projection(_) => "associated type".to_string(),
- ty_param(ref p) => {
+ TyClosure(..) => "closure".to_string(),
+ TyTuple(_) => "tuple".to_string(),
+ TyInfer(TyVar(_)) => "inferred type".to_string(),
+ TyInfer(IntVar(_)) => "integral variable".to_string(),
+ TyInfer(FloatVar(_)) => "floating-point variable".to_string(),
+ TyInfer(FreshTy(_)) => "skolemized type".to_string(),
+ TyInfer(FreshIntTy(_)) => "skolemized integral type".to_string(),
+ TyInfer(FreshFloatTy(_)) => "skolemized floating-point type".to_string(),
+ TyProjection(_) => "associated type".to_string(),
+ TyParam(ref p) => {
if p.space == subst::SelfSpace {
"Self".to_string()
} else {
"type parameter".to_string()
}
}
- ty_err => "type error".to_string(),
- }
-}
-
-impl<'tcx> Repr<'tcx> for ty::type_err<'tcx> {
- fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
- ty::type_err_to_str(tcx, self)
+ TyError => "type error".to_string(),
}
}
/// in parentheses after some larger message. You should also invoke `note_and_explain_type_err()`
/// afterwards to present additional details, particularly when it comes to lifetime-related
/// errors.
-pub fn type_err_to_str<'tcx>(cx: &ctxt<'tcx>, err: &type_err<'tcx>) -> String {
- match *err {
- terr_cyclic_ty => "cyclic type of infinite size".to_string(),
- terr_mismatch => "types differ".to_string(),
- terr_unsafety_mismatch(values) => {
- format!("expected {} fn, found {} fn",
- values.expected,
- values.found)
- }
- terr_abi_mismatch(values) => {
- format!("expected {} fn, found {} fn",
- values.expected,
- values.found)
- }
- terr_mutability => "values differ in mutability".to_string(),
- terr_box_mutability => {
- "boxed values differ in mutability".to_string()
- }
- terr_vec_mutability => "vectors differ in mutability".to_string(),
- terr_ptr_mutability => "pointers differ in mutability".to_string(),
- terr_ref_mutability => "references differ in mutability".to_string(),
- terr_ty_param_size(values) => {
- format!("expected a type with {} type params, \
- found one with {} type params",
- values.expected,
- values.found)
- }
- terr_fixed_array_size(values) => {
- format!("expected an array with a fixed size of {} elements, \
- found one with {} elements",
- values.expected,
- values.found)
- }
- terr_tuple_size(values) => {
- format!("expected a tuple with {} elements, \
- found one with {} elements",
- values.expected,
- values.found)
- }
- terr_arg_count => {
- "incorrect number of function parameters".to_string()
- }
- terr_regions_does_not_outlive(..) => {
- "lifetime mismatch".to_string()
- }
- terr_regions_not_same(..) => {
- "lifetimes are not the same".to_string()
- }
- terr_regions_no_overlap(..) => {
- "lifetimes do not intersect".to_string()
- }
- terr_regions_insufficiently_polymorphic(br, _) => {
- format!("expected bound lifetime parameter {}, \
- found concrete lifetime",
- bound_region_ptr_to_string(cx, br))
- }
- terr_regions_overly_polymorphic(br, _) => {
- format!("expected concrete lifetime, \
- found bound lifetime parameter {}",
- bound_region_ptr_to_string(cx, br))
- }
- terr_sorts(values) => {
- // A naive approach to making sure that we're not reporting silly errors such as:
- // (expected closure, found closure).
- let expected_str = ty_sort_string(cx, values.expected);
- let found_str = ty_sort_string(cx, values.found);
- if expected_str == found_str {
- format!("expected {}, found a different {}", expected_str, found_str)
- } else {
- format!("expected {}, found {}", expected_str, found_str)
+impl<'tcx> fmt::Display for type_err<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ terr_cyclic_ty => write!(f, "cyclic type of infinite size"),
+ terr_mismatch => write!(f, "types differ"),
+ terr_unsafety_mismatch(values) => {
+ write!(f, "expected {} fn, found {} fn",
+ values.expected,
+ values.found)
+ }
+ terr_abi_mismatch(values) => {
+ write!(f, "expected {} fn, found {} fn",
+ values.expected,
+ values.found)
+ }
+ terr_mutability => write!(f, "values differ in mutability"),
+ terr_box_mutability => {
+ write!(f, "boxed values differ in mutability")
+ }
+ terr_vec_mutability => write!(f, "vectors differ in mutability"),
+ terr_ptr_mutability => write!(f, "pointers differ in mutability"),
+ terr_ref_mutability => write!(f, "references differ in mutability"),
+ terr_ty_param_size(values) => {
+ write!(f, "expected a type with {} type params, \
+ found one with {} type params",
+ values.expected,
+ values.found)
+ }
+ terr_fixed_array_size(values) => {
+ write!(f, "expected an array with a fixed size of {} elements, \
+ found one with {} elements",
+ values.expected,
+ values.found)
+ }
+ terr_tuple_size(values) => {
+ write!(f, "expected a tuple with {} elements, \
+ found one with {} elements",
+ values.expected,
+ values.found)
+ }
+ terr_arg_count => {
+ write!(f, "incorrect number of function parameters")
+ }
+ terr_regions_does_not_outlive(..) => {
+ write!(f, "lifetime mismatch")
+ }
+ terr_regions_not_same(..) => {
+ write!(f, "lifetimes are not the same")
+ }
+ terr_regions_no_overlap(..) => {
+ write!(f, "lifetimes do not intersect")
+ }
+ terr_regions_insufficiently_polymorphic(br, _) => {
+ write!(f, "expected bound lifetime parameter {}, \
+ found concrete lifetime", br)
+ }
+ terr_regions_overly_polymorphic(br, _) => {
+ write!(f, "expected concrete lifetime, \
+ found bound lifetime parameter {}", br)
+ }
+ terr_sorts(values) => tls::with(|tcx| {
+ // A naive approach to making sure that we're not reporting silly errors such as:
+ // (expected closure, found closure).
+ let expected_str = ty_sort_string(tcx, values.expected);
+ let found_str = ty_sort_string(tcx, values.found);
+ if expected_str == found_str {
+ write!(f, "expected {}, found a different {}", expected_str, found_str)
+ } else {
+ write!(f, "expected {}, found {}", expected_str, found_str)
+ }
+ }),
+ terr_traits(values) => tls::with(|tcx| {
+ write!(f, "expected trait `{}`, found trait `{}`",
+ item_path_str(tcx, values.expected),
+ item_path_str(tcx, values.found))
+ }),
+ terr_builtin_bounds(values) => {
+ if values.expected.is_empty() {
+ write!(f, "expected no bounds, found `{}`",
+ values.found)
+ } else if values.found.is_empty() {
+ write!(f, "expected bounds `{}`, found no bounds",
+ values.expected)
+ } else {
+ write!(f, "expected bounds `{}`, found bounds `{}`",
+ values.expected,
+ values.found)
+ }
}
- }
- terr_traits(values) => {
- format!("expected trait `{}`, found trait `{}`",
- item_path_str(cx, values.expected),
- item_path_str(cx, values.found))
- }
- terr_builtin_bounds(values) => {
- if values.expected.is_empty() {
- format!("expected no bounds, found `{}`",
- values.found.user_string(cx))
- } else if values.found.is_empty() {
- format!("expected bounds `{}`, found no bounds",
- values.expected.user_string(cx))
- } else {
- format!("expected bounds `{}`, found bounds `{}`",
- values.expected.user_string(cx),
- values.found.user_string(cx))
+ terr_integer_as_char => {
+ write!(f, "expected an integral type, found `char`")
+ }
+ terr_int_mismatch(ref values) => {
+ write!(f, "expected `{:?}`, found `{:?}`",
+ values.expected,
+ values.found)
+ }
+ terr_float_mismatch(ref values) => {
+ write!(f, "expected `{:?}`, found `{:?}`",
+ values.expected,
+ values.found)
+ }
+ terr_variadic_mismatch(ref values) => {
+ write!(f, "expected {} fn, found {} function",
+ if values.expected { "variadic" } else { "non-variadic" },
+ if values.found { "variadic" } else { "non-variadic" })
+ }
+ terr_convergence_mismatch(ref values) => {
+ write!(f, "expected {} fn, found {} function",
+ if values.expected { "converging" } else { "diverging" },
+ if values.found { "converging" } else { "diverging" })
+ }
+ terr_projection_name_mismatched(ref values) => {
+ write!(f, "expected {}, found {}",
+ values.expected,
+ values.found)
+ }
+ terr_projection_bounds_length(ref values) => {
+ write!(f, "expected {} associated type bindings, found {}",
+ values.expected,
+ values.found)
}
- }
- terr_integer_as_char => {
- "expected an integral type, found `char`".to_string()
- }
- terr_int_mismatch(ref values) => {
- format!("expected `{:?}`, found `{:?}`",
- values.expected,
- values.found)
- }
- terr_float_mismatch(ref values) => {
- format!("expected `{:?}`, found `{:?}`",
- values.expected,
- values.found)
- }
- terr_variadic_mismatch(ref values) => {
- format!("expected {} fn, found {} function",
- if values.expected { "variadic" } else { "non-variadic" },
- if values.found { "variadic" } else { "non-variadic" })
- }
- terr_convergence_mismatch(ref values) => {
- format!("expected {} fn, found {} function",
- if values.expected { "converging" } else { "diverging" },
- if values.found { "converging" } else { "diverging" })
- }
- terr_projection_name_mismatched(ref values) => {
- format!("expected {}, found {}",
- token::get_name(values.expected),
- token::get_name(values.found))
- }
- terr_projection_bounds_length(ref values) => {
- format!("expected {} associated type bindings, found {}",
- values.expected,
- values.found)
}
}
}
/// the future).
fn lookup_locally_or_in_crate_store<V, F>(descr: &str,
def_id: ast::DefId,
- map: &mut DefIdMap<V>,
+ map: &RefCell<DefIdMap<V>>,
load_external: F) -> V where
V: Clone,
F: FnOnce() -> V,
{
- match map.get(&def_id).cloned() {
+ match map.borrow().get(&def_id).cloned() {
Some(v) => { return v; }
None => { }
}
panic!("No def'n found for {:?} in tcx.{}", def_id, descr);
}
let v = load_external();
- map.insert(def_id, v.clone());
+ map.borrow_mut().insert(def_id, v.clone());
v
}
pub fn impl_or_trait_item<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId)
-> ImplOrTraitItem<'tcx> {
- lookup_locally_or_in_crate_store("impl_or_trait_items",
- id,
- &mut *cx.impl_or_trait_items
- .borrow_mut(),
- || {
- csearch::get_impl_or_trait_item(cx, id)
- })
-}
-
-/// Returns true if the given ID refers to an associated type and false if it
-/// refers to anything else.
-pub fn is_associated_type(cx: &ctxt, id: ast::DefId) -> bool {
- memoized(&cx.associated_types, id, |id: ast::DefId| {
- if id.krate == ast::LOCAL_CRATE {
- match cx.impl_or_trait_items.borrow().get(&id) {
- Some(ref item) => {
- match **item {
- TypeTraitItem(_) => true,
- _ => false,
- }
- }
- None => false,
- }
- } else {
- csearch::is_associated_type(&cx.sess.cstore, id)
- }
- })
+ lookup_locally_or_in_crate_store(
+ "impl_or_trait_items", id, &cx.impl_or_trait_items,
+ || csearch::get_impl_or_trait_item(cx, id))
}
/// Returns the parameter index that the given associated type corresponds to.
trait_def: &TraitDef,
associated_type_id: ast::DefId)
-> usize {
- for type_parameter_def in trait_def.generics.types.iter() {
+ for type_parameter_def in &trait_def.generics.types {
if type_parameter_def.def_id == associated_type_id {
return type_parameter_def.index as usize
}
pub fn trait_item_def_ids(cx: &ctxt, id: ast::DefId)
-> Rc<Vec<ImplOrTraitItemId>> {
- lookup_locally_or_in_crate_store("trait_item_def_ids",
- id,
- &mut *cx.trait_item_def_ids.borrow_mut(),
- || {
- Rc::new(csearch::get_trait_item_def_ids(&cx.sess.cstore, id))
- })
+ lookup_locally_or_in_crate_store(
+ "trait_item_def_ids", id, &cx.trait_item_def_ids,
+ || Rc::new(csearch::get_trait_item_def_ids(&cx.sess.cstore, id)))
}
+/// Returns the trait-ref corresponding to a given impl, or None if it is
+/// an inherent impl.
pub fn impl_trait_ref<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId)
- -> Option<TraitRef<'tcx>> {
- memoized(&cx.impl_trait_cache, id, |id: ast::DefId| {
- if id.krate == ast::LOCAL_CRATE {
- debug!("(impl_trait_ref) searching for trait impl {:?}", id);
- if let Some(ast_map::NodeItem(item)) = cx.map.find(id.node) {
- match item.node {
- ast::ItemImpl(_, _, _, Some(_), _, _) |
- ast::ItemDefaultImpl(..) => {
- Some(ty::impl_id_to_trait_ref(cx, id.node))
- }
- _ => None
- }
- } else {
- None
- }
+ -> Option<TraitRef<'tcx>>
+{
+ lookup_locally_or_in_crate_store(
+ "impl_trait_refs", id, &cx.impl_trait_refs,
+ || csearch::get_impl_trait(cx, id))
+}
+
+/// Returns whether this DefId refers to an impl
+pub fn is_impl<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId) -> bool {
+ if id.krate == ast::LOCAL_CRATE {
+ if let Some(ast_map::NodeItem(
+ &ast::Item { node: ast::ItemImpl(..), .. })) = cx.map.find(id.node) {
+ true
} else {
- csearch::get_impl_trait(cx, id)
+ false
}
- })
+ } else {
+ csearch::is_impl(&cx.sess.cstore, id)
+ }
}
pub fn trait_ref_to_def_id(tcx: &ctxt, tr: &ast::TraitRef) -> ast::DefId {
pub fn ty_to_def_id(ty: Ty) -> Option<ast::DefId> {
match ty.sty {
- ty_trait(ref tt) =>
+ TyTrait(ref tt) =>
Some(tt.principal_def_id()),
- ty_struct(id, _) |
- ty_enum(id, _) |
- ty_closure(id, _) =>
+ TyStruct(id, _) |
+ TyEnum(id, _) |
+ TyClosure(id, _) =>
Some(id),
_ =>
None
pub fn type_is_empty(cx: &ctxt, ty: Ty) -> bool {
match ty.sty {
- ty_enum(did, _) => (*enum_variants(cx, did)).is_empty(),
+ TyEnum(did, _) => (*enum_variants(cx, did)).is_empty(),
_ => false
}
}
let computed_value = repr_type.disr_wrap_incr(Some(prev_val));
let computed_value = repr_type.disr_string(computed_value);
let prev_val = repr_type.disr_string(prev_val);
- let repr_type = repr_type.to_ty(cx).user_string(cx);
+ let repr_type = repr_type.to_ty(cx);
span_err!(cx.sess, variant_span, E0370,
"enum discriminant overflowed on value after {}: {}; \
set explicitly via {} = {} if that is desired outcome",
// more robust (on case-by-case basis).
match const_eval::eval_const_expr_partial(cx, &**e, Some(repr_type_ty)) {
- Ok(const_eval::const_int(val)) => current_disr_val = val as Disr,
- Ok(const_eval::const_uint(val)) => current_disr_val = val as Disr,
+ Ok(ConstVal::Int(val)) => current_disr_val = val as Disr,
+ Ok(ConstVal::Uint(val)) => current_disr_val = val as Disr,
Ok(_) => {
let sign_desc = if repr_type.is_signed() { "signed" } else { "unsigned" };
span_err!(cx.sess, e.span, E0079,
did: ast::DefId)
-> TypeScheme<'tcx> {
lookup_locally_or_in_crate_store(
- "tcache", did, &mut *cx.tcache.borrow_mut(),
+ "tcache", did, &cx.tcache,
|| csearch::get_type(cx, did))
}
/// Given the did of a trait, returns its canonical trait ref.
pub fn lookup_trait_def<'tcx>(cx: &ctxt<'tcx>, did: ast::DefId)
-> &'tcx TraitDef<'tcx> {
- memoized(&cx.trait_defs, did, |did: DefId| {
- assert!(did.krate != ast::LOCAL_CRATE);
- cx.arenas.trait_defs.alloc(csearch::get_trait_def(cx, did))
- })
+ lookup_locally_or_in_crate_store(
+ "trait_defs", did, &cx.trait_defs,
+ || cx.arenas.trait_defs.alloc(csearch::get_trait_def(cx, did))
+ )
}
/// Given the did of an item, returns its full set of predicates.
pub fn lookup_predicates<'tcx>(cx: &ctxt<'tcx>, did: ast::DefId)
-> GenericPredicates<'tcx>
{
- memoized(&cx.predicates, did, |did: DefId| {
- assert!(did.krate != ast::LOCAL_CRATE);
- csearch::get_predicates(cx, did)
- })
+ lookup_locally_or_in_crate_store(
+ "predicates", did, &cx.predicates,
+ || csearch::get_predicates(cx, did))
}
/// Given the did of a trait, returns its superpredicates.
pub fn lookup_super_predicates<'tcx>(cx: &ctxt<'tcx>, did: ast::DefId)
-> GenericPredicates<'tcx>
{
- memoized(&cx.super_predicates, did, |did: DefId| {
- assert!(did.krate != ast::LOCAL_CRATE);
- csearch::get_super_predicates(cx, did)
- })
-}
-
-pub fn predicates<'tcx>(
- tcx: &ctxt<'tcx>,
- param_ty: Ty<'tcx>,
- bounds: &ParamBounds<'tcx>)
- -> Vec<Predicate<'tcx>>
-{
- let mut vec = Vec::new();
-
- for builtin_bound in &bounds.builtin_bounds {
- match traits::trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty) {
- Ok(trait_ref) => { vec.push(trait_ref.as_predicate()); }
- Err(ErrorReported) => { }
- }
- }
-
- for ®ion_bound in &bounds.region_bounds {
- // account for the binder being introduced below; no need to shift `param_ty`
- // because, at present at least, it can only refer to early-bound regions
- let region_bound = ty_fold::shift_region(region_bound, 1);
- vec.push(ty::Binder(ty::OutlivesPredicate(param_ty, region_bound)).as_predicate());
- }
-
- for bound_trait_ref in &bounds.trait_bounds {
- vec.push(bound_trait_ref.as_predicate());
- }
-
- for projection in &bounds.projection_bounds {
- vec.push(projection.as_predicate());
- }
-
- vec
+ lookup_locally_or_in_crate_store(
+ "super_predicates", did, &cx.super_predicates,
+ || csearch::get_super_predicates(cx, did))
}
/// Get the attributes of a definition.
/// if not a structure at all. Corresponds to the only possible unsized
/// field, and its type can be used to determine unsizing strategy.
pub fn struct_tail<'tcx>(cx: &ctxt<'tcx>, mut ty: Ty<'tcx>) -> Ty<'tcx> {
- while let ty_struct(def_id, substs) = ty.sty {
+ while let TyStruct(def_id, substs) = ty.sty {
match struct_fields(cx, def_id, substs).last() {
Some(f) => ty = f.mt.ty,
None => break
target: Ty<'tcx>)
-> (Ty<'tcx>, Ty<'tcx>) {
let (mut a, mut b) = (source, target);
- while let (&ty_struct(a_did, a_substs), &ty_struct(b_did, b_substs)) = (&a.sty, &b.sty) {
+ while let (&TyStruct(a_did, a_substs), &TyStruct(b_did, b_substs)) = (&a.sty, &b.sty) {
if a_did != b_did {
continue;
}
match const_eval::eval_const_expr_partial(tcx, count_expr, Some(tcx.types.usize)) {
Ok(val) => {
let found = match val {
- const_eval::const_uint(count) => return count as usize,
- const_eval::const_int(count) if count >= 0 => return count as usize,
- const_eval::const_int(_) => "negative integer",
- const_eval::const_float(_) => "float",
- const_eval::const_str(_) => "string",
- const_eval::const_bool(_) => "boolean",
- const_eval::const_binary(_) => "binary array",
- const_eval::Struct(..) => "struct",
- const_eval::Tuple(_) => "tuple"
+ ConstVal::Uint(count) => return count as usize,
+ ConstVal::Int(count) if count >= 0 => return count as usize,
+ ConstVal::Int(_) => "negative integer",
+ ConstVal::Float(_) => "float",
+ ConstVal::Str(_) => "string",
+ ConstVal::Bool(_) => "boolean",
+ ConstVal::Binary(_) => "binary array",
+ ConstVal::Struct(..) => "struct",
+ ConstVal::Tuple(_) => "tuple"
};
span_err!(tcx.sess, count_expr.span, E0306,
"expected positive integer for repeat count, found {}",
-> Vec<ty::Region>
{
debug!("required_region_bounds(erased_self_ty={:?}, predicates={:?})",
- erased_self_ty.repr(tcx),
- predicates.repr(tcx));
+ erased_self_ty,
+ predicates);
assert!(!erased_self_ty.has_escaping_regions());
pub fn item_variances(tcx: &ctxt, item_id: ast::DefId) -> Rc<ItemVariances> {
lookup_locally_or_in_crate_store(
- "item_variance_map", item_id, &mut *tcx.item_variance_map.borrow_mut(),
+ "item_variance_map", item_id, &tcx.item_variance_map,
|| Rc::new(csearch::get_item_variances(&tcx.sess.cstore, item_id)))
}
return;
}
- debug!("populate_implementations_for_trait_if_necessary: searching for {}", def.repr(tcx));
+ debug!("populate_implementations_for_trait_if_necessary: searching for {:?}", def);
if csearch::is_defaulted_trait(&tcx.sess.cstore, trait_id) {
record_trait_has_default_impl(tcx, trait_id);
};
maybe_walk_ty(ty, |ty| {
match ty.sty {
- ty_bool => byte!(2),
- ty_char => byte!(3),
- ty_int(i) => {
+ TyBool => byte!(2),
+ TyChar => byte!(3),
+ TyInt(i) => {
byte!(4);
hash!(i);
}
- ty_uint(u) => {
+ TyUint(u) => {
byte!(5);
hash!(u);
}
- ty_float(f) => {
+ TyFloat(f) => {
byte!(6);
hash!(f);
}
- ty_str => {
+ TyStr => {
byte!(7);
}
- ty_enum(d, _) => {
+ TyEnum(d, _) => {
byte!(8);
did(state, d);
}
- ty_uniq(_) => {
+ TyBox(_) => {
byte!(9);
}
- ty_vec(_, Some(n)) => {
+ TyArray(_, n) => {
byte!(10);
n.hash(state);
}
- ty_vec(_, None) => {
+ TySlice(_) => {
byte!(11);
}
- ty_ptr(m) => {
+ TyRawPtr(m) => {
byte!(12);
mt(state, m);
}
- ty_rptr(r, m) => {
+ TyRef(r, m) => {
byte!(13);
region(state, *r);
mt(state, m);
}
- ty_bare_fn(opt_def_id, ref b) => {
+ TyBareFn(opt_def_id, ref b) => {
byte!(14);
hash!(opt_def_id);
hash!(b.unsafety);
fn_sig(state, &b.sig);
return false;
}
- ty_trait(ref data) => {
+ TyTrait(ref data) => {
byte!(17);
did(state, data.principal_def_id());
hash!(data.bounds);
let principal = anonymize_late_bound_regions(tcx, &data.principal).0;
- for subty in principal.substs.types.iter() {
- helper(tcx, *subty, svh, state);
+ for subty in &principal.substs.types {
+ helper(tcx, subty, svh, state);
}
return false;
}
- ty_struct(d, _) => {
+ TyStruct(d, _) => {
byte!(18);
did(state, d);
}
- ty_tup(ref inner) => {
+ TyTuple(ref inner) => {
byte!(19);
hash!(inner.len());
}
- ty_param(p) => {
+ TyParam(p) => {
byte!(20);
hash!(p.space);
hash!(p.idx);
hash!(token::get_name(p.name));
}
- ty_infer(_) => unreachable!(),
- ty_err => byte!(21),
- ty_closure(d, _) => {
+ TyInfer(_) => unreachable!(),
+ TyError => byte!(21),
+ TyClosure(d, _) => {
byte!(22);
did(state, d);
}
- ty_projection(ref data) => {
+ TyProjection(ref data) => {
byte!(23);
did(state, data.trait_ref.def_id);
hash!(token::get_name(data.item_name));
}
}
-impl Variance {
- pub fn to_string(self) -> &'static str {
- match self {
+impl fmt::Debug for Variance {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.write_str(match *self {
Covariant => "+",
Contravariant => "-",
Invariant => "o",
Bivariant => "*",
- }
+ })
}
}
defs: &[TypeParameterDef<'tcx>]) {
for def in defs {
debug!("construct_parameter_environment(): push_types_from_defs: def={:?}",
- def.repr(tcx));
+ def);
let ty = ty::mk_param_from_def(tcx, def);
types.push(def.space, ty);
}
debug!("construct_parameter_environment: free_id={:?} free_subst={:?} predicates={:?}",
free_id,
- free_substs.repr(tcx),
- predicates.repr(tcx));
+ free_substs,
+ predicates);
//
// Finally, we have to normalize the bounds in the environment, in
ty: Ty) {
walk_ty(ty, |ty| {
match ty.sty {
- ty_rptr(region, _) => {
+ TyRef(region, _) => {
accumulator.push(*region)
}
- ty_trait(ref t) => {
+ TyTrait(ref t) => {
accumulator.push_all(t.principal.0.substs.regions().as_slice());
}
- ty_enum(_, substs) |
- ty_struct(_, substs) => {
+ TyEnum(_, substs) |
+ TyStruct(_, substs) => {
accum_substs(accumulator, substs);
}
- ty_closure(_, substs) => {
+ TyClosure(_, substs) => {
accum_substs(accumulator, substs);
}
- ty_bool |
- ty_char |
- ty_int(_) |
- ty_uint(_) |
- ty_float(_) |
- ty_uniq(_) |
- ty_str |
- ty_vec(_, _) |
- ty_ptr(_) |
- ty_bare_fn(..) |
- ty_tup(_) |
- ty_projection(_) |
- ty_param(_) |
- ty_infer(_) |
- ty_err => {
+ TyBool |
+ TyChar |
+ TyInt(_) |
+ TyUint(_) |
+ TyFloat(_) |
+ TyBox(_) |
+ TyStr |
+ TyArray(_, _) |
+ TySlice(_) |
+ TyRawPtr(_) |
+ TyBareFn(..) |
+ TyTuple(_) |
+ TyProjection(_) |
+ TyParam(_) |
+ TyInfer(_) |
+ TyError => {
}
}
});
match substs.regions {
subst::ErasedRegions => {}
subst::NonerasedRegions(ref regions) => {
- for region in regions.iter() {
+ for region in regions {
accumulator.push(*region)
}
}
all_outlive_scope: region::DestructionScopeData,
value: &Binder<T>)
-> T
- where T : TypeFoldable<'tcx> + Repr<'tcx>
+ where T : TypeFoldable<'tcx>
{
- replace_late_bound_regions(
+ ty_fold::replace_late_bound_regions(
tcx, value,
|br| ty::ReFree(ty::FreeRegion{scope: all_outlive_scope, bound_region: br})).0
}
tcx: &ty::ctxt<'tcx>,
value: &Binder<T>)
-> usize
- where T : TypeFoldable<'tcx> + Repr<'tcx>
+ where T : TypeFoldable<'tcx>
{
- let (_, skol_map) = replace_late_bound_regions(tcx, value, |_| ty::ReStatic);
+ let (_, skol_map) = ty_fold::replace_late_bound_regions(tcx, value, |_| ty::ReStatic);
skol_map.len()
}
tcx: &ty::ctxt<'tcx>,
value: &Binder<T>)
-> bool
- where T : TypeFoldable<'tcx> + Repr<'tcx>
+ where T : TypeFoldable<'tcx>
{
count_late_bound_regions(tcx, value) > 0
}
tcx: &ty::ctxt<'tcx>,
bound2_value: &Binder<Binder<T>>)
-> Binder<T>
- where T: TypeFoldable<'tcx> + Repr<'tcx>
+ where T: TypeFoldable<'tcx>
{
let bound0_value = bound2_value.skip_binder().skip_binder();
let value = ty_fold::fold_regions(tcx, bound0_value, |region, current_depth| {
tcx: &ty::ctxt<'tcx>,
value: &Binder<T>)
-> Option<T>
- where T : TypeFoldable<'tcx> + Repr<'tcx> + Clone
+ where T : TypeFoldable<'tcx>
{
if binds_late_bound_regions(tcx, value) {
None
tcx: &ty::ctxt<'tcx>,
value: &Binder<T>)
-> T
- where T : TypeFoldable<'tcx> + Repr<'tcx>
+ where T : TypeFoldable<'tcx>
{
- replace_late_bound_regions(tcx, value, |_| ty::ReStatic).0
+ ty_fold::replace_late_bound_regions(tcx, value, |_| ty::ReStatic).0
}
/// Rewrite any late-bound regions so that they are anonymous. Region numbers are
tcx: &ctxt<'tcx>,
sig: &Binder<T>)
-> Binder<T>
- where T : TypeFoldable<'tcx> + Repr<'tcx>,
+ where T : TypeFoldable<'tcx>,
{
let mut counter = 0;
- ty::Binder(replace_late_bound_regions(tcx, sig, |_| {
+ ty::Binder(ty_fold::replace_late_bound_regions(tcx, sig, |_| {
counter += 1;
ReLateBound(ty::DebruijnIndex::new(1), BrAnon(counter))
}).0)
}
-/// Replaces the late-bound-regions in `value` that are bound by `value`.
-pub fn replace_late_bound_regions<'tcx, T, F>(
- tcx: &ty::ctxt<'tcx>,
- binder: &Binder<T>,
- mut mapf: F)
- -> (T, FnvHashMap<ty::BoundRegion,ty::Region>)
- where T : TypeFoldable<'tcx> + Repr<'tcx>,
- F : FnMut(BoundRegion) -> ty::Region,
-{
- debug!("replace_late_bound_regions({})", binder.repr(tcx));
-
- let mut map = FnvHashMap();
-
- // Note: fold the field `0`, not the binder, so that late-bound
- // regions bound by `binder` are considered free.
- let value = ty_fold::fold_regions(tcx, &binder.0, |region, current_depth| {
- debug!("region={}", region.repr(tcx));
- match region {
- ty::ReLateBound(debruijn, br) if debruijn.depth == current_depth => {
- let region = *map.entry(br).or_insert_with(|| mapf(br));
-
- if let ty::ReLateBound(debruijn1, br) = region {
- // If the callback returns a late-bound region,
- // that region should always use depth 1. Then we
- // adjust it to the correct depth.
- assert_eq!(debruijn1.depth, 1);
- ty::ReLateBound(debruijn, br)
- } else {
- region
- }
- }
- _ => {
- region
- }
- }
- });
-
- debug!("resulting map: {:?} value: {:?}", map, value.repr(tcx));
- (value, map)
-}
-
impl DebruijnIndex {
pub fn new(depth: u32) -> DebruijnIndex {
assert!(depth > 0);
}
}
-impl<'tcx> Repr<'tcx> for AutoAdjustment<'tcx> {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
+impl<'tcx> fmt::Debug for AutoAdjustment<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
AdjustReifyFnPointer => {
- format!("AdjustReifyFnPointer")
+ write!(f, "AdjustReifyFnPointer")
}
AdjustUnsafeFnPointer => {
- format!("AdjustUnsafeFnPointer")
+ write!(f, "AdjustUnsafeFnPointer")
}
AdjustDerefRef(ref data) => {
- data.repr(tcx)
+ write!(f, "{:?}", data)
}
}
}
}
-impl<'tcx> Repr<'tcx> for AutoDerefRef<'tcx> {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- format!("AutoDerefRef({}, unsize={}, {})",
- self.autoderefs, self.unsize.repr(tcx), self.autoref.repr(tcx))
- }
-}
-
-impl<'tcx> Repr<'tcx> for AutoRef<'tcx> {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- match *self {
- AutoPtr(a, b) => {
- format!("AutoPtr({},{:?})", a.repr(tcx), b)
- }
- AutoUnsafe(ref a) => {
- format!("AutoUnsafe({:?})", a)
- }
- }
+impl<'tcx> fmt::Debug for AutoDerefRef<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "AutoDerefRef({}, unsize={:?}, {:?})",
+ self.autoderefs, self.unsize, self.autoref)
}
}
-impl<'tcx> Repr<'tcx> for TyTrait<'tcx> {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- format!("TyTrait({},{})",
- self.principal.repr(tcx),
- self.bounds.repr(tcx))
+impl<'tcx> fmt::Debug for TraitTy<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "TraitTy({:?},{:?})",
+ self.principal,
+ self.bounds)
}
}
-impl<'tcx> Repr<'tcx> for ty::Predicate<'tcx> {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
+impl<'tcx> fmt::Debug for ty::Predicate<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
- Predicate::Trait(ref a) => a.repr(tcx),
- Predicate::Equate(ref pair) => pair.repr(tcx),
- Predicate::RegionOutlives(ref pair) => pair.repr(tcx),
- Predicate::TypeOutlives(ref pair) => pair.repr(tcx),
- Predicate::Projection(ref pair) => pair.repr(tcx),
- }
- }
-}
-
-impl<'tcx> Repr<'tcx> for vtable_origin<'tcx> {
- fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
- match *self {
- vtable_static(def_id, ref tys, ref vtable_res) => {
- format!("vtable_static({:?}:{}, {}, {})",
- def_id,
- ty::item_path_str(tcx, def_id),
- tys.repr(tcx),
- vtable_res.repr(tcx))
- }
-
- vtable_param(x, y) => {
- format!("vtable_param({:?}, {})", x, y)
- }
-
- vtable_closure(def_id) => {
- format!("vtable_closure({:?})", def_id)
- }
-
- vtable_error => {
- format!("vtable_error")
- }
+ Predicate::Trait(ref a) => write!(f, "{:?}", a),
+ Predicate::Equate(ref pair) => write!(f, "{:?}", pair),
+ Predicate::RegionOutlives(ref pair) => write!(f, "{:?}", pair),
+ Predicate::TypeOutlives(ref pair) => write!(f, "{:?}", pair),
+ Predicate::Projection(ref pair) => write!(f, "{:?}", pair),
}
}
}
let tcx = param_env.tcx;
let did = match self_type.sty {
- ty::ty_struct(struct_did, substs) => {
+ ty::TyStruct(struct_did, substs) => {
let fields = ty::struct_fields(tcx, struct_did, substs);
for field in &fields {
if type_moves_by_default(param_env, span, field.mt.ty) {
}
struct_did
}
- ty::ty_enum(enum_did, substs) => {
+ ty::TyEnum(enum_did, substs) => {
let enum_variants = ty::enum_variants(tcx, enum_did);
- for variant in &*enum_variants {
+ for variant in enum_variants.iter() {
for variant_arg_type in &variant.args {
let substd_arg_type =
variant_arg_type.subst(tcx, substs);
}
}
-impl<'tcx> Repr<'tcx> for ty::ProjectionPredicate<'tcx> {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- format!("ProjectionPredicate({}, {})",
- self.projection_ty.repr(tcx),
- self.ty.repr(tcx))
- }
-}
-
pub trait HasProjectionTypes {
fn has_projection_types(&self) -> bool;
}
}
}
-impl<'tcx> Repr<'tcx> for ClosureTy<'tcx> {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- format!("ClosureTy({},{},{})",
- self.unsafety,
- self.sig.repr(tcx),
- self.abi)
+impl<'tcx> fmt::Debug for ClosureTy<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "ClosureTy({},{:?},{})",
+ self.unsafety,
+ self.sig,
+ self.abi)
}
}
-impl<'tcx> Repr<'tcx> for ClosureUpvar<'tcx> {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- format!("ClosureUpvar({},{})",
- self.def.repr(tcx),
- self.ty.repr(tcx))
+impl<'tcx> fmt::Debug for ClosureUpvar<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "ClosureUpvar({:?},{:?})",
+ self.def,
+ self.ty)
}
}
-impl<'tcx> Repr<'tcx> for field<'tcx> {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- format!("field({},{})",
- self.name.repr(tcx),
- self.mt.repr(tcx))
+impl<'tcx> fmt::Debug for field<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "field({},{})", self.name, self.mt)
}
}
-impl<'a, 'tcx> Repr<'tcx> for ParameterEnvironment<'a, 'tcx> {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- format!("ParameterEnvironment(\
- free_substs={}, \
- implicit_region_bound={}, \
- caller_bounds={})",
- self.free_substs.repr(tcx),
- self.implicit_region_bound.repr(tcx),
- self.caller_bounds.repr(tcx))
+impl<'a, 'tcx> fmt::Debug for ParameterEnvironment<'a, 'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "ParameterEnvironment(\
+ free_substs={:?}, \
+ implicit_region_bound={:?}, \
+ caller_bounds={:?})",
+ self.free_substs,
+ self.implicit_region_bound,
+ self.caller_bounds)
}
}
-impl<'tcx> Repr<'tcx> for ObjectLifetimeDefault {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
+impl<'tcx> fmt::Debug for ObjectLifetimeDefault {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
- ObjectLifetimeDefault::Ambiguous => format!("Ambiguous"),
- ObjectLifetimeDefault::Specific(ref r) => r.repr(tcx),
+ ObjectLifetimeDefault::Ambiguous => write!(f, "Ambiguous"),
+ ObjectLifetimeDefault::BaseDefault => write!(f, "BaseDefault"),
+ ObjectLifetimeDefault::Specific(ref r) => write!(f, "{:?}", r),
}
}
}
use middle::subst::VecPerParamSpace;
use middle::ty::{self, Ty};
use middle::traits;
+
+use std::fmt;
use std::rc::Rc;
use syntax::abi;
use syntax::ast;
use syntax::owned_slice::OwnedSlice;
-use util::ppaux::Repr;
+use util::nodemap::FnvHashMap;
///////////////////////////////////////////////////////////////////////////
// Two generic traits
/// The TypeFoldable trait is implemented for every type that can be folded.
/// Basically, every type that has a corresponding method in TypeFolder.
-pub trait TypeFoldable<'tcx>: Repr<'tcx> + Clone {
+pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self;
}
fn exit_region_binder(&mut self) { }
fn fold_binder<T>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T>
- where T : TypeFoldable<'tcx> + Repr<'tcx> + Clone
+ where T : TypeFoldable<'tcx>
{
// FIXME(#20526) this should replace `enter_region_binder`/`exit_region_binder`.
super_fold_binder(self, t)
}
}
-impl<'tcx, T:TypeFoldable<'tcx>+Repr<'tcx>+Clone> TypeFoldable<'tcx> for ty::Binder<T> {
+impl<'tcx, T:TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<T> {
fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::Binder<T> {
folder.fold_binder(self)
}
}
}
-impl<'tcx> TypeFoldable<'tcx> for ty::vtable_origin<'tcx> {
- fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::vtable_origin<'tcx> {
- match *self {
- ty::vtable_static(def_id, ref substs, ref origins) => {
- let r_substs = substs.fold_with(folder);
- let r_origins = origins.fold_with(folder);
- ty::vtable_static(def_id, r_substs, r_origins)
- }
- ty::vtable_param(n, b) => {
- ty::vtable_param(n, b)
- }
- ty::vtable_closure(def_id) => {
- ty::vtable_closure(def_id)
- }
- ty::vtable_error => {
- ty::vtable_error
- }
- }
- }
-}
-
impl<'tcx> TypeFoldable<'tcx> for ty::BuiltinBounds {
fn fold_with<F: TypeFolder<'tcx>>(&self, _folder: &mut F) -> ty::BuiltinBounds {
*self
}
}
-impl<'tcx> TypeFoldable<'tcx> for ty::ParamBounds<'tcx> {
- fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::ParamBounds<'tcx> {
- ty::ParamBounds {
- region_bounds: self.region_bounds.fold_with(folder),
- builtin_bounds: self.builtin_bounds.fold_with(folder),
- trait_bounds: self.trait_bounds.fold_with(folder),
- projection_bounds: self.projection_bounds.fold_with(folder),
- }
- }
-}
-
impl<'tcx> TypeFoldable<'tcx> for ty::TypeParameterDef<'tcx> {
fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::TypeParameterDef<'tcx> {
ty::TypeParameterDef {
ty::ObjectLifetimeDefault::Ambiguous =>
ty::ObjectLifetimeDefault::Ambiguous,
+ ty::ObjectLifetimeDefault::BaseDefault =>
+ ty::ObjectLifetimeDefault::BaseDefault,
+
ty::ObjectLifetimeDefault::Specific(r) =>
ty::ObjectLifetimeDefault::Specific(r.fold_with(folder)),
}
}
}
+impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableClosureData<'tcx, N> {
+ fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableClosureData<'tcx, N> {
+ traits::VtableClosureData {
+ closure_def_id: self.closure_def_id,
+ substs: self.substs.fold_with(folder),
+ nested: self.nested.fold_with(folder),
+ }
+ }
+}
+
impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableDefaultImplData<N> {
fn fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> traits::VtableDefaultImplData<N> {
traits::VtableDefaultImplData {
match *self {
traits::VtableImpl(ref v) => traits::VtableImpl(v.fold_with(folder)),
traits::VtableDefaultImpl(ref t) => traits::VtableDefaultImpl(t.fold_with(folder)),
- traits::VtableClosure(d, ref s) => {
- traits::VtableClosure(d, s.fold_with(folder))
+ traits::VtableClosure(ref d) => {
+ traits::VtableClosure(d.fold_with(folder))
}
traits::VtableFnPointer(ref d) => {
traits::VtableFnPointer(d.fold_with(folder))
ty: Ty<'tcx>)
-> Ty<'tcx> {
let sty = match ty.sty {
- ty::ty_uniq(typ) => {
- ty::ty_uniq(typ.fold_with(this))
+ ty::TyBox(typ) => {
+ ty::TyBox(typ.fold_with(this))
}
- ty::ty_ptr(ref tm) => {
- ty::ty_ptr(tm.fold_with(this))
+ ty::TyRawPtr(ref tm) => {
+ ty::TyRawPtr(tm.fold_with(this))
}
- ty::ty_vec(typ, sz) => {
- ty::ty_vec(typ.fold_with(this), sz)
+ ty::TyArray(typ, sz) => {
+ ty::TyArray(typ.fold_with(this), sz)
}
- ty::ty_enum(tid, ref substs) => {
+ ty::TySlice(typ) => {
+ ty::TySlice(typ.fold_with(this))
+ }
+ ty::TyEnum(tid, ref substs) => {
let substs = substs.fold_with(this);
- ty::ty_enum(tid, this.tcx().mk_substs(substs))
+ ty::TyEnum(tid, this.tcx().mk_substs(substs))
}
- ty::ty_trait(box ty::TyTrait { ref principal, ref bounds }) => {
- ty::ty_trait(box ty::TyTrait {
+ ty::TyTrait(box ty::TraitTy { ref principal, ref bounds }) => {
+ ty::TyTrait(box ty::TraitTy {
principal: principal.fold_with(this),
bounds: bounds.fold_with(this),
})
}
- ty::ty_tup(ref ts) => {
- ty::ty_tup(ts.fold_with(this))
+ ty::TyTuple(ref ts) => {
+ ty::TyTuple(ts.fold_with(this))
}
- ty::ty_bare_fn(opt_def_id, ref f) => {
+ ty::TyBareFn(opt_def_id, ref f) => {
let bfn = f.fold_with(this);
- ty::ty_bare_fn(opt_def_id, this.tcx().mk_bare_fn(bfn))
+ ty::TyBareFn(opt_def_id, this.tcx().mk_bare_fn(bfn))
}
- ty::ty_rptr(r, ref tm) => {
+ ty::TyRef(r, ref tm) => {
let r = r.fold_with(this);
- ty::ty_rptr(this.tcx().mk_region(r), tm.fold_with(this))
+ ty::TyRef(this.tcx().mk_region(r), tm.fold_with(this))
}
- ty::ty_struct(did, ref substs) => {
+ ty::TyStruct(did, ref substs) => {
let substs = substs.fold_with(this);
- ty::ty_struct(did, this.tcx().mk_substs(substs))
+ ty::TyStruct(did, this.tcx().mk_substs(substs))
}
- ty::ty_closure(did, ref substs) => {
+ ty::TyClosure(did, ref substs) => {
let s = substs.fold_with(this);
- ty::ty_closure(did, this.tcx().mk_substs(s))
+ ty::TyClosure(did, this.tcx().mk_substs(s))
}
- ty::ty_projection(ref data) => {
- ty::ty_projection(data.fold_with(this))
+ ty::TyProjection(ref data) => {
+ ty::TyProjection(data.fold_with(this))
}
- ty::ty_bool | ty::ty_char | ty::ty_str |
- ty::ty_int(_) | ty::ty_uint(_) | ty::ty_float(_) |
- ty::ty_err | ty::ty_infer(_) |
- ty::ty_param(..) => {
+ ty::TyBool | ty::TyChar | ty::TyStr |
+ ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) |
+ ty::TyError | ty::TyInfer(_) |
+ ty::TyParam(..) => {
ty.sty.clone()
}
};
region_bound: bounds.region_bound.fold_with(this),
builtin_bounds: bounds.builtin_bounds,
projection_bounds: bounds.projection_bounds.fold_with(this),
+ region_bound_will_change: bounds.region_bound_will_change,
}
}
fn fold_region(&mut self, r: ty::Region) -> ty::Region {
match r {
ty::ReLateBound(debruijn, _) if debruijn.depth < self.current_depth => {
- debug!("RegionFolder.fold_region({}) skipped bound region (current depth={})",
- r.repr(self.tcx()), self.current_depth);
+ debug!("RegionFolder.fold_region({:?}) skipped bound region (current depth={})",
+ r, self.current_depth);
r
}
_ => {
- debug!("RegionFolder.fold_region({}) folding free region (current_depth={})",
- r.repr(self.tcx()), self.current_depth);
+ debug!("RegionFolder.fold_region({:?}) folding free region (current_depth={})",
+ r, self.current_depth);
(self.fld_r)(r, self.current_depth)
}
}
}
}
+///////////////////////////////////////////////////////////////////////////
+// Late-bound region replacer
+
+// Replaces the escaping regions in a type.
+
+struct RegionReplacer<'a, 'tcx: 'a> {
+ tcx: &'a ty::ctxt<'tcx>,
+ current_depth: u32,
+ fld_r: &'a mut (FnMut(ty::BoundRegion) -> ty::Region + 'a),
+ map: FnvHashMap<ty::BoundRegion, ty::Region>
+}
+
+impl<'a, 'tcx> RegionReplacer<'a, 'tcx> {
+ fn new<F>(tcx: &'a ty::ctxt<'tcx>, fld_r: &'a mut F) -> RegionReplacer<'a, 'tcx>
+ where F : FnMut(ty::BoundRegion) -> ty::Region
+ {
+ RegionReplacer {
+ tcx: tcx,
+ current_depth: 1,
+ fld_r: fld_r,
+ map: FnvHashMap()
+ }
+ }
+}
+
+pub fn replace_late_bound_regions<'tcx,T,F>(tcx: &ty::ctxt<'tcx>,
+ value: &ty::Binder<T>,
+ mut f: F)
+ -> (T, FnvHashMap<ty::BoundRegion, ty::Region>)
+ where F : FnMut(ty::BoundRegion) -> ty::Region,
+ T : TypeFoldable<'tcx>,
+{
+ debug!("replace_late_bound_regions({:?})", value);
+ let mut replacer = RegionReplacer::new(tcx, &mut f);
+ let result = value.skip_binder().fold_with(&mut replacer);
+ (result, replacer.map)
+}
+
+impl<'a, 'tcx> TypeFolder<'tcx> for RegionReplacer<'a, 'tcx>
+{
+ fn tcx(&self) -> &ty::ctxt<'tcx> { self.tcx }
+
+ fn enter_region_binder(&mut self) {
+ self.current_depth += 1;
+ }
+
+ fn exit_region_binder(&mut self) {
+ self.current_depth -= 1;
+ }
+
+ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+ if !ty::type_escapes_depth(t, self.current_depth-1) {
+ return t;
+ }
+
+ super_fold_ty(self, t)
+ }
+
+ fn fold_region(&mut self, r: ty::Region) -> ty::Region {
+ match r {
+ ty::ReLateBound(debruijn, br) if debruijn.depth == self.current_depth => {
+ debug!("RegionReplacer.fold_region({:?}) folding region (current_depth={})",
+ r, self.current_depth);
+ let fld_r = &mut self.fld_r;
+ let region = *self.map.entry(br).or_insert_with(|| fld_r(br));
+ if let ty::ReLateBound(debruijn1, br) = region {
+ // If the callback returns a late-bound region,
+ // that region should always use depth 1. Then we
+ // adjust it to the correct depth.
+ assert_eq!(debruijn1.depth, 1);
+ ty::ReLateBound(debruijn, br)
+ } else {
+ region
+ }
+ }
+ r => r
+ }
+ }
+}
+
///////////////////////////////////////////////////////////////////////////
// Region eraser
//
impl<'a, 'tcx> TypeFolder<'tcx> for RegionEraser<'a, 'tcx> {
fn tcx(&self) -> &ty::ctxt<'tcx> { self.tcx }
+ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+ if !ty::type_has_erasable_regions(t) {
+ return t;
+ }
+
+ super_fold_ty(self, t)
+ }
+
fn fold_region(&mut self, r: ty::Region) -> ty::Region {
// because whether or not a region is bound affects subtyping,
// we can't erase the bound/free distinction, but we can
}
}
-pub fn shift_regions<'tcx, T:TypeFoldable<'tcx>+Repr<'tcx>>(tcx: &ty::ctxt<'tcx>,
- amount: u32, value: &T) -> T {
- debug!("shift_regions(value={}, amount={})",
- value.repr(tcx), amount);
+pub fn shift_regions<'tcx, T:TypeFoldable<'tcx>>(tcx: &ty::ctxt<'tcx>,
+ amount: u32, value: &T) -> T {
+ debug!("shift_regions(value={:?}, amount={})",
+ value, amount);
value.fold_with(&mut RegionFolder::new(tcx, &mut |region, _current_depth| {
shift_region(region, amount)
use middle::ty::{self, Ty};
use middle::ty_relate::{self, Relate, TypeRelation, RelateResult};
-use util::ppaux::Repr;
/// A type "A" *matches* "B" if the fresh types in B could be
/// substituted with values so as to make it equal to A. Matching is
fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.tcx }
fn a_is_expected(&self) -> bool { true } // irrelevant
+ fn will_change(&mut self, _: bool, _: bool) -> bool {
+ // we're ignoring regions in this code
+ false
+ }
+
fn relate_with_variance<T:Relate<'a,'tcx>>(&mut self,
_: ty::Variance,
a: &T,
}
fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> {
- debug!("{}.regions({}, {})",
+ debug!("{}.regions({:?}, {:?})",
self.tag(),
- a.repr(self.tcx()),
- b.repr(self.tcx()));
+ a,
+ b);
Ok(a)
}
fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
- debug!("{}.tys({}, {})", self.tag(),
- a.repr(self.tcx()), b.repr(self.tcx()));
+ debug!("{}.tys({:?}, {:?})", self.tag(),
+ a, b);
if a == b { return Ok(a); }
match (&a.sty, &b.sty) {
- (_, &ty::ty_infer(ty::FreshTy(_))) |
- (_, &ty::ty_infer(ty::FreshIntTy(_))) |
- (_, &ty::ty_infer(ty::FreshFloatTy(_))) => {
+ (_, &ty::TyInfer(ty::FreshTy(_))) |
+ (_, &ty::TyInfer(ty::FreshIntTy(_))) |
+ (_, &ty::TyInfer(ty::FreshFloatTy(_))) => {
Ok(a)
}
- (&ty::ty_infer(_), _) |
- (_, &ty::ty_infer(_)) => {
+ (&ty::TyInfer(_), _) |
+ (_, &ty::TyInfer(_)) => {
Err(ty::terr_sorts(ty_relate::expected_found(self, &a, &b)))
}
- (&ty::ty_err, _) | (_, &ty::ty_err) => {
+ (&ty::TyError, _) | (_, &ty::TyError) => {
Ok(self.tcx().types.err)
}
use std::rc::Rc;
use syntax::abi;
use syntax::ast;
-use util::ppaux::Repr;
pub type RelateResult<'tcx, T> = Result<T, ty::type_err<'tcx>>;
+#[derive(Clone, Debug)]
+pub enum Cause {
+ ExistentialRegionBound(bool), // if true, this is a default, else explicit
+}
+
pub trait TypeRelation<'a,'tcx> : Sized {
fn tcx(&self) -> &'a ty::ctxt<'tcx>;
/// relation. Just affects error messages.
fn a_is_expected(&self) -> bool;
+ fn with_cause<F,R>(&mut self, _cause: Cause, f: F) -> R
+ where F: FnOnce(&mut Self) -> R
+ {
+ f(self)
+ }
+
+ /// Hack for deciding whether the lifetime bound defaults change
+ /// will be a breaking change or not. The bools indicate whether
+ /// `a`/`b` have a default that will change to `'static`; the
+ /// result is true if this will potentially affect the affect of
+ /// relating `a` and `b`.
+ fn will_change(&mut self, a: bool, b: bool) -> bool;
+
/// Generic relation routine suitable for most anything.
fn relate<T:Relate<'a,'tcx>>(&mut self, a: &T, b: &T) -> RelateResult<'tcx, T> {
Relate::relate(self, a, b)
-> RelateResult<'tcx, ty::mt<'tcx>>
where R: TypeRelation<'a,'tcx>
{
- debug!("{}.mts({}, {})",
+ debug!("{}.mts({:?}, {:?})",
relation.tag(),
- a.repr(relation.tcx()),
- b.repr(relation.tcx()));
+ a,
+ b);
if a.mutbl != b.mutbl {
Err(ty::terr_mutability)
} else {
-> RelateResult<'tcx, Substs<'tcx>>
where R: TypeRelation<'a,'tcx>
{
- debug!("substs: item_def_id={} a_subst={} b_subst={}",
- item_def_id.repr(relation.tcx()),
- a_subst.repr(relation.tcx()),
- b_subst.repr(relation.tcx()));
+ debug!("substs: item_def_id={:?} a_subst={:?} b_subst={:?}",
+ item_def_id,
+ a_subst,
+ b_subst);
let variances;
let opt_variances = if relation.tcx().variance_computed.get() {
-> RelateResult<'tcx, Vec<ty::Region>>
where R: TypeRelation<'a,'tcx>
{
- let tcx = relation.tcx();
let num_region_params = a_rs.len();
- debug!("relate_region_params(a_rs={}, \
- b_rs={}, variances={})",
- a_rs.repr(tcx),
- b_rs.repr(tcx),
- variances.repr(tcx));
+ debug!("relate_region_params(a_rs={:?}, \
+ b_rs={:?}, variances={:?})",
+ a_rs,
+ b_rs,
+ variances);
assert_eq!(num_region_params,
variances.map_or(num_region_params,
return Err(ty::terr_arg_count);
}
- a_args.iter()
- .zip(b_args.iter())
+ a_args.iter().zip(b_args)
.map(|(a, b)| relation.relate_with_variance(ty::Contravariant, a, b))
.collect()
}
if a.len() != b.len() {
Err(ty::terr_projection_bounds_length(expected_found(relation, &a.len(), &b.len())))
} else {
- a.iter()
- .zip(b.iter())
+ a.iter().zip(b)
.map(|(a, b)| relation.relate(a, b))
.collect()
}
-> RelateResult<'tcx, ty::ExistentialBounds<'tcx>>
where R: TypeRelation<'a,'tcx>
{
- let r = try!(relation.relate_with_variance(ty::Contravariant,
- &a.region_bound,
- &b.region_bound));
+ let will_change = relation.will_change(a.region_bound_will_change,
+ b.region_bound_will_change);
+
+ let r =
+ try!(relation.with_cause(
+ Cause::ExistentialRegionBound(will_change),
+ |relation| relation.relate_with_variance(ty::Contravariant,
+ &a.region_bound,
+ &b.region_bound)));
let nb = try!(relation.relate(&a.builtin_bounds, &b.builtin_bounds));
let pb = try!(relation.relate(&a.projection_bounds, &b.projection_bounds));
Ok(ty::ExistentialBounds { region_bound: r,
builtin_bounds: nb,
- projection_bounds: pb })
+ projection_bounds: pb,
+ region_bound_will_change: will_change })
}
}
let b_sty = &b.sty;
debug!("super_tys: a_sty={:?} b_sty={:?}", a_sty, b_sty);
match (a_sty, b_sty) {
- (&ty::ty_infer(_), _) |
- (_, &ty::ty_infer(_)) =>
+ (&ty::TyInfer(_), _) |
+ (_, &ty::TyInfer(_)) =>
{
// The caller should handle these cases!
tcx.sess.bug("var types encountered in super_relate_tys")
}
- (&ty::ty_err, _) | (_, &ty::ty_err) =>
+ (&ty::TyError, _) | (_, &ty::TyError) =>
{
Ok(tcx.types.err)
}
- (&ty::ty_char, _) |
- (&ty::ty_bool, _) |
- (&ty::ty_int(_), _) |
- (&ty::ty_uint(_), _) |
- (&ty::ty_float(_), _) |
- (&ty::ty_str, _)
+ (&ty::TyChar, _) |
+ (&ty::TyBool, _) |
+ (&ty::TyInt(_), _) |
+ (&ty::TyUint(_), _) |
+ (&ty::TyFloat(_), _) |
+ (&ty::TyStr, _)
if a == b =>
{
Ok(a)
}
- (&ty::ty_param(ref a_p), &ty::ty_param(ref b_p))
+ (&ty::TyParam(ref a_p), &ty::TyParam(ref b_p))
if a_p.idx == b_p.idx && a_p.space == b_p.space =>
{
Ok(a)
}
- (&ty::ty_enum(a_id, a_substs), &ty::ty_enum(b_id, b_substs))
+ (&ty::TyEnum(a_id, a_substs), &ty::TyEnum(b_id, b_substs))
if a_id == b_id =>
{
let substs = try!(relate_item_substs(relation, a_id, a_substs, b_substs));
Ok(ty::mk_enum(tcx, a_id, tcx.mk_substs(substs)))
}
- (&ty::ty_trait(ref a_), &ty::ty_trait(ref b_)) =>
+ (&ty::TyTrait(ref a_), &ty::TyTrait(ref b_)) =>
{
let principal = try!(relation.relate(&a_.principal, &b_.principal));
let bounds = try!(relation.relate(&a_.bounds, &b_.bounds));
Ok(ty::mk_trait(tcx, principal, bounds))
}
- (&ty::ty_struct(a_id, a_substs), &ty::ty_struct(b_id, b_substs))
+ (&ty::TyStruct(a_id, a_substs), &ty::TyStruct(b_id, b_substs))
if a_id == b_id =>
{
let substs = try!(relate_item_substs(relation, a_id, a_substs, b_substs));
Ok(ty::mk_struct(tcx, a_id, tcx.mk_substs(substs)))
}
- (&ty::ty_closure(a_id, a_substs),
- &ty::ty_closure(b_id, b_substs))
+ (&ty::TyClosure(a_id, a_substs),
+ &ty::TyClosure(b_id, b_substs))
if a_id == b_id =>
{
- // All ty_closure types with the same id represent
+ // All TyClosure types with the same id represent
// the (anonymous) type of the same closure expression. So
// all of their regions should be equated.
let substs = try!(relate_substs(relation, None, a_substs, b_substs));
Ok(ty::mk_closure(tcx, a_id, tcx.mk_substs(substs)))
}
- (&ty::ty_uniq(a_inner), &ty::ty_uniq(b_inner)) =>
+ (&ty::TyBox(a_inner), &ty::TyBox(b_inner)) =>
{
let typ = try!(relation.relate(&a_inner, &b_inner));
Ok(ty::mk_uniq(tcx, typ))
}
- (&ty::ty_ptr(ref a_mt), &ty::ty_ptr(ref b_mt)) =>
+ (&ty::TyRawPtr(ref a_mt), &ty::TyRawPtr(ref b_mt)) =>
{
let mt = try!(relation.relate(a_mt, b_mt));
Ok(ty::mk_ptr(tcx, mt))
}
- (&ty::ty_rptr(a_r, ref a_mt), &ty::ty_rptr(b_r, ref b_mt)) =>
+ (&ty::TyRef(a_r, ref a_mt), &ty::TyRef(b_r, ref b_mt)) =>
{
let r = try!(relation.relate_with_variance(ty::Contravariant, a_r, b_r));
let mt = try!(relation.relate(a_mt, b_mt));
Ok(ty::mk_rptr(tcx, tcx.mk_region(r), mt))
}
- (&ty::ty_vec(a_t, Some(sz_a)), &ty::ty_vec(b_t, Some(sz_b))) =>
+ (&ty::TyArray(a_t, sz_a), &ty::TyArray(b_t, sz_b)) =>
{
let t = try!(relation.relate(&a_t, &b_t));
if sz_a == sz_b {
}
}
- (&ty::ty_vec(a_t, None), &ty::ty_vec(b_t, None)) =>
+ (&ty::TySlice(a_t), &ty::TySlice(b_t)) =>
{
let t = try!(relation.relate(&a_t, &b_t));
Ok(ty::mk_vec(tcx, t, None))
}
- (&ty::ty_tup(ref as_), &ty::ty_tup(ref bs)) =>
+ (&ty::TyTuple(ref as_), &ty::TyTuple(ref bs)) =>
{
if as_.len() == bs.len() {
- let ts = try!(as_.iter()
- .zip(bs.iter())
+ let ts = try!(as_.iter().zip(bs)
.map(|(a, b)| relation.relate(a, b))
.collect::<Result<_, _>>());
Ok(ty::mk_tup(tcx, ts))
}
}
- (&ty::ty_bare_fn(a_opt_def_id, a_fty), &ty::ty_bare_fn(b_opt_def_id, b_fty))
+ (&ty::TyBareFn(a_opt_def_id, a_fty), &ty::TyBareFn(b_opt_def_id, b_fty))
if a_opt_def_id == b_opt_def_id =>
{
let fty = try!(relation.relate(a_fty, b_fty));
Ok(ty::mk_bare_fn(tcx, a_opt_def_id, tcx.mk_bare_fn(fty)))
}
- (&ty::ty_projection(ref a_data), &ty::ty_projection(ref b_data)) =>
+ (&ty::TyProjection(ref a_data), &ty::TyProjection(ref b_data)) =>
{
let projection_ty = try!(relation.relate(a_data, b_data));
Ok(ty::mk_projection(tcx, projection_ty.trait_ref, projection_ty.item_name))
fn push_subtypes<'tcx>(stack: &mut Vec<Ty<'tcx>>, parent_ty: Ty<'tcx>) {
match parent_ty.sty {
- ty::ty_bool | ty::ty_char | ty::ty_int(_) | ty::ty_uint(_) | ty::ty_float(_) |
- ty::ty_str | ty::ty_infer(_) | ty::ty_param(_) | ty::ty_err => {
+ ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) |
+ ty::TyStr | ty::TyInfer(_) | ty::TyParam(_) | ty::TyError => {
}
- ty::ty_uniq(ty) | ty::ty_vec(ty, _) => {
+ ty::TyBox(ty) | ty::TyArray(ty, _) | ty::TySlice(ty) => {
stack.push(ty);
}
- ty::ty_ptr(ref mt) | ty::ty_rptr(_, ref mt) => {
+ ty::TyRawPtr(ref mt) | ty::TyRef(_, ref mt) => {
stack.push(mt.ty);
}
- ty::ty_projection(ref data) => {
+ ty::TyProjection(ref data) => {
push_reversed(stack, data.trait_ref.substs.types.as_slice());
}
- ty::ty_trait(box ty::TyTrait { ref principal, ref bounds }) => {
+ ty::TyTrait(box ty::TraitTy { ref principal, ref bounds }) => {
push_reversed(stack, principal.substs().types.as_slice());
push_reversed(stack, &bounds.projection_bounds.iter().map(|pred| {
pred.0.ty
}).collect::<Vec<_>>());
}
- ty::ty_enum(_, ref substs) |
- ty::ty_struct(_, ref substs) |
- ty::ty_closure(_, ref substs) => {
+ ty::TyEnum(_, ref substs) |
+ ty::TyStruct(_, ref substs) |
+ ty::TyClosure(_, ref substs) => {
push_reversed(stack, substs.types.as_slice());
}
- ty::ty_tup(ref ts) => {
+ ty::TyTuple(ref ts) => {
push_reversed(stack, ts);
}
- ty::ty_bare_fn(_, ref ft) => {
+ ty::TyBareFn(_, ref ft) => {
push_sig_subtypes(stack, &ft.sig);
}
}
use syntax::parse::token;
use syntax::ptr::P;
use syntax::ast;
+use syntax::feature_gate::AttributeType;
use std::collections::HashMap;
use std::borrow::ToOwned;
#[doc(hidden)]
pub llvm_passes: Vec<String>,
+
+ #[doc(hidden)]
+ pub attributes: Vec<(String, AttributeType)>,
}
impl<'a> Registry<'a> {
lint_passes: vec!(),
lint_groups: HashMap::new(),
llvm_passes: vec!(),
+ attributes: vec!(),
}
}
pub fn register_llvm_pass(&mut self, name: &str) {
self.llvm_passes.push(name.to_owned());
}
+
+
+ /// Register an attribute with an attribute type.
+ ///
+ /// Registered attributes will bypass the `custom_attribute` feature gate.
+ /// `Whitelisted` attributes will additionally not trigger the `unused_attribute`
+ /// lint. `CrateLevel` attributes will not be allowed on anything other than a crate.
+ pub fn register_attribute(&mut self, name: String, ty: AttributeType) {
+ if let AttributeType::Gated(..) = ty {
+ self.sess.span_err(self.krate_span, "plugin tried to register a gated \
+ attribute. Only `Normal`, `Whitelisted`, \
+ and `CrateLevel` attributes are allowed");
+ }
+ self.attributes.push((name, ty));
+ }
}
use syntax::diagnostic::{ColorConfig, Auto, Always, Never, SpanHandler};
use syntax::parse;
use syntax::parse::token::InternedString;
+use syntax::feature_gate::UnstableFeatures;
use getopts;
use std::collections::HashMap;
pub unstable_features: UnstableFeatures
}
-#[derive(Clone, Copy)]
-pub enum UnstableFeatures {
- /// Hard errors for unstable features are active, as on
- /// beta/stable channels.
- Disallow,
- /// Use the default lint levels
- Default,
- /// Errors are bypassed for bootstrapping. This is required any time
- /// during the build that feature-related lints are set to warn or above
- /// because the build turns on warnings-as-errors and uses lots of unstable
- /// features. As a result, this this is always required for building Rust
- /// itself.
- Cheat
-}
-
#[derive(Clone, PartialEq, Eq)]
pub enum PrintRequest {
FileNames,
parse::parse_meta_from_source_str("cfgspec".to_string(),
s.to_string(),
Vec::new(),
- &parse::new_parse_sess())
+ &parse::ParseSess::new())
}).collect::<ast::CrateConfig>()
}
match (disable_unstable_features, bootstrap_secret_key, bootstrap_provided_key) {
(_, Some(ref s), Some(ref p)) if s == p => UnstableFeatures::Cheat,
(true, _, _) => UnstableFeatures::Disallow,
- (false, _, _) => UnstableFeatures::Default
+ (false, _, _) => UnstableFeatures::Allow
}
}
use syntax::parse::token;
use syntax::parse::ParseSess;
use syntax::{ast, codemap};
+use syntax::feature_gate::AttributeType;
use rustc_back::target::Target;
pub lint_store: RefCell<lint::LintStore>,
pub lints: RefCell<NodeMap<Vec<(lint::LintId, codemap::Span, String)>>>,
pub plugin_llvm_passes: RefCell<Vec<String>>,
+ pub plugin_attributes: RefCell<Vec<(String, AttributeType)>>,
pub crate_types: RefCell<Vec<config::CrateType>>,
pub crate_metadata: RefCell<Vec<String>>,
pub features: RefCell<feature_gate::Features>,
/// operations such as auto-dereference and monomorphization.
pub recursion_limit: Cell<usize>,
- pub can_print_warnings: bool
+ pub can_print_warnings: bool,
+
+ next_node_id: Cell<ast::NodeId>
}
impl Session {
lints.insert(id, vec!((lint_id, sp, msg)));
}
pub fn next_node_id(&self) -> ast::NodeId {
- self.parse_sess.next_node_id()
+ self.reserve_node_ids(1)
}
pub fn reserve_node_ids(&self, count: ast::NodeId) -> ast::NodeId {
- self.parse_sess.reserve_node_ids(count)
+ let id = self.next_node_id.get();
+
+ match id.checked_add(count) {
+ Some(next) => self.next_node_id.set(next),
+ None => self.bug("Input too large, ran out of node ids!")
+ }
+
+ id
}
pub fn diagnostic<'a>(&'a self) -> &'a diagnostic::SpanHandler {
&self.parse_sess.span_diagnostic
}
pub fn codemap<'a>(&'a self) -> &'a codemap::CodeMap {
- &self.parse_sess.span_diagnostic.cm
+ self.parse_sess.codemap()
}
// This exists to help with refactoring to eliminate impossible
// cases later on
let codemap = codemap::CodeMap::new();
let diagnostic_handler =
- diagnostic::default_handler(sopts.color, Some(registry), can_print_warnings);
+ diagnostic::Handler::new(sopts.color, Some(registry), can_print_warnings);
let span_diagnostic_handler =
- diagnostic::mk_span_handler(diagnostic_handler, codemap);
+ diagnostic::SpanHandler::new(diagnostic_handler, codemap);
build_session_(sopts, local_crate_source_file, span_diagnostic_handler)
}
}
};
let target_cfg = config::build_target_config(&sopts, &span_diagnostic);
- let p_s = parse::new_parse_sess_special_handler(span_diagnostic);
+ let p_s = parse::ParseSess::with_span_handler(span_diagnostic);
let default_sysroot = match sopts.maybe_sysroot {
Some(_) => None,
None => Some(filesearch::get_or_default_sysroot())
lint_store: RefCell::new(lint::LintStore::new()),
lints: RefCell::new(NodeMap()),
plugin_llvm_passes: RefCell::new(Vec::new()),
+ plugin_attributes: RefCell::new(Vec::new()),
crate_types: RefCell::new(Vec::new()),
crate_metadata: RefCell::new(Vec::new()),
delayed_span_bug: RefCell::new(None),
features: RefCell::new(feature_gate::Features::new()),
recursion_limit: Cell::new(64),
- can_print_warnings: can_print_warnings
+ can_print_warnings: can_print_warnings,
+ next_node_id: Cell::new(1)
};
sess
use std::path::{self, Path, PathBuf};
use std::ffi::OsString;
-// Unfortunately, on windows, gcc cannot accept paths of the form `\\?\C:\...`
-// (a verbatim path). This form of path is generally pretty rare, but the
-// implementation of `fs::canonicalize` currently generates paths of this form,
-// meaning that we're going to be passing quite a few of these down to gcc.
+// Unfortunately, on windows, it looks like msvcrt.dll is silently translating
+// verbatim paths under the hood to non-verbatim paths! This manifests itself as
+// gcc looking like it cannot accept paths of the form `\\?\C:\...`, but the
+// real bug seems to lie in msvcrt.dll.
+//
+// Verbatim paths are generally pretty rare, but the implementation of
+// `fs::canonicalize` currently generates paths of this form, meaning that we're
+// going to be passing quite a few of these down to gcc, so we need to deal with
+// this case.
//
// For now we just strip the "verbatim prefix" of `\\?\` from the path. This
// will probably lose information in some cases, but there's not a whole lot
-// more we can do with a buggy gcc...
+// more we can do with a buggy msvcrt...
+//
+// For some more information, see this comment:
+// https://github.com/rust-lang/rust/issues/25505#issuecomment-102876737
pub fn fix_windows_verbatim_for_gcc(p: &Path) -> PathBuf {
if !cfg!(windows) {
return p.to_path_buf()
Some(path::Component::Prefix(p)) => p,
_ => return p.to_path_buf(),
};
- let disk = match prefix.kind() {
- path::Prefix::VerbatimDisk(disk) => disk,
- _ => return p.to_path_buf(),
- };
- let mut base = OsString::from(format!("{}:", disk as char));
- base.push(components.as_path());
- PathBuf::from(base)
+ match prefix.kind() {
+ path::Prefix::VerbatimDisk(disk) => {
+ let mut base = OsString::from(format!("{}:", disk as char));
+ base.push(components.as_path());
+ PathBuf::from(base)
+ }
+ path::Prefix::VerbatimUNC(server, share) => {
+ let mut base = OsString::from(r"\\");
+ base.push(server);
+ base.push(r"\");
+ base.push(share);
+ base.push(components.as_path());
+ PathBuf::from(base)
+ }
+ _ => p.to_path_buf(),
+ }
}
// except according to those terms.
-use middle::def;
-use middle::region;
-use middle::subst::{VecPerParamSpace,Subst};
-use middle::subst;
+use middle::subst::{self, Subst};
use middle::ty::{BoundRegion, BrAnon, BrNamed};
use middle::ty::{ReEarlyBound, BrFresh, ctxt};
use middle::ty::{ReFree, ReScope, ReInfer, ReStatic, Region, ReEmpty};
use middle::ty::{ReSkolemized, ReVar, BrEnv};
-use middle::ty::{mt, Ty, ParamTy};
-use middle::ty::{ty_bool, ty_char, ty_struct, ty_enum};
-use middle::ty::{ty_err, ty_str, ty_vec, ty_float, ty_bare_fn};
-use middle::ty::{ty_param, ty_ptr, ty_rptr, ty_tup};
-use middle::ty::ty_closure;
-use middle::ty::{ty_uniq, ty_trait, ty_int, ty_uint, ty_infer};
+use middle::ty::{mt, Ty};
+use middle::ty::{TyBool, TyChar, TyStruct, TyEnum};
+use middle::ty::{TyError, TyStr, TyArray, TySlice, TyFloat, TyBareFn};
+use middle::ty::{TyParam, TyRawPtr, TyRef, TyTuple};
+use middle::ty::TyClosure;
+use middle::ty::{TyBox, TyTrait, TyInt, TyUint, TyInfer};
use middle::ty;
-use middle::ty_fold::TypeFoldable;
+use middle::ty_fold::{self, TypeFoldable};
-use std::collections::HashMap;
-use std::collections::hash_state::HashState;
-use std::hash::Hash;
-use std::rc::Rc;
+use std::fmt;
use syntax::abi;
-use syntax::ast_map;
-use syntax::codemap::{Span, Pos};
use syntax::parse::token;
-use syntax::print::pprust;
-use syntax::ptr::P;
use syntax::{ast, ast_util};
-use syntax::owned_slice::OwnedSlice;
-/// Produces a string suitable for debugging output.
-pub trait Repr<'tcx> {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String;
+pub fn verbose() -> bool {
+ ty::tls::with(|tcx| tcx.sess.verbose())
}
-/// Produces a string suitable for showing to the user.
-pub trait UserString<'tcx> : Repr<'tcx> {
- fn user_string(&self, tcx: &ctxt<'tcx>) -> String;
-}
-
-pub fn note_and_explain_region(cx: &ctxt,
- prefix: &str,
- region: ty::Region,
- suffix: &str) -> Option<Span> {
- match explain_region_and_span(cx, region) {
- (ref str, Some(span)) => {
- cx.sess.span_note(
- span,
- &format!("{}{}{}", prefix, *str, suffix));
- Some(span)
- }
- (ref str, None) => {
- cx.sess.note(
- &format!("{}{}{}", prefix, *str, suffix));
- None
- }
- }
-}
-
-/// When a free region is associated with `item`, how should we describe the item in the error
-/// message.
-fn item_scope_tag(item: &ast::Item) -> &'static str {
- match item.node {
- ast::ItemImpl(..) => "impl",
- ast::ItemStruct(..) => "struct",
- ast::ItemEnum(..) => "enum",
- ast::ItemTrait(..) => "trait",
- ast::ItemFn(..) => "function body",
- _ => "item"
- }
-}
-
-pub fn explain_region_and_span(cx: &ctxt, region: ty::Region)
- -> (String, Option<Span>) {
- return match region {
- ReScope(scope) => {
- let new_string;
- let on_unknown_scope = || {
- (format!("unknown scope: {:?}. Please report a bug.", scope), None)
- };
- let span = match scope.span(&cx.map) {
- Some(s) => s,
- None => return on_unknown_scope(),
- };
- let tag = match cx.map.find(scope.node_id()) {
- Some(ast_map::NodeBlock(_)) => "block",
- Some(ast_map::NodeExpr(expr)) => match expr.node {
- ast::ExprCall(..) => "call",
- ast::ExprMethodCall(..) => "method call",
- ast::ExprMatch(_, _, ast::MatchSource::IfLetDesugar { .. }) => "if let",
- ast::ExprMatch(_, _, ast::MatchSource::WhileLetDesugar) => "while let",
- ast::ExprMatch(_, _, ast::MatchSource::ForLoopDesugar) => "for",
- ast::ExprMatch(..) => "match",
- _ => "expression",
- },
- Some(ast_map::NodeStmt(_)) => "statement",
- Some(ast_map::NodeItem(it)) => item_scope_tag(&*it),
- Some(_) | None => {
- // this really should not happen
- return on_unknown_scope();
- }
- };
- let scope_decorated_tag = match scope {
- region::CodeExtent::Misc(_) => tag,
- region::CodeExtent::ParameterScope { .. } => {
- "scope of parameters for function"
- }
- region::CodeExtent::DestructionScope(_) => {
- new_string = format!("destruction scope surrounding {}", tag);
- &*new_string
- }
- region::CodeExtent::Remainder(r) => {
- new_string = format!("block suffix following statement {}",
- r.first_statement_index);
- &*new_string
- }
- };
- explain_span(cx, scope_decorated_tag, span)
-
- }
-
- ReFree(ref fr) => {
- let prefix = match fr.bound_region {
- BrAnon(idx) => {
- format!("the anonymous lifetime #{} defined on", idx + 1)
- }
- BrFresh(_) => "an anonymous lifetime defined on".to_string(),
- _ => {
- format!("the lifetime {} as defined on",
- bound_region_ptr_to_string(cx, fr.bound_region))
- }
- };
-
- match cx.map.find(fr.scope.node_id) {
- Some(ast_map::NodeBlock(ref blk)) => {
- let (msg, opt_span) = explain_span(cx, "block", blk.span);
- (format!("{} {}", prefix, msg), opt_span)
- }
- Some(ast_map::NodeItem(it)) => {
- let tag = item_scope_tag(&*it);
- let (msg, opt_span) = explain_span(cx, tag, it.span);
- (format!("{} {}", prefix, msg), opt_span)
- }
- Some(_) | None => {
- // this really should not happen
- (format!("{} unknown free region bounded by scope {:?}", prefix, fr.scope), None)
- }
- }
- }
-
- ReStatic => { ("the static lifetime".to_string(), None) }
-
- ReEmpty => { ("the empty lifetime".to_string(), None) }
-
- ReEarlyBound(ref data) => {
- (format!("{}", token::get_name(data.name)), None)
- }
-
- // I believe these cases should not occur (except when debugging,
- // perhaps)
- ty::ReInfer(_) | ty::ReLateBound(..) => {
- (format!("lifetime {:?}", region), None)
- }
- };
-
- fn explain_span(cx: &ctxt, heading: &str, span: Span)
- -> (String, Option<Span>) {
- let lo = cx.sess.codemap().lookup_char_pos_adj(span.lo);
- (format!("the {} at {}:{}", heading, lo.line, lo.col.to_usize()),
- Some(span))
- }
-}
-
-pub fn bound_region_ptr_to_string(cx: &ctxt, br: BoundRegion) -> String {
- bound_region_to_string(cx, "", false, br)
-}
-
-pub fn bound_region_to_string(cx: &ctxt,
- prefix: &str, space: bool,
- br: BoundRegion) -> String {
- let space_str = if space { " " } else { "" };
-
- if cx.sess.verbose() {
- return format!("{}{}{}", prefix, br.repr(cx), space_str)
- }
-
- match br {
- BrNamed(_, name) => {
- format!("{}{}{}", prefix, token::get_name(name), space_str)
- }
- BrAnon(_) | BrFresh(_) | BrEnv => prefix.to_string()
- }
-}
-
-// In general, if you are giving a region error message,
-// you should use `explain_region()` or, better yet,
-// `note_and_explain_region()`
-pub fn region_ptr_to_string(cx: &ctxt, region: Region) -> String {
- region_to_string(cx, "&", true, region)
-}
-
-pub fn region_to_string(cx: &ctxt, prefix: &str, space: bool, region: Region) -> String {
- let space_str = if space { " " } else { "" };
-
- if cx.sess.verbose() {
- return format!("{}{}{}", prefix, region.repr(cx), space_str)
- }
-
- // These printouts are concise. They do not contain all the information
- // the user might want to diagnose an error, but there is basically no way
- // to fit that into a short string. Hence the recommendation to use
- // `explain_region()` or `note_and_explain_region()`.
- match region {
- ty::ReScope(_) => prefix.to_string(),
- ty::ReEarlyBound(ref data) => {
- token::get_name(data.name).to_string()
- }
- ty::ReLateBound(_, br) => bound_region_to_string(cx, prefix, space, br),
- ty::ReFree(ref fr) => bound_region_to_string(cx, prefix, space, fr.bound_region),
- ty::ReInfer(ReSkolemized(_, br)) => {
- bound_region_to_string(cx, prefix, space, br)
- }
- ty::ReInfer(ReVar(_)) => prefix.to_string(),
- ty::ReStatic => format!("{}'static{}", prefix, space_str),
- ty::ReEmpty => format!("{}'<empty>{}", prefix, space_str),
- }
-}
-
-pub fn mutability_to_string(m: ast::Mutability) -> String {
- match m {
- ast::MutMutable => "mut ".to_string(),
- ast::MutImmutable => "".to_string(),
- }
-}
-
-pub fn mt_to_string<'tcx>(cx: &ctxt<'tcx>, m: &mt<'tcx>) -> String {
- format!("{}{}",
- mutability_to_string(m.mutbl),
- ty_to_string(cx, m.ty))
-}
-
-pub fn vec_map_to_string<T, F>(ts: &[T], f: F) -> String where
- F: FnMut(&T) -> String,
-{
- let tstrs = ts.iter().map(f).collect::<Vec<String>>();
- format!("[{}]", tstrs.connect(", "))
-}
-
-pub fn ty_to_string<'tcx>(cx: &ctxt<'tcx>, typ: &ty::TyS<'tcx>) -> String {
- fn bare_fn_to_string<'tcx>(cx: &ctxt<'tcx>,
- opt_def_id: Option<ast::DefId>,
- unsafety: ast::Unsafety,
- abi: abi::Abi,
- ident: Option<ast::Ident>,
- sig: &ty::PolyFnSig<'tcx>)
- -> String {
- let mut s = String::new();
-
- match unsafety {
- ast::Unsafety::Normal => {}
- ast::Unsafety::Unsafe => {
- s.push_str(&unsafety.to_string());
- s.push(' ');
- }
- };
-
- if abi != abi::Rust {
- s.push_str(&format!("extern {} ", abi.to_string()));
- };
-
- s.push_str("fn");
-
- match ident {
- Some(i) => {
- s.push(' ');
- s.push_str(&token::get_ident(i));
- }
- _ => { }
- }
-
- push_sig_to_string(cx, &mut s, '(', ')', sig);
-
- match opt_def_id {
- Some(def_id) => {
- s.push_str(" {");
- let path_str = ty::item_path_str(cx, def_id);
- s.push_str(&path_str[..]);
- s.push_str("}");
- }
- None => { }
- }
-
- s
- }
-
- fn closure_to_string<'tcx>(cx: &ctxt<'tcx>, cty: &ty::ClosureTy<'tcx>) -> String {
- let mut s = String::new();
- s.push_str("[closure");
- push_sig_to_string(cx, &mut s, '(', ')', &cty.sig);
- s.push(']');
- s
- }
-
- fn push_sig_to_string<'tcx>(cx: &ctxt<'tcx>,
- s: &mut String,
- bra: char,
- ket: char,
- sig: &ty::PolyFnSig<'tcx>) {
- s.push(bra);
- let strs = sig.0.inputs
- .iter()
- .map(|a| ty_to_string(cx, *a))
- .collect::<Vec<_>>();
- s.push_str(&strs.connect(", "));
- if sig.0.variadic {
- s.push_str(", ...");
+fn fn_sig(f: &mut fmt::Formatter,
+ inputs: &[Ty],
+ variadic: bool,
+ output: ty::FnOutput)
+ -> fmt::Result {
+ try!(write!(f, "("));
+ let mut inputs = inputs.iter();
+ if let Some(&ty) = inputs.next() {
+ try!(write!(f, "{}", ty));
+ for &ty in inputs {
+ try!(write!(f, ", {}", ty));
}
- s.push(ket);
-
- match sig.0.output {
- ty::FnConverging(t) => {
- if !ty::type_is_nil(t) {
- s.push_str(" -> ");
- s.push_str(&ty_to_string(cx, t));
- }
- }
- ty::FnDiverging => {
- s.push_str(" -> !");
- }
- }
- }
-
- fn infer_ty_to_string(cx: &ctxt, ty: ty::InferTy) -> String {
- let print_var_ids = cx.sess.verbose();
- match ty {
- ty::TyVar(ref vid) if print_var_ids => vid.repr(cx),
- ty::IntVar(ref vid) if print_var_ids => vid.repr(cx),
- ty::FloatVar(ref vid) if print_var_ids => vid.repr(cx),
- ty::TyVar(_) | ty::IntVar(_) | ty::FloatVar(_) => format!("_"),
- ty::FreshTy(v) => format!("FreshTy({})", v),
- ty::FreshIntTy(v) => format!("FreshIntTy({})", v),
- ty::FreshFloatTy(v) => format!("FreshFloatTy({})", v)
+ if variadic {
+ try!(write!(f, ", ..."));
}
}
+ try!(write!(f, ")"));
- // pretty print the structural type representation:
- match typ.sty {
- ty_bool => "bool".to_string(),
- ty_char => "char".to_string(),
- ty_int(t) => ast_util::int_ty_to_string(t, None).to_string(),
- ty_uint(t) => ast_util::uint_ty_to_string(t, None).to_string(),
- ty_float(t) => ast_util::float_ty_to_string(t).to_string(),
- ty_uniq(typ) => format!("Box<{}>", ty_to_string(cx, typ)),
- ty_ptr(ref tm) => {
- format!("*{} {}", match tm.mutbl {
- ast::MutMutable => "mut",
- ast::MutImmutable => "const",
- }, ty_to_string(cx, tm.ty))
- }
- ty_rptr(r, ref tm) => {
- let mut buf = region_ptr_to_string(cx, *r);
- buf.push_str(&mt_to_string(cx, tm));
- buf
- }
- ty_tup(ref elems) => {
- let strs = elems
- .iter()
- .map(|elem| ty_to_string(cx, *elem))
- .collect::<Vec<_>>();
- match &strs[..] {
- [ref string] => format!("({},)", string),
- strs => format!("({})", strs.connect(", "))
+ match output {
+ ty::FnConverging(ty) => {
+ if !ty::type_is_nil(ty) {
+ try!(write!(f, " -> {}", ty));
}
+ Ok(())
}
- ty_bare_fn(opt_def_id, ref f) => {
- bare_fn_to_string(cx, opt_def_id, f.unsafety, f.abi, None, &f.sig)
- }
- ty_infer(infer_ty) => infer_ty_to_string(cx, infer_ty),
- ty_err => "[type error]".to_string(),
- ty_param(ref param_ty) => param_ty.user_string(cx),
- ty_enum(did, substs) | ty_struct(did, substs) => {
- let base = ty::item_path_str(cx, did);
- parameterized(cx, &base, substs, did, &[],
- || ty::lookup_item_type(cx, did).generics)
- }
- ty_trait(ref data) => {
- data.user_string(cx)
- }
- ty::ty_projection(ref data) => {
- format!("<{} as {}>::{}",
- data.trait_ref.self_ty().user_string(cx),
- data.trait_ref.user_string(cx),
- data.item_name.user_string(cx))
- }
- ty_str => "str".to_string(),
- ty_closure(ref did, substs) => {
- let closure_tys = cx.closure_tys.borrow();
- closure_tys.get(did).map(|closure_type| {
- closure_to_string(cx, &closure_type.subst(cx, substs))
- }).unwrap_or_else(|| {
- if did.krate == ast::LOCAL_CRATE {
- let span = cx.map.span(did.node);
- format!("[closure {}]", span.repr(cx))
- } else {
- format!("[closure]")
- }
- })
- }
- ty_vec(t, sz) => {
- let inner_str = ty_to_string(cx, t);
- match sz {
- Some(n) => format!("[{}; {}]", inner_str, n),
- None => format!("[{}]", inner_str),
- }
+ ty::FnDiverging => {
+ write!(f, " -> !")
}
}
}
-pub fn explicit_self_category_to_str(category: &ty::ExplicitSelfCategory)
- -> &'static str {
- match *category {
- ty::StaticExplicitSelfCategory => "static",
- ty::ByValueExplicitSelfCategory => "self",
- ty::ByReferenceExplicitSelfCategory(_, ast::MutMutable) => {
- "&mut self"
+fn parameterized<GG>(f: &mut fmt::Formatter,
+ substs: &subst::Substs,
+ did: ast::DefId,
+ projections: &[ty::ProjectionPredicate],
+ get_generics: GG)
+ -> fmt::Result
+ where GG: for<'tcx> FnOnce(&ty::ctxt<'tcx>) -> ty::Generics<'tcx>
+{
+ let (fn_trait_kind, verbose) = try!(ty::tls::with(|tcx| {
+ try!(write!(f, "{}", ty::item_path_str(tcx, did)));
+ Ok((tcx.lang_items.fn_trait_kind(did), tcx.sess.verbose()))
+ }));
+
+ let mut empty = true;
+ let mut start_or_continue = |f: &mut fmt::Formatter, start: &str, cont: &str| {
+ if empty {
+ empty = false;
+ write!(f, "{}", start)
+ } else {
+ write!(f, "{}", cont)
}
- ty::ByReferenceExplicitSelfCategory(_, ast::MutImmutable) => "&self",
- ty::ByBoxExplicitSelfCategory => "Box<self>",
- }
-}
+ };
-pub fn parameterized<'tcx,GG>(cx: &ctxt<'tcx>,
- base: &str,
- substs: &subst::Substs<'tcx>,
- did: ast::DefId,
- projections: &[ty::ProjectionPredicate<'tcx>],
- get_generics: GG)
- -> String
- where GG : FnOnce() -> ty::Generics<'tcx>
-{
- if cx.sess.verbose() {
- let mut strings = vec![];
+ if verbose {
match substs.regions {
subst::ErasedRegions => {
- strings.push(format!(".."));
+ try!(start_or_continue(f, "<", ", "));
+ try!(write!(f, ".."));
}
subst::NonerasedRegions(ref regions) => {
- for region in regions.iter() {
- strings.push(region.repr(cx));
+ for region in regions {
+ try!(start_or_continue(f, "<", ", "));
+ try!(write!(f, "{:?}", region));
}
}
}
- for ty in substs.types.iter() {
- strings.push(ty.repr(cx));
+ for &ty in &substs.types {
+ try!(start_or_continue(f, "<", ", "));
+ try!(write!(f, "{}", ty));
}
- for projection in projections.iter() {
- strings.push(format!("{}={}",
- projection.projection_ty.item_name.user_string(cx),
- projection.ty.user_string(cx)));
+ for projection in projections {
+ try!(start_or_continue(f, "<", ", "));
+ try!(write!(f, "{}={}",
+ projection.projection_ty.item_name,
+ projection.ty));
}
- return if strings.is_empty() {
- format!("{}", base)
- } else {
- format!("{}<{}>", base, strings.connect(","))
- };
+ return start_or_continue(f, "", ">");
}
- let mut strs = Vec::new();
+ if fn_trait_kind.is_some() && projections.len() == 1 {
+ let projection_ty = projections[0].ty;
+ if let TyTuple(ref args) = substs.types.get_slice(subst::TypeSpace)[0].sty {
+ return fn_sig(f, args, false, ty::FnConverging(projection_ty));
+ }
+ }
match substs.regions {
subst::ErasedRegions => { }
subst::NonerasedRegions(ref regions) => {
- for &r in regions.iter() {
- let s = region_to_string(cx, "", false, r);
+ for &r in regions {
+ try!(start_or_continue(f, "<", ", "));
+ let s = r.to_string();
if s.is_empty() {
// This happens when the value of the region
// parameter is not easily serialized. This may be
// because the user omitted it in the first place,
// or because it refers to some block in the code,
// etc. I'm not sure how best to serialize this.
- strs.push(format!("'_"));
+ try!(write!(f, "'_"));
} else {
- strs.push(s)
+ try!(write!(f, "{}", s));
}
}
}
// ICEs trying to fetch the generics early in the pipeline. This
// is kind of a hacky workaround in that -Z verbose is required to
// avoid those ICEs.
- let generics = get_generics();
-
- let has_self = substs.self_ty().is_some();
let tps = substs.types.get_slice(subst::TypeSpace);
- let ty_params = generics.types.get_slice(subst::TypeSpace);
- let has_defaults = ty_params.last().map_or(false, |def| def.default.is_some());
- let num_defaults = if has_defaults {
- ty_params.iter().zip(tps.iter()).rev().take_while(|&(def, &actual)| {
- match def.default {
- Some(default) => {
- if !has_self && ty::type_has_self(default) {
- // In an object type, there is no `Self`, and
- // thus if the default value references Self,
- // the user will be required to give an
- // explicit value. We can't even do the
- // substitution below to check without causing
- // an ICE. (#18956).
- false
- } else {
- default.subst(cx, substs) == actual
+ let num_defaults = ty::tls::with(|tcx| {
+ let generics = get_generics(tcx);
+
+ let has_self = substs.self_ty().is_some();
+ let ty_params = generics.types.get_slice(subst::TypeSpace);
+ if ty_params.last().map_or(false, |def| def.default.is_some()) {
+ let substs = tcx.lift(&substs);
+ ty_params.iter().zip(tps).rev().take_while(|&(def, &actual)| {
+ match def.default {
+ Some(default) => {
+ if !has_self && ty::type_has_self(default) {
+ // In an object type, there is no `Self`, and
+ // thus if the default value references Self,
+ // the user will be required to give an
+ // explicit value. We can't even do the
+ // substitution below to check without causing
+ // an ICE. (#18956).
+ false
+ } else {
+ let default = tcx.lift(&default);
+ substs.and_then(|substs| default.subst(tcx, substs)) == Some(actual)
+ }
}
+ None => false
}
- None => false
- }
- }).count()
- } else {
- 0
- };
+ }).count()
+ } else {
+ 0
+ }
+ });
- for t in &tps[..tps.len() - num_defaults] {
- strs.push(ty_to_string(cx, *t))
+ for &ty in &tps[..tps.len() - num_defaults] {
+ try!(start_or_continue(f, "<", ", "));
+ try!(write!(f, "{}", ty));
}
for projection in projections {
- strs.push(format!("{}={}",
- projection.projection_ty.item_name.user_string(cx),
- projection.ty.user_string(cx)));
- }
-
- if cx.lang_items.fn_trait_kind(did).is_some() && projections.len() == 1 {
- let projection_ty = projections[0].ty;
- let tail =
- if ty::type_is_nil(projection_ty) {
- format!("")
- } else {
- format!(" -> {}", projection_ty.user_string(cx))
- };
- format!("{}({}){}",
- base,
- if strs[0].starts_with("(") && strs[0].ends_with(",)") {
- &strs[0][1 .. strs[0].len() - 2] // Remove '(' and ',)'
- } else if strs[0].starts_with("(") && strs[0].ends_with(")") {
- &strs[0][1 .. strs[0].len() - 1] // Remove '(' and ')'
- } else {
- &strs[0][..]
- },
- tail)
- } else if !strs.is_empty() {
- format!("{}<{}>", base, strs.connect(", "))
- } else {
- format!("{}", base)
+ try!(start_or_continue(f, "<", ", "));
+ try!(write!(f, "{}={}",
+ projection.projection_ty.item_name,
+ projection.ty));
}
-}
-pub fn ty_to_short_str<'tcx>(cx: &ctxt<'tcx>, typ: Ty<'tcx>) -> String {
- let mut s = typ.repr(cx).to_string();
- if s.len() >= 32 {
- s = (&s[0..32]).to_string();
- }
- return s;
+ start_or_continue(f, "", ">")
}
-impl<'tcx, T:Repr<'tcx>> Repr<'tcx> for Option<T> {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- match self {
- &None => "None".to_string(),
- &Some(ref t) => t.repr(tcx),
- }
- }
-}
-
-impl<'tcx, T:Repr<'tcx>> Repr<'tcx> for P<T> {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- (**self).repr(tcx)
- }
-}
+fn in_binder<'tcx, T, U>(f: &mut fmt::Formatter,
+ tcx: &ty::ctxt<'tcx>,
+ original: &ty::Binder<T>,
+ lifted: Option<ty::Binder<U>>) -> fmt::Result
+ where T: fmt::Display, U: fmt::Display + TypeFoldable<'tcx>
+{
+ // Replace any anonymous late-bound regions with named
+ // variants, using gensym'd identifiers, so that we can
+ // clearly differentiate between named and unnamed regions in
+ // the output. We'll probably want to tweak this over time to
+ // decide just how much information to give.
+ let value = if let Some(v) = lifted {
+ v
+ } else {
+ return write!(f, "{}", original.0);
+ };
-impl<'tcx,T:Repr<'tcx>,U:Repr<'tcx>> Repr<'tcx> for Result<T,U> {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- match self {
- &Ok(ref t) => t.repr(tcx),
- &Err(ref u) => format!("Err({})", u.repr(tcx))
+ let mut empty = true;
+ let mut start_or_continue = |f: &mut fmt::Formatter, start: &str, cont: &str| {
+ if empty {
+ empty = false;
+ write!(f, "{}", start)
+ } else {
+ write!(f, "{}", cont)
}
- }
-}
-
-impl<'tcx> Repr<'tcx> for () {
- fn repr(&self, _tcx: &ctxt) -> String {
- "()".to_string()
- }
-}
-
-impl<'a, 'tcx, T: ?Sized +Repr<'tcx>> Repr<'tcx> for &'a T {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- Repr::repr(*self, tcx)
- }
-}
-
-impl<'tcx, T:Repr<'tcx>> Repr<'tcx> for Rc<T> {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- (&**self).repr(tcx)
- }
-}
-
-impl<'tcx, T:Repr<'tcx>> Repr<'tcx> for Box<T> {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- (&**self).repr(tcx)
- }
-}
-
-fn repr_vec<'tcx, T:Repr<'tcx>>(tcx: &ctxt<'tcx>, v: &[T]) -> String {
- vec_map_to_string(v, |t| t.repr(tcx))
-}
-
-impl<'tcx, T:Repr<'tcx>> Repr<'tcx> for [T] {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- repr_vec(tcx, self)
- }
-}
-
-impl<'tcx, T:Repr<'tcx>> Repr<'tcx> for OwnedSlice<T> {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- repr_vec(tcx, &self[..])
- }
-}
-
-// This is necessary to handle types like Option<Vec<T>>, for which
-// autoderef cannot convert the &[T] handler
-impl<'tcx, T:Repr<'tcx>> Repr<'tcx> for Vec<T> {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- repr_vec(tcx, &self[..])
- }
-}
+ };
-impl<'tcx, T:UserString<'tcx>> UserString<'tcx> for Vec<T> {
- fn user_string(&self, tcx: &ctxt<'tcx>) -> String {
- let strs: Vec<String> =
- self.iter().map(|t| t.user_string(tcx)).collect();
- strs.connect(", ")
- }
-}
+ let new_value = ty_fold::replace_late_bound_regions(tcx, &value, |br| {
+ let _ = start_or_continue(f, "for<", ", ");
+ ty::ReLateBound(ty::DebruijnIndex::new(1), match br {
+ ty::BrNamed(_, name) => {
+ let _ = write!(f, "{}", name);
+ br
+ }
+ ty::BrAnon(_) |
+ ty::BrFresh(_) |
+ ty::BrEnv => {
+ let name = token::intern("'r");
+ let _ = write!(f, "{}", name);
+ ty::BrNamed(ast_util::local_def(ast::DUMMY_NODE_ID), name)
+ }
+ })
+ }).0;
-impl<'tcx> Repr<'tcx> for def::Def {
- fn repr(&self, _tcx: &ctxt) -> String {
- format!("{:?}", *self)
- }
+ try!(start_or_continue(f, "", "> "));
+ write!(f, "{}", new_value)
}
/// This curious type is here to help pretty-print trait objects. In
/// Right now there is only one trait in an object that can have
/// projection bounds, so we just stuff them altogether. But in
/// reality we should eventually sort things out better.
-type TraitAndProjections<'tcx> =
- (ty::TraitRef<'tcx>, Vec<ty::ProjectionPredicate<'tcx>>);
-
-impl<'tcx> UserString<'tcx> for TraitAndProjections<'tcx> {
- fn user_string(&self, tcx: &ctxt<'tcx>) -> String {
- let &(ref trait_ref, ref projection_bounds) = self;
- let base = ty::item_path_str(tcx, trait_ref.def_id);
- parameterized(tcx,
- &base,
- trait_ref.substs,
- trait_ref.def_id,
- &projection_bounds[..],
- || ty::lookup_trait_def(tcx, trait_ref.def_id).generics.clone())
+#[derive(Clone, Debug)]
+struct TraitAndProjections<'tcx>(ty::TraitRef<'tcx>, Vec<ty::ProjectionPredicate<'tcx>>);
+
+impl<'tcx> TypeFoldable<'tcx> for TraitAndProjections<'tcx> {
+ fn fold_with<F:ty_fold::TypeFolder<'tcx>>(&self, folder: &mut F)
+ -> TraitAndProjections<'tcx> {
+ TraitAndProjections(self.0.fold_with(folder), self.1.fold_with(folder))
}
}
-impl<'tcx> UserString<'tcx> for ty::TyTrait<'tcx> {
- fn user_string(&self, tcx: &ctxt<'tcx>) -> String {
- let &ty::TyTrait { ref principal, ref bounds } = self;
-
- let mut components = vec![];
+impl<'tcx> fmt::Display for TraitAndProjections<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let TraitAndProjections(ref trait_ref, ref projection_bounds) = *self;
+ parameterized(f, trait_ref.substs,
+ trait_ref.def_id,
+ projection_bounds,
+ |tcx| ty::lookup_trait_def(tcx, trait_ref.def_id).generics.clone())
+ }
+}
- let tap: ty::Binder<TraitAndProjections<'tcx>> =
- ty::Binder((principal.0.clone(),
- bounds.projection_bounds.iter().map(|x| x.0.clone()).collect()));
+impl<'tcx> fmt::Display for ty::TraitTy<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let bounds = &self.bounds;
// Generate the main trait ref, including associated types.
- components.push(tap.user_string(tcx));
+ try!(ty::tls::with(|tcx| {
+ let principal = tcx.lift(&self.principal.0)
+ .expect("could not lift TraitRef for printing");
+ let projections = tcx.lift(&bounds.projection_bounds[..])
+ .expect("could not lift projections for printing");
+ let projections = projections.map_in_place(|p| p.0);
+
+ let tap = ty::Binder(TraitAndProjections(principal, projections));
+ in_binder(f, tcx, &ty::Binder(""), Some(tap))
+ }));
// Builtin bounds.
for bound in &bounds.builtin_bounds {
- components.push(bound.user_string(tcx));
+ try!(write!(f, " + {:?}", bound));
}
- // Region, if not obviously implied by builtin bounds.
- if bounds.region_bound != ty::ReStatic {
- // Region bound is implied by builtin bounds:
- components.push(bounds.region_bound.user_string(tcx));
+ // FIXME: It'd be nice to compute from context when this bound
+ // is implied, but that's non-trivial -- we'd perhaps have to
+ // use thread-local data of some kind? There are also
+ // advantages to just showing the region, since it makes
+ // people aware that it's there.
+ let bound = bounds.region_bound.to_string();
+ if !bound.is_empty() {
+ try!(write!(f, " + {}", bound));
}
- components.retain(|s| !s.is_empty());
-
- components.connect(" + ")
- }
-}
-
-impl<'tcx> Repr<'tcx> for ty::TypeParameterDef<'tcx> {
- fn repr(&self, _tcx: &ctxt<'tcx>) -> String {
- format!("TypeParameterDef({:?}, {:?}/{})",
- self.def_id,
- self.space,
- self.index)
- }
-}
+ if bounds.region_bound_will_change && verbose() {
+ try!(write!(f, " [WILL-CHANGE]"));
+ }
-impl<'tcx> Repr<'tcx> for ty::RegionParameterDef {
- fn repr(&self, tcx: &ctxt) -> String {
- format!("RegionParameterDef(name={}, def_id={}, bounds={})",
- token::get_name(self.name),
- self.def_id.repr(tcx),
- self.bounds.repr(tcx))
+ Ok(())
}
}
-impl<'tcx> Repr<'tcx> for ty::TyS<'tcx> {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- ty_to_string(tcx, self)
+impl<'tcx> fmt::Debug for ty::TypeParameterDef<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "TypeParameterDef({:?}, {:?}/{})",
+ self.def_id, self.space, self.index)
}
}
-impl<'tcx> Repr<'tcx> for ty::mt<'tcx> {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- mt_to_string(tcx, self)
+impl<'tcx> fmt::Debug for ty::TyS<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{}", *self)
}
}
-impl<'tcx> Repr<'tcx> for subst::Substs<'tcx> {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- format!("Substs[types={}, regions={}]",
- self.types.repr(tcx),
- self.regions.repr(tcx))
+impl<'tcx> fmt::Display for ty::mt<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{}{}",
+ if self.mutbl == ast::MutMutable { "mut " } else { "" },
+ self.ty)
}
}
-impl<'tcx, T:Repr<'tcx>> Repr<'tcx> for subst::VecPerParamSpace<T> {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- format!("[{};{};{}]",
- self.get_slice(subst::TypeSpace).repr(tcx),
- self.get_slice(subst::SelfSpace).repr(tcx),
- self.get_slice(subst::FnSpace).repr(tcx))
+impl<'tcx> fmt::Debug for subst::Substs<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "Substs[types={:?}, regions={:?}]",
+ self.types, self.regions)
}
}
-impl<'tcx> Repr<'tcx> for ty::ItemSubsts<'tcx> {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- format!("ItemSubsts({})", self.substs.repr(tcx))
+impl<'tcx> fmt::Debug for ty::ItemSubsts<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "ItemSubsts({:?})", self.substs)
}
}
-impl<'tcx> Repr<'tcx> for subst::RegionSubsts {
- fn repr(&self, tcx: &ctxt) -> String {
+impl fmt::Debug for subst::RegionSubsts {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
- subst::ErasedRegions => "erased".to_string(),
- subst::NonerasedRegions(ref regions) => regions.repr(tcx)
- }
- }
-}
-
-impl<'tcx> Repr<'tcx> for ty::BuiltinBounds {
- fn repr(&self, _tcx: &ctxt) -> String {
- let mut res = Vec::new();
- for b in self {
- res.push(match b {
- ty::BoundSend => "Send".to_string(),
- ty::BoundSized => "Sized".to_string(),
- ty::BoundCopy => "Copy".to_string(),
- ty::BoundSync => "Sync".to_string(),
- });
- }
- res.connect("+")
- }
-}
-
-impl<'tcx> Repr<'tcx> for ty::ParamBounds<'tcx> {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- let mut res = Vec::new();
- res.push(self.builtin_bounds.repr(tcx));
- for t in &self.trait_bounds {
- res.push(t.repr(tcx));
+ subst::ErasedRegions => write!(f, "erased"),
+ subst::NonerasedRegions(ref regions) => write!(f, "{:?}", regions)
}
- res.connect("+")
}
}
-impl<'tcx> Repr<'tcx> for ty::TraitRef<'tcx> {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
+impl<'tcx> fmt::Debug for ty::TraitRef<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// when printing out the debug representation, we don't need
// to enumerate the `for<...>` etc because the debruijn index
// tells you everything you need to know.
- let base = ty::item_path_str(tcx, self.def_id);
- let result = parameterized(tcx, &base, self.substs, self.def_id, &[],
- || ty::lookup_trait_def(tcx, self.def_id).generics.clone());
match self.substs.self_ty() {
- None => result,
- Some(sty) => format!("<{} as {}>", sty.repr(tcx), result)
+ None => write!(f, "{}", *self),
+ Some(self_ty) => write!(f, "<{:?} as {}>", self_ty, *self)
}
}
}
-impl<'tcx> Repr<'tcx> for ty::TraitDef<'tcx> {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- format!("TraitDef(generics={}, trait_ref={})",
- self.generics.repr(tcx),
- self.trait_ref.repr(tcx))
+impl<'tcx> fmt::Debug for ty::TraitDef<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "TraitDef(generics={:?}, trait_ref={:?})",
+ self.generics, self.trait_ref)
}
}
-impl<'tcx> Repr<'tcx> for ast::TraitItem {
- fn repr(&self, _tcx: &ctxt) -> String {
- let kind = match self.node {
- ast::ConstTraitItem(..) => "ConstTraitItem",
- ast::MethodTraitItem(..) => "MethodTraitItem",
- ast::TypeTraitItem(..) => "TypeTraitItem",
- };
- format!("{}({}, id={})", kind, self.ident, self.id)
- }
-}
-
-impl<'tcx> Repr<'tcx> for ast::Expr {
- fn repr(&self, _tcx: &ctxt) -> String {
- format!("expr({}: {})", self.id, pprust::expr_to_string(self))
- }
-}
-
-impl<'tcx> Repr<'tcx> for ast::Path {
- fn repr(&self, _tcx: &ctxt) -> String {
- format!("path({})", pprust::path_to_string(self))
- }
-}
-
-impl<'tcx> UserString<'tcx> for ast::Path {
- fn user_string(&self, _tcx: &ctxt) -> String {
- pprust::path_to_string(self)
- }
-}
-
-impl<'tcx> Repr<'tcx> for ast::Ty {
- fn repr(&self, _tcx: &ctxt) -> String {
- format!("type({})", pprust::ty_to_string(self))
- }
-}
-
-impl<'tcx> Repr<'tcx> for ast::Item {
- fn repr(&self, tcx: &ctxt) -> String {
- format!("item({})", tcx.map.node_to_string(self.id))
- }
-}
-
-impl<'tcx> Repr<'tcx> for ast::Lifetime {
- fn repr(&self, _tcx: &ctxt) -> String {
- format!("lifetime({}: {})", self.id, pprust::lifetime_to_string(self))
- }
-}
-
-impl<'tcx> Repr<'tcx> for ast::Stmt {
- fn repr(&self, _tcx: &ctxt) -> String {
- format!("stmt({}: {})",
- ast_util::stmt_id(self),
- pprust::stmt_to_string(self))
- }
-}
-
-impl<'tcx> Repr<'tcx> for ast::Pat {
- fn repr(&self, _tcx: &ctxt) -> String {
- format!("pat({}: {})", self.id, pprust::pat_to_string(self))
- }
-}
+impl fmt::Display for ty::BoundRegion {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ if verbose() {
+ return write!(f, "{:?}", *self);
+ }
-impl<'tcx> Repr<'tcx> for ty::BoundRegion {
- fn repr(&self, tcx: &ctxt) -> String {
match *self {
- ty::BrAnon(id) => format!("BrAnon({})", id),
- ty::BrNamed(id, name) => {
- format!("BrNamed({}, {})", id.repr(tcx), token::get_name(name))
- }
- ty::BrFresh(id) => format!("BrFresh({})", id),
- ty::BrEnv => "BrEnv".to_string()
+ BrNamed(_, name) => write!(f, "{}", name),
+ BrAnon(_) | BrFresh(_) | BrEnv => Ok(())
}
}
}
-impl<'tcx> Repr<'tcx> for ty::Region {
- fn repr(&self, tcx: &ctxt) -> String {
+impl fmt::Debug for ty::Region {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
ty::ReEarlyBound(ref data) => {
- format!("ReEarlyBound({}, {:?}, {}, {})",
- data.param_id,
- data.space,
- data.index,
- token::get_name(data.name))
+ write!(f, "ReEarlyBound({}, {:?}, {}, {})",
+ data.param_id,
+ data.space,
+ data.index,
+ data.name)
}
ty::ReLateBound(binder_id, ref bound_region) => {
- format!("ReLateBound({:?}, {})",
- binder_id,
- bound_region.repr(tcx))
+ write!(f, "ReLateBound({:?}, {:?})",
+ binder_id,
+ bound_region)
}
- ty::ReFree(ref fr) => fr.repr(tcx),
+ ty::ReFree(ref fr) => write!(f, "{:?}", fr),
ty::ReScope(id) => {
- format!("ReScope({:?})", id)
+ write!(f, "ReScope({:?})", id)
}
- ty::ReStatic => {
- "ReStatic".to_string()
- }
+ ty::ReStatic => write!(f, "ReStatic"),
ty::ReInfer(ReVar(ref vid)) => {
- format!("{:?}", vid)
+ write!(f, "{:?}", vid)
}
ty::ReInfer(ReSkolemized(id, ref bound_region)) => {
- format!("re_skolemized({}, {})", id, bound_region.repr(tcx))
+ write!(f, "ReSkolemized({}, {:?})", id, bound_region)
}
- ty::ReEmpty => {
- "ReEmpty".to_string()
- }
+ ty::ReEmpty => write!(f, "ReEmpty")
}
}
}
-impl<'tcx> UserString<'tcx> for ty::Region {
- fn user_string(&self, tcx: &ctxt) -> String {
- region_to_string(tcx, "", false, *self)
- }
-}
-
-impl<'tcx> Repr<'tcx> for ty::FreeRegion {
- fn repr(&self, tcx: &ctxt) -> String {
- format!("ReFree({}, {})",
- self.scope.repr(tcx),
- self.bound_region.repr(tcx))
- }
-}
-
-impl<'tcx> Repr<'tcx> for region::CodeExtent {
- fn repr(&self, _tcx: &ctxt) -> String {
- match *self {
- region::CodeExtent::ParameterScope { fn_id, body_id } =>
- format!("ParameterScope({}, {})", fn_id, body_id),
- region::CodeExtent::Misc(node_id) =>
- format!("Misc({})", node_id),
- region::CodeExtent::DestructionScope(node_id) =>
- format!("DestructionScope({})", node_id),
- region::CodeExtent::Remainder(rem) =>
- format!("Remainder({}, {})", rem.block, rem.first_statement_index),
+impl fmt::Display for ty::Region {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ if verbose() {
+ return write!(f, "{:?}", *self);
}
- }
-}
-impl<'tcx> Repr<'tcx> for region::DestructionScopeData {
- fn repr(&self, _tcx: &ctxt) -> String {
+ // These printouts are concise. They do not contain all the information
+ // the user might want to diagnose an error, but there is basically no way
+ // to fit that into a short string. Hence the recommendation to use
+ // `explain_region()` or `note_and_explain_region()`.
match *self {
- region::DestructionScopeData{ node_id } =>
- format!("DestructionScopeData {{ node_id: {} }}", node_id),
- }
- }
-}
-
-impl<'tcx> Repr<'tcx> for ast::DefId {
- fn repr(&self, tcx: &ctxt) -> String {
- // Unfortunately, there seems to be no way to attempt to print
- // a path for a def-id, so I'll just make a best effort for now
- // and otherwise fallback to just printing the crate/node pair
- if self.krate == ast::LOCAL_CRATE {
- match tcx.map.find(self.node) {
- Some(ast_map::NodeItem(..)) |
- Some(ast_map::NodeForeignItem(..)) |
- Some(ast_map::NodeImplItem(..)) |
- Some(ast_map::NodeTraitItem(..)) |
- Some(ast_map::NodeVariant(..)) |
- Some(ast_map::NodeStructCtor(..)) => {
- return format!(
- "{:?}:{}",
- *self,
- ty::item_path_str(tcx, *self))
- }
- _ => {}
+ ty::ReEarlyBound(ref data) => {
+ write!(f, "{}", data.name)
+ }
+ ty::ReLateBound(_, br) |
+ ty::ReFree(ty::FreeRegion { bound_region: br, .. }) |
+ ty::ReInfer(ReSkolemized(_, br)) => {
+ write!(f, "{}", br)
}
+ ty::ReScope(_) |
+ ty::ReInfer(ReVar(_)) => Ok(()),
+ ty::ReStatic => write!(f, "'static"),
+ ty::ReEmpty => write!(f, "'<empty>"),
}
- return format!("{:?}", *self)
- }
-}
-
-impl<'tcx> Repr<'tcx> for ty::TypeScheme<'tcx> {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- format!("TypeScheme {{generics: {}, ty: {}}}",
- self.generics.repr(tcx),
- self.ty.repr(tcx))
- }
-}
-
-impl<'tcx> Repr<'tcx> for ty::Generics<'tcx> {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- format!("Generics(types: {}, regions: {})",
- self.types.repr(tcx),
- self.regions.repr(tcx))
- }
-}
-
-impl<'tcx> Repr<'tcx> for ty::GenericPredicates<'tcx> {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- format!("GenericPredicates(predicates: {})",
- self.predicates.repr(tcx))
- }
-}
-
-impl<'tcx> Repr<'tcx> for ty::InstantiatedPredicates<'tcx> {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- format!("InstantiatedPredicates({})",
- self.predicates.repr(tcx))
- }
-}
-
-impl<'tcx> Repr<'tcx> for ty::ItemVariances {
- fn repr(&self, tcx: &ctxt) -> String {
- format!("ItemVariances(types={}, \
- regions={})",
- self.types.repr(tcx),
- self.regions.repr(tcx))
- }
-}
-
-impl<'tcx> Repr<'tcx> for ty::Variance {
- fn repr(&self, _: &ctxt) -> String {
- // The first `.to_string()` returns a &'static str (it is not an implementation
- // of the ToString trait). Because of that, we need to call `.to_string()` again
- // if we want to have a `String`.
- let result: &'static str = (*self).to_string();
- result.to_string()
- }
-}
-
-impl<'tcx> Repr<'tcx> for ty::ImplOrTraitItem<'tcx> {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- format!("ImplOrTraitItem({})",
- match *self {
- ty::ImplOrTraitItem::MethodTraitItem(ref i) => i.repr(tcx),
- ty::ImplOrTraitItem::ConstTraitItem(ref i) => i.repr(tcx),
- ty::ImplOrTraitItem::TypeTraitItem(ref i) => i.repr(tcx),
- })
- }
-}
-
-impl<'tcx> Repr<'tcx> for ty::AssociatedConst<'tcx> {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- format!("AssociatedConst(name: {}, ty: {}, vis: {}, def_id: {})",
- self.name.repr(tcx),
- self.ty.repr(tcx),
- self.vis.repr(tcx),
- self.def_id.repr(tcx))
- }
-}
-
-impl<'tcx> Repr<'tcx> for ty::AssociatedType {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- format!("AssociatedType(name: {}, vis: {}, def_id: {})",
- self.name.repr(tcx),
- self.vis.repr(tcx),
- self.def_id.repr(tcx))
- }
-}
-
-impl<'tcx> Repr<'tcx> for ty::Method<'tcx> {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- format!("Method(name: {}, generics: {}, predicates: {}, fty: {}, \
- explicit_self: {}, vis: {}, def_id: {})",
- self.name.repr(tcx),
- self.generics.repr(tcx),
- self.predicates.repr(tcx),
- self.fty.repr(tcx),
- self.explicit_self.repr(tcx),
- self.vis.repr(tcx),
- self.def_id.repr(tcx))
}
}
-impl<'tcx> Repr<'tcx> for ast::Name {
- fn repr(&self, _tcx: &ctxt) -> String {
- token::get_name(*self).to_string()
+impl fmt::Debug for ty::FreeRegion {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "ReFree({:?}, {:?})",
+ self.scope, self.bound_region)
}
}
-impl<'tcx> UserString<'tcx> for ast::Name {
- fn user_string(&self, _tcx: &ctxt) -> String {
- token::get_name(*self).to_string()
+impl fmt::Debug for ty::ItemVariances {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "ItemVariances(types={:?}, regions={:?})",
+ self.types, self.regions)
}
}
-impl<'tcx> Repr<'tcx> for ast::Ident {
- fn repr(&self, _tcx: &ctxt) -> String {
- token::get_ident(*self).to_string()
+impl<'tcx> fmt::Debug for ty::GenericPredicates<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "GenericPredicates({:?})", self.predicates)
}
}
-impl<'tcx> Repr<'tcx> for ast::ExplicitSelf_ {
- fn repr(&self, _tcx: &ctxt) -> String {
- format!("{:?}", *self)
+impl<'tcx> fmt::Debug for ty::InstantiatedPredicates<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "InstantiatedPredicates({:?})",
+ self.predicates)
}
}
-impl<'tcx> Repr<'tcx> for ast::Visibility {
- fn repr(&self, _tcx: &ctxt) -> String {
- format!("{:?}", *self)
- }
-}
-
-impl<'tcx> Repr<'tcx> for ty::BareFnTy<'tcx> {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- format!("BareFnTy {{unsafety: {}, abi: {}, sig: {}}}",
- self.unsafety,
- self.abi.to_string(),
- self.sig.repr(tcx))
+impl<'tcx> fmt::Debug for ty::ImplOrTraitItem<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ try!(write!(f, "ImplOrTraitItem("));
+ try!(match *self {
+ ty::ImplOrTraitItem::MethodTraitItem(ref i) => write!(f, "{:?}", i),
+ ty::ImplOrTraitItem::ConstTraitItem(ref i) => write!(f, "{:?}", i),
+ ty::ImplOrTraitItem::TypeTraitItem(ref i) => write!(f, "{:?}", i),
+ });
+ write!(f, ")")
}
}
-
-impl<'tcx> Repr<'tcx> for ty::FnSig<'tcx> {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- format!("fn{} -> {}", self.inputs.repr(tcx), self.output.repr(tcx))
+impl<'tcx> fmt::Display for ty::FnSig<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ try!(write!(f, "fn"));
+ fn_sig(f, &self.inputs, self.variadic, self.output)
}
}
-impl<'tcx> Repr<'tcx> for ty::FnOutput<'tcx> {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
+impl<'tcx> fmt::Debug for ty::MethodOrigin<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
- ty::FnConverging(ty) =>
- format!("FnConverging({0})", ty.repr(tcx)),
- ty::FnDiverging =>
- "FnDiverging".to_string()
- }
- }
-}
-
-impl<'tcx> Repr<'tcx> for ty::MethodCallee<'tcx> {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- format!("MethodCallee {{origin: {}, ty: {}, {}}}",
- self.origin.repr(tcx),
- self.ty.repr(tcx),
- self.substs.repr(tcx))
- }
-}
-
-impl<'tcx> Repr<'tcx> for ty::MethodOrigin<'tcx> {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- match self {
- &ty::MethodStatic(def_id) => {
- format!("MethodStatic({})", def_id.repr(tcx))
- }
- &ty::MethodStaticClosure(def_id) => {
- format!("MethodStaticClosure({})", def_id.repr(tcx))
- }
- &ty::MethodTypeParam(ref p) => {
- p.repr(tcx)
+ ty::MethodStatic(def_id) => {
+ write!(f, "MethodStatic({:?})", def_id)
}
- &ty::MethodTraitObject(ref p) => {
- p.repr(tcx)
+ ty::MethodStaticClosure(def_id) => {
+ write!(f, "MethodStaticClosure({:?})", def_id)
}
+ ty::MethodTypeParam(ref p) => write!(f, "{:?}", p),
+ ty::MethodTraitObject(ref p) => write!(f, "{:?}", p)
}
}
}
-impl<'tcx> Repr<'tcx> for ty::MethodParam<'tcx> {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- format!("MethodParam({},{})",
- self.trait_ref.repr(tcx),
- self.method_num)
- }
-}
-
-impl<'tcx> Repr<'tcx> for ty::MethodObject<'tcx> {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- format!("MethodObject({},{},{})",
- self.trait_ref.repr(tcx),
- self.method_num,
- self.vtable_index)
- }
-}
-
-impl<'tcx> Repr<'tcx> for ty::BuiltinBound {
- fn repr(&self, _tcx: &ctxt) -> String {
- format!("{:?}", *self)
- }
-}
-
-impl<'tcx> UserString<'tcx> for ty::BuiltinBound {
- fn user_string(&self, _tcx: &ctxt) -> String {
- match *self {
- ty::BoundSend => "Send".to_string(),
- ty::BoundSized => "Sized".to_string(),
- ty::BoundCopy => "Copy".to_string(),
- ty::BoundSync => "Sync".to_string(),
- }
- }
-}
-
-impl<'tcx> Repr<'tcx> for Span {
- fn repr(&self, tcx: &ctxt) -> String {
- tcx.sess.codemap().span_to_string(*self).to_string()
+impl<'tcx> fmt::Debug for ty::MethodParam<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "MethodParam({:?},{})",
+ self.trait_ref,
+ self.method_num)
}
}
-impl<'tcx, A:UserString<'tcx>> UserString<'tcx> for Rc<A> {
- fn user_string(&self, tcx: &ctxt<'tcx>) -> String {
- let this: &A = &**self;
- this.user_string(tcx)
- }
-}
-
-impl<'tcx> UserString<'tcx> for ty::ParamBounds<'tcx> {
- fn user_string(&self, tcx: &ctxt<'tcx>) -> String {
- let mut result = Vec::new();
- let s = self.builtin_bounds.user_string(tcx);
- if !s.is_empty() {
- result.push(s);
- }
- for n in &self.trait_bounds {
- result.push(n.user_string(tcx));
- }
- result.connect(" + ")
+impl<'tcx> fmt::Debug for ty::MethodObject<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "MethodObject({:?},{},{})",
+ self.trait_ref,
+ self.method_num,
+ self.vtable_index)
}
}
-impl<'tcx> Repr<'tcx> for ty::ExistentialBounds<'tcx> {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- let mut res = Vec::new();
+impl<'tcx> fmt::Debug for ty::ExistentialBounds<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let mut empty = true;
+ let mut maybe_continue = |f: &mut fmt::Formatter| {
+ if empty {
+ empty = false;
+ Ok(())
+ } else {
+ write!(f, " + ")
+ }
+ };
- let region_str = self.region_bound.repr(tcx);
+ let region_str = format!("{:?}", self.region_bound);
if !region_str.is_empty() {
- res.push(region_str);
+ try!(maybe_continue(f));
+ try!(write!(f, "{}", region_str));
}
for bound in &self.builtin_bounds {
- res.push(bound.repr(tcx));
+ try!(maybe_continue(f));
+ try!(write!(f, "{:?}", bound));
}
for projection_bound in &self.projection_bounds {
- res.push(projection_bound.repr(tcx));
+ try!(maybe_continue(f));
+ try!(write!(f, "{:?}", projection_bound));
}
- res.connect("+")
- }
-}
-
-impl<'tcx> UserString<'tcx> for ty::BuiltinBounds {
- fn user_string(&self, tcx: &ctxt) -> String {
- self.iter()
- .map(|bb| bb.user_string(tcx))
- .collect::<Vec<String>>()
- .connect("+")
- .to_string()
+ Ok(())
}
}
-impl<'tcx, T> UserString<'tcx> for ty::Binder<T>
- where T : UserString<'tcx> + TypeFoldable<'tcx>
-{
- fn user_string(&self, tcx: &ctxt<'tcx>) -> String {
- // Replace any anonymous late-bound regions with named
- // variants, using gensym'd identifiers, so that we can
- // clearly differentiate between named and unnamed regions in
- // the output. We'll probably want to tweak this over time to
- // decide just how much information to give.
- let mut names = Vec::new();
- let (unbound_value, _) = ty::replace_late_bound_regions(tcx, self, |br| {
- ty::ReLateBound(ty::DebruijnIndex::new(1), match br {
- ty::BrNamed(_, name) => {
- names.push(token::get_name(name));
- br
- }
- ty::BrAnon(_) |
- ty::BrFresh(_) |
- ty::BrEnv => {
- let name = token::gensym("'r");
- names.push(token::get_name(name));
- ty::BrNamed(ast_util::local_def(ast::DUMMY_NODE_ID), name)
- }
- })
- });
- let names: Vec<_> = names.iter().map(|s| &s[..]).collect();
-
- let value_str = unbound_value.user_string(tcx);
- if names.is_empty() {
- value_str
- } else {
- format!("for<{}> {}", names.connect(","), value_str)
+impl fmt::Display for ty::BuiltinBounds {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let mut bounds = self.iter();
+ if let Some(bound) = bounds.next() {
+ try!(write!(f, "{:?}", bound));
+ for bound in bounds {
+ try!(write!(f, " + {:?}", bound));
+ }
}
+ Ok(())
}
}
-impl<'tcx> UserString<'tcx> for ty::TraitRef<'tcx> {
- fn user_string(&self, tcx: &ctxt<'tcx>) -> String {
- let path_str = ty::item_path_str(tcx, self.def_id);
- parameterized(tcx, &path_str, self.substs, self.def_id, &[],
- || ty::lookup_trait_def(tcx, self.def_id).generics.clone())
+// The generic impl doesn't work yet because projections are not
+// normalized under HRTB.
+/*impl<T> fmt::Display for ty::Binder<T>
+ where T: fmt::Display + for<'a> ty::Lift<'a>,
+ for<'a> <T as ty::Lift<'a>>::Lifted: fmt::Display + TypeFoldable<'a>
+{
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self)))
}
-}
+}*/
-impl<'tcx> UserString<'tcx> for Ty<'tcx> {
- fn user_string(&self, tcx: &ctxt<'tcx>) -> String {
- ty_to_string(tcx, *self)
+impl<'tcx> fmt::Display for ty::Binder<ty::TraitRef<'tcx>> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self)))
}
}
-impl<'tcx> UserString<'tcx> for ast::Ident {
- fn user_string(&self, _tcx: &ctxt) -> String {
- token::get_name(self.name).to_string()
+impl<'tcx> fmt::Display for ty::Binder<ty::TraitPredicate<'tcx>> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self)))
}
}
-impl<'tcx> Repr<'tcx> for abi::Abi {
- fn repr(&self, _tcx: &ctxt) -> String {
- self.to_string()
+impl<'tcx> fmt::Display for ty::Binder<ty::EquatePredicate<'tcx>> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self)))
}
}
-impl<'tcx> UserString<'tcx> for abi::Abi {
- fn user_string(&self, _tcx: &ctxt) -> String {
- self.to_string()
+impl<'tcx> fmt::Display for ty::Binder<ty::ProjectionPredicate<'tcx>> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self)))
}
}
-impl<'tcx> Repr<'tcx> for ty::UpvarId {
- fn repr(&self, tcx: &ctxt) -> String {
- format!("UpvarId({};`{}`;{})",
- self.var_id,
- ty::local_var_name_str(tcx, self.var_id),
- self.closure_expr_id)
+impl<'tcx> fmt::Display for ty::Binder<ty::OutlivesPredicate<Ty<'tcx>, ty::Region>> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self)))
}
}
-impl<'tcx> Repr<'tcx> for ast::Mutability {
- fn repr(&self, _tcx: &ctxt) -> String {
- format!("{:?}", *self)
+impl fmt::Display for ty::Binder<ty::OutlivesPredicate<ty::Region, ty::Region>> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self)))
}
}
-impl<'tcx> Repr<'tcx> for ty::BorrowKind {
- fn repr(&self, _tcx: &ctxt) -> String {
- format!("{:?}", *self)
+impl<'tcx> fmt::Display for ty::TraitRef<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ parameterized(f, self.substs, self.def_id, &[],
+ |tcx| ty::lookup_trait_def(tcx, self.def_id).generics.clone())
}
}
-impl<'tcx> Repr<'tcx> for ty::UpvarBorrow {
- fn repr(&self, tcx: &ctxt) -> String {
- format!("UpvarBorrow({}, {})",
- self.kind.repr(tcx),
- self.region.repr(tcx))
- }
-}
-
-impl<'tcx> Repr<'tcx> for ty::UpvarCapture {
- fn repr(&self, tcx: &ctxt) -> String {
+impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
- ty::UpvarCapture::ByValue => format!("ByValue"),
- ty::UpvarCapture::ByRef(ref data) => format!("ByRef({})", data.repr(tcx)),
- }
- }
-}
-
-impl<'tcx> Repr<'tcx> for ty::IntVid {
- fn repr(&self, _tcx: &ctxt) -> String {
- format!("{:?}", self)
- }
-}
-
-impl<'tcx> Repr<'tcx> for ty::FloatVid {
- fn repr(&self, _tcx: &ctxt) -> String {
- format!("{:?}", self)
- }
-}
-
-impl<'tcx> Repr<'tcx> for ty::RegionVid {
- fn repr(&self, _tcx: &ctxt) -> String {
- format!("{:?}", self)
- }
-}
-
-impl<'tcx> Repr<'tcx> for ty::TyVid {
- fn repr(&self, _tcx: &ctxt) -> String {
- format!("{:?}", self)
- }
-}
-
-impl<'tcx> Repr<'tcx> for ty::IntVarValue {
- fn repr(&self, _tcx: &ctxt) -> String {
- format!("{:?}", *self)
- }
-}
+ TyBool => write!(f, "bool"),
+ TyChar => write!(f, "char"),
+ TyInt(t) => write!(f, "{}", ast_util::int_ty_to_string(t, None)),
+ TyUint(t) => write!(f, "{}", ast_util::uint_ty_to_string(t, None)),
+ TyFloat(t) => write!(f, "{}", ast_util::float_ty_to_string(t)),
+ TyBox(typ) => write!(f, "Box<{}>", typ),
+ TyRawPtr(ref tm) => {
+ write!(f, "*{} {}", match tm.mutbl {
+ ast::MutMutable => "mut",
+ ast::MutImmutable => "const",
+ }, tm.ty)
+ }
+ TyRef(r, ref tm) => {
+ try!(write!(f, "&"));
+ let s = r.to_string();
+ try!(write!(f, "{}", s));
+ if !s.is_empty() {
+ try!(write!(f, " "));
+ }
+ write!(f, "{}", tm)
+ }
+ TyTuple(ref tys) => {
+ try!(write!(f, "("));
+ let mut tys = tys.iter();
+ if let Some(&ty) = tys.next() {
+ try!(write!(f, "{},", ty));
+ if let Some(&ty) = tys.next() {
+ try!(write!(f, " {}", ty));
+ for &ty in tys {
+ try!(write!(f, ", {}", ty));
+ }
+ }
+ }
+ write!(f, ")")
+ }
+ TyBareFn(opt_def_id, ref bare_fn) => {
+ if bare_fn.unsafety == ast::Unsafety::Unsafe {
+ try!(write!(f, "unsafe "));
+ }
-impl<'tcx> Repr<'tcx> for ast::IntTy {
- fn repr(&self, _tcx: &ctxt) -> String {
- format!("{:?}", *self)
- }
-}
+ if bare_fn.abi != abi::Rust {
+ try!(write!(f, "extern {} ", bare_fn.abi));
+ }
-impl<'tcx> Repr<'tcx> for ast::UintTy {
- fn repr(&self, _tcx: &ctxt) -> String {
- format!("{:?}", *self)
- }
-}
+ try!(write!(f, "{}", bare_fn.sig.0));
-impl<'tcx> Repr<'tcx> for ast::FloatTy {
- fn repr(&self, _tcx: &ctxt) -> String {
- format!("{:?}", *self)
+ if let Some(def_id) = opt_def_id {
+ try!(write!(f, " {{{}}}", ty::tls::with(|tcx| {
+ ty::item_path_str(tcx, def_id)
+ })));
+ }
+ Ok(())
+ }
+ TyInfer(infer_ty) => write!(f, "{}", infer_ty),
+ TyError => write!(f, "[type error]"),
+ TyParam(ref param_ty) => write!(f, "{}", param_ty),
+ TyEnum(did, substs) | TyStruct(did, substs) => {
+ parameterized(f, substs, did, &[],
+ |tcx| ty::lookup_item_type(tcx, did).generics)
+ }
+ TyTrait(ref data) => write!(f, "{}", data),
+ ty::TyProjection(ref data) => write!(f, "{}", data),
+ TyStr => write!(f, "str"),
+ TyClosure(ref did, substs) => ty::tls::with(|tcx| {
+ try!(write!(f, "[closure"));
+ let closure_tys = tcx.closure_tys.borrow();
+ try!(closure_tys.get(did).map(|cty| &cty.sig).and_then(|sig| {
+ tcx.lift(&substs).map(|substs| sig.subst(tcx, substs))
+ }).map(|sig| {
+ fn_sig(f, &sig.0.inputs, false, sig.0.output)
+ }).unwrap_or_else(|| {
+ if did.krate == ast::LOCAL_CRATE {
+ try!(write!(f, " {:?}", tcx.map.span(did.node)));
+ }
+ Ok(())
+ }));
+ if verbose() {
+ try!(write!(f, " id={:?}", did));
+ }
+ write!(f, "]")
+ }),
+ TyArray(ty, sz) => write!(f, "[{}; {}]", ty, sz),
+ TySlice(ty) => write!(f, "[{}]", ty)
+ }
}
}
-impl<'tcx> Repr<'tcx> for ty::ExplicitSelfCategory {
- fn repr(&self, _: &ctxt) -> String {
- explicit_self_category_to_str(self).to_string()
+impl<'tcx> fmt::Display for ty::TyS<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{}", self.sty)
}
}
-impl<'tcx> UserString<'tcx> for ParamTy {
- fn user_string(&self, _tcx: &ctxt) -> String {
- format!("{}", token::get_name(self.name))
+impl fmt::Debug for ty::UpvarId {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "UpvarId({};`{}`;{})",
+ self.var_id,
+ ty::tls::with(|tcx| ty::local_var_name_str(tcx, self.var_id)),
+ self.closure_expr_id)
}
}
-impl<'tcx> Repr<'tcx> for ParamTy {
- fn repr(&self, tcx: &ctxt) -> String {
- let ident = self.user_string(tcx);
- format!("{}/{:?}.{}", ident, self.space, self.idx)
+impl fmt::Debug for ty::UpvarBorrow {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "UpvarBorrow({:?}, {:?})",
+ self.kind, self.region)
}
}
-impl<'tcx, A:Repr<'tcx>, B:Repr<'tcx>> Repr<'tcx> for (A,B) {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- let &(ref a, ref b) = self;
- format!("({},{})", a.repr(tcx), b.repr(tcx))
+impl fmt::Display for ty::InferTy {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let print_var_ids = verbose();
+ match *self {
+ ty::TyVar(ref vid) if print_var_ids => write!(f, "{:?}", vid),
+ ty::IntVar(ref vid) if print_var_ids => write!(f, "{:?}", vid),
+ ty::FloatVar(ref vid) if print_var_ids => write!(f, "{:?}", vid),
+ ty::TyVar(_) | ty::IntVar(_) | ty::FloatVar(_) => write!(f, "_"),
+ ty::FreshTy(v) => write!(f, "FreshTy({})", v),
+ ty::FreshIntTy(v) => write!(f, "FreshIntTy({})", v),
+ ty::FreshFloatTy(v) => write!(f, "FreshFloatTy({})", v)
+ }
}
}
-impl<'tcx, T:Repr<'tcx>> Repr<'tcx> for ty::Binder<T> {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- format!("Binder({})", self.0.repr(tcx))
+impl fmt::Display for ty::ExplicitSelfCategory {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.write_str(match *self {
+ ty::StaticExplicitSelfCategory => "static",
+ ty::ByValueExplicitSelfCategory => "self",
+ ty::ByReferenceExplicitSelfCategory(_, ast::MutMutable) => {
+ "&mut self"
+ }
+ ty::ByReferenceExplicitSelfCategory(_, ast::MutImmutable) => "&self",
+ ty::ByBoxExplicitSelfCategory => "Box<self>",
+ })
}
}
-impl<'tcx, S, K, V> Repr<'tcx> for HashMap<K, V, S>
- where K: Hash + Eq + Repr<'tcx>,
- V: Repr<'tcx>,
- S: HashState,
-{
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- format!("HashMap({})",
- self.iter()
- .map(|(k,v)| format!("{} => {}", k.repr(tcx), v.repr(tcx)))
- .collect::<Vec<String>>()
- .connect(", "))
+impl fmt::Display for ty::ParamTy {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{}", self.name)
}
}
-impl<'tcx, T, U> Repr<'tcx> for ty::OutlivesPredicate<T,U>
- where T : Repr<'tcx> + TypeFoldable<'tcx>,
- U : Repr<'tcx> + TypeFoldable<'tcx>,
-{
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- format!("OutlivesPredicate({}, {})",
- self.0.repr(tcx),
- self.1.repr(tcx))
+impl fmt::Debug for ty::ParamTy {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{}/{:?}.{}", self, self.space, self.idx)
}
}
-impl<'tcx, T, U> UserString<'tcx> for ty::OutlivesPredicate<T,U>
- where T : UserString<'tcx> + TypeFoldable<'tcx>,
- U : UserString<'tcx> + TypeFoldable<'tcx>,
+impl<'tcx, T, U> fmt::Display for ty::OutlivesPredicate<T,U>
+ where T: fmt::Display, U: fmt::Display
{
- fn user_string(&self, tcx: &ctxt<'tcx>) -> String {
- format!("{} : {}",
- self.0.user_string(tcx),
- self.1.user_string(tcx))
- }
-}
-
-impl<'tcx> Repr<'tcx> for ty::EquatePredicate<'tcx> {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- format!("EquatePredicate({}, {})",
- self.0.repr(tcx),
- self.1.repr(tcx))
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{} : {}", self.0, self.1)
}
}
-impl<'tcx> UserString<'tcx> for ty::EquatePredicate<'tcx> {
- fn user_string(&self, tcx: &ctxt<'tcx>) -> String {
- format!("{} == {}",
- self.0.user_string(tcx),
- self.1.user_string(tcx))
+impl<'tcx> fmt::Display for ty::EquatePredicate<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{} == {}", self.0, self.1)
}
}
-impl<'tcx> Repr<'tcx> for ty::TraitPredicate<'tcx> {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- format!("TraitPredicate({})",
- self.trait_ref.repr(tcx))
+impl<'tcx> fmt::Debug for ty::TraitPredicate<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "TraitPredicate({:?})",
+ self.trait_ref)
}
}
-impl<'tcx> UserString<'tcx> for ty::TraitPredicate<'tcx> {
- fn user_string(&self, tcx: &ctxt<'tcx>) -> String {
- format!("{} : {}",
- self.trait_ref.self_ty().user_string(tcx),
- self.trait_ref.user_string(tcx))
+impl<'tcx> fmt::Display for ty::TraitPredicate<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{} : {}",
+ self.trait_ref.self_ty(),
+ self.trait_ref)
}
}
-impl<'tcx> UserString<'tcx> for ty::ProjectionPredicate<'tcx> {
- fn user_string(&self, tcx: &ctxt<'tcx>) -> String {
- format!("{} == {}",
- self.projection_ty.user_string(tcx),
- self.ty.user_string(tcx))
+impl<'tcx> fmt::Debug for ty::ProjectionPredicate<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "ProjectionPredicate({:?}, {:?})",
+ self.projection_ty,
+ self.ty)
}
}
-impl<'tcx> Repr<'tcx> for ty::ProjectionTy<'tcx> {
- fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- format!("{}::{}",
- self.trait_ref.repr(tcx),
- self.item_name.repr(tcx))
+impl<'tcx> fmt::Display for ty::ProjectionPredicate<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{} == {}",
+ self.projection_ty,
+ self.ty)
}
}
-impl<'tcx> UserString<'tcx> for ty::ProjectionTy<'tcx> {
- fn user_string(&self, tcx: &ctxt<'tcx>) -> String {
- format!("<{} as {}>::{}",
- self.trait_ref.self_ty().user_string(tcx),
- self.trait_ref.user_string(tcx),
- self.item_name.user_string(tcx))
+impl<'tcx> fmt::Display for ty::ProjectionTy<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{:?}::{}",
+ self.trait_ref,
+ self.item_name)
}
}
-impl<'tcx> UserString<'tcx> for ty::Predicate<'tcx> {
- fn user_string(&self, tcx: &ctxt<'tcx>) -> String {
+impl<'tcx> fmt::Display for ty::Predicate<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
- ty::Predicate::Trait(ref data) => data.user_string(tcx),
- ty::Predicate::Equate(ref predicate) => predicate.user_string(tcx),
- ty::Predicate::RegionOutlives(ref predicate) => predicate.user_string(tcx),
- ty::Predicate::TypeOutlives(ref predicate) => predicate.user_string(tcx),
- ty::Predicate::Projection(ref predicate) => predicate.user_string(tcx),
+ ty::Predicate::Trait(ref data) => write!(f, "{}", data),
+ ty::Predicate::Equate(ref predicate) => write!(f, "{}", predicate),
+ ty::Predicate::RegionOutlives(ref predicate) => write!(f, "{}", predicate),
+ ty::Predicate::TypeOutlives(ref predicate) => write!(f, "{}", predicate),
+ ty::Predicate::Projection(ref predicate) => write!(f, "{}", predicate),
}
}
}
-
-impl<'tcx> Repr<'tcx> for ast::Unsafety {
- fn repr(&self, _: &ctxt<'tcx>) -> String {
- format!("{:?}", *self)
- }
-}
//! A helper class for dealing with static archives
use std::env;
+use std::ffi::OsString;
use std::fs::{self, File};
use std::io::prelude::*;
use std::io;
pub lib_search_paths: Vec<PathBuf>,
pub slib_prefix: String,
pub slib_suffix: String,
- pub maybe_ar_prog: Option<String>
+ pub ar_prog: String,
+ pub command_path: OsString,
}
pub struct Archive<'a> {
- handler: &'a ErrorHandler,
- dst: PathBuf,
- lib_search_paths: Vec<PathBuf>,
- slib_prefix: String,
- slib_suffix: String,
- maybe_ar_prog: Option<String>
+ config: ArchiveConfig<'a>,
}
/// Helper for adding many files to an archive with a single invocation of
should_update_symbols: bool,
}
-fn run_ar(handler: &ErrorHandler, maybe_ar_prog: &Option<String>,
- args: &str, cwd: Option<&Path>,
- paths: &[&Path]) -> Output {
- let ar = match *maybe_ar_prog {
- Some(ref ar) => &ar[..],
- None => "ar"
- };
- let mut cmd = Command::new(ar);
-
- cmd.arg(args).args(paths).stdout(Stdio::piped()).stderr(Stdio::piped());
- debug!("{:?}", cmd);
-
- match cwd {
- Some(p) => {
- cmd.current_dir(p);
- debug!("inside {:?}", p.display());
- }
- None => {}
- }
-
- match cmd.spawn() {
- Ok(prog) => {
- let o = prog.wait_with_output().unwrap();
- if !o.status.success() {
- handler.err(&format!("{:?} failed with: {}", cmd, o.status));
- handler.note(&format!("stdout ---\n{}",
- str::from_utf8(&o.stdout).unwrap()));
- handler.note(&format!("stderr ---\n{}",
- str::from_utf8(&o.stderr).unwrap())
- );
- handler.abort_if_errors();
- }
- o
- },
- Err(e) => {
- handler.err(&format!("could not exec `{}`: {}", &ar[..],
- e));
- handler.abort_if_errors();
- panic!("rustc::back::archive::run_ar() should not reach this point");
- }
- }
+enum Action<'a> {
+ Remove(&'a Path),
+ AddObjects(&'a [&'a PathBuf], bool),
+ UpdateSymbols,
}
pub fn find_library(name: &str, osprefix: &str, ossuffix: &str,
impl<'a> Archive<'a> {
fn new(config: ArchiveConfig<'a>) -> Archive<'a> {
- let ArchiveConfig { handler, dst, lib_search_paths, slib_prefix, slib_suffix,
- maybe_ar_prog } = config;
- Archive {
- handler: handler,
- dst: dst,
- lib_search_paths: lib_search_paths,
- slib_prefix: slib_prefix,
- slib_suffix: slib_suffix,
- maybe_ar_prog: maybe_ar_prog
- }
+ Archive { config: config }
}
/// Opens an existing static archive
pub fn open(config: ArchiveConfig<'a>) -> Archive<'a> {
let archive = Archive::new(config);
- assert!(archive.dst.exists());
+ assert!(archive.config.dst.exists());
archive
}
/// Removes a file from this archive
pub fn remove_file(&mut self, file: &str) {
- run_ar(self.handler, &self.maybe_ar_prog, "d", None, &[&self.dst, &Path::new(file)]);
+ self.run(None, Action::Remove(Path::new(file)));
}
/// Lists all files in an archive
pub fn files(&self) -> Vec<String> {
- let output = run_ar(self.handler, &self.maybe_ar_prog, "t", None, &[&self.dst]);
- let output = str::from_utf8(&output.stdout).unwrap();
- // use lines_any because windows delimits output with `\r\n` instead of
- // just `\n`
- output.lines_any().map(|s| s.to_string()).collect()
+ let archive = match ArchiveRO::open(&self.config.dst) {
+ Some(ar) => ar,
+ None => return Vec::new(),
+ };
+ let ret = archive.iter().filter_map(|child| child.name())
+ .map(|name| name.to_string())
+ .collect();
+ return ret;
}
/// Creates an `ArchiveBuilder` for adding files to this archive.
pub fn extend(self) -> ArchiveBuilder<'a> {
ArchiveBuilder::new(self)
}
+
+ fn run(&self, cwd: Option<&Path>, action: Action) -> Output {
+ let abs_dst = env::current_dir().unwrap().join(&self.config.dst);
+ let ar = &self.config.ar_prog;
+ let mut cmd = Command::new(ar);
+ cmd.env("PATH", &self.config.command_path);
+ cmd.stdout(Stdio::piped()).stderr(Stdio::piped());
+ self.prepare_ar_action(&mut cmd, &abs_dst, action);
+ info!("{:?}", cmd);
+
+ if let Some(p) = cwd {
+ cmd.current_dir(p);
+ info!("inside {:?}", p.display());
+ }
+
+ let handler = &self.config.handler;
+ match cmd.spawn() {
+ Ok(prog) => {
+ let o = prog.wait_with_output().unwrap();
+ if !o.status.success() {
+ handler.err(&format!("{:?} failed with: {}", cmd, o.status));
+ handler.note(&format!("stdout ---\n{}",
+ str::from_utf8(&o.stdout).unwrap()));
+ handler.note(&format!("stderr ---\n{}",
+ str::from_utf8(&o.stderr).unwrap()));
+ handler.abort_if_errors();
+ }
+ o
+ },
+ Err(e) => {
+ handler.err(&format!("could not exec `{}`: {}",
+ self.config.ar_prog, e));
+ handler.abort_if_errors();
+ panic!("rustc::back::archive::run() should not reach this point");
+ }
+ }
+ }
+
+ fn prepare_ar_action(&self, cmd: &mut Command, dst: &Path, action: Action) {
+ match action {
+ Action::Remove(file) => {
+ cmd.arg("d").arg(dst).arg(file);
+ }
+ Action::AddObjects(objs, update_symbols) => {
+ cmd.arg(if update_symbols {"crs"} else {"crS"})
+ .arg(dst)
+ .args(objs);
+ }
+ Action::UpdateSymbols => {
+ cmd.arg("s").arg(dst);
+ }
+ }
+ }
}
impl<'a> ArchiveBuilder<'a> {
/// search in the relevant locations for a library named `name`.
pub fn add_native_library(&mut self, name: &str) -> io::Result<()> {
let location = find_library(name,
- &self.archive.slib_prefix,
- &self.archive.slib_suffix,
- &self.archive.lib_search_paths,
- self.archive.handler);
+ &self.archive.config.slib_prefix,
+ &self.archive.config.slib_suffix,
+ &self.archive.config.lib_search_paths,
+ self.archive.config.handler);
self.add_archive(&location, name, |_| false)
}
pub fn build(self) -> Archive<'a> {
// Get an absolute path to the destination, so `ar` will work even
// though we run it from `self.work_dir`.
- let abs_dst = env::current_dir().unwrap().join(&self.archive.dst);
- assert!(!abs_dst.is_relative());
- let mut args = vec![&*abs_dst];
- let mut total_len = abs_dst.to_string_lossy().len();
+ let mut objects = Vec::new();
+ let mut total_len = self.archive.config.dst.to_string_lossy().len();
if self.members.is_empty() {
- // OSX `ar` does not allow using `r` with no members, but it does
- // allow running `ar s file.a` to update symbols only.
if self.should_update_symbols {
- run_ar(self.archive.handler, &self.archive.maybe_ar_prog,
- "s", Some(self.work_dir.path()), &args[..]);
+ self.archive.run(Some(self.work_dir.path()),
+ Action::UpdateSymbols);
}
return self.archive;
}
// string, not an array of strings.)
if total_len + len + 1 > ARG_LENGTH_LIMIT {
// Add the archive members seen so far, without updating the
- // symbol table (`S`).
- run_ar(self.archive.handler, &self.archive.maybe_ar_prog,
- "cruS", Some(self.work_dir.path()), &args[..]);
+ // symbol table.
+ self.archive.run(Some(self.work_dir.path()),
+ Action::AddObjects(&objects, false));
- args.clear();
- args.push(&abs_dst);
- total_len = abs_dst.to_string_lossy().len();
+ objects.clear();
+ total_len = self.archive.config.dst.to_string_lossy().len();
}
- args.push(member_name);
+ objects.push(member_name);
total_len += len + 1;
}
// Add the remaining archive members, and update the symbol table if
// necessary.
- let flags = if self.should_update_symbols { "crus" } else { "cruS" };
- run_ar(self.archive.handler, &self.archive.maybe_ar_prog,
- flags, Some(self.work_dir.path()), &args[..]);
+ self.archive.run(Some(self.work_dir.path()),
+ Action::AddObjects(&objects, self.should_update_symbols));
self.archive
}
};
if filename.contains(".SYMDEF") { continue }
if skip(filename) { continue }
+ let filename = Path::new(filename).file_name().unwrap()
+ .to_str().unwrap();
// Archives on unix systems typically do not have slashes in
// filenames as the `ar` utility generally only uses the last
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
- html_favicon_url = "http://www.rust-lang.org/favicon.ico",
+ html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/")]
#![feature(box_syntax)]
-#![feature(collections)]
-#![feature(core)]
+#![feature(fs_canonicalize)]
+#![feature(libc)]
+#![feature(path_ext)]
+#![feature(rand)]
#![feature(rustc_private)]
+#![feature(slice_bytes)]
#![feature(staged_api)]
-#![feature(rand)]
-#![feature(path_ext)]
#![feature(step_by)]
-#![feature(libc)]
-#![feature(fs_canonicalize)]
+#![feature(vec_push_all)]
#![cfg_attr(test, feature(test, rand))]
extern crate syntax;
impl Sha256 {
/// Construct a new instance of a SHA-256 digest.
+ /// Do not – under any circumstances – use this where timing attacks might be possible!
pub fn new() -> Sha256 {
Sha256 {
engine: Engine256::new(&H256)
executables: true,
morestack: true,
has_rpath: true,
- pre_link_args: vec!(
- "-L/usr/local/lib".to_string(),
- "-L/usr/local/lib/gcc46".to_string(),
- "-L/usr/local/lib/gcc44".to_string(),
- ),
.. Default::default()
}
pub fn opts() -> TargetOptions {
TargetOptions {
- linker: "cc".to_string(),
dynamic_linking: true,
executables: true,
morestack: true,
mod linux_base;
mod openbsd_base;
mod windows_base;
+mod windows_msvc_base;
/// Everything `rustc` knows about how to compile for a specific target.
///
pub struct TargetOptions {
/// Linker to invoke. Defaults to "cc".
pub linker: String,
+ /// Archive utility to use when managing archives. Defaults to "ar".
+ pub ar: String,
/// Linker arguments that are unconditionally passed *before* any
/// user-defined libraries.
pub pre_link_args: Vec<String>,
/// only really used for figuring out how to find libraries, since Windows uses its own
/// library naming convention. Defaults to false.
pub is_like_windows: bool,
+ pub is_like_msvc: bool,
/// Whether the target toolchain is like Android's. Only useful for compiling against Android.
/// Defaults to false.
pub is_like_android: bool,
pub linker_is_gnu: bool,
/// Whether the linker support rpaths or not. Defaults to false.
pub has_rpath: bool,
- /// Whether to disable linking to compiler-rt. Defaults to false, as LLVM will emit references
- /// to the functions that compiler-rt provides.
+ /// Whether to disable linking to compiler-rt. Defaults to false, as LLVM
+ /// will emit references to the functions that compiler-rt provides.
pub no_compiler_rt: bool,
- /// Dynamically linked executables can be compiled as position independent if the default
- /// relocation model of position independent code is not changed. This is a requirement to take
- /// advantage of ASLR, as otherwise the functions in the executable are not randomized and can
- /// be used during an exploit of a vulnerability in any code.
+ /// Dynamically linked executables can be compiled as position independent
+ /// if the default relocation model of position independent code is not
+ /// changed. This is a requirement to take advantage of ASLR, as otherwise
+ /// the functions in the executable are not randomized and can be used
+ /// during an exploit of a vulnerability in any code.
pub position_independent_executables: bool,
}
impl Default for TargetOptions {
- /// Create a set of "sane defaults" for any target. This is still incomplete, and if used for
- /// compilation, will certainly not work.
+ /// Create a set of "sane defaults" for any target. This is still
+ /// incomplete, and if used for compilation, will certainly not work.
fn default() -> TargetOptions {
TargetOptions {
linker: "cc".to_string(),
+ ar: "ar".to_string(),
pre_link_args: Vec::new(),
post_link_args: Vec::new(),
cpu: "generic".to_string(),
is_like_osx: false,
is_like_windows: false,
is_like_android: false,
+ is_like_msvc: false,
linker_is_gnu: false,
has_rpath: false,
no_compiler_rt: false,
// this is 1. ugly, 2. error prone.
- let handler = diagnostic::default_handler(diagnostic::Auto, None, true);
+ let handler = diagnostic::Handler::new(diagnostic::Auto, None, true);
let get_req_field = |name: &str| {
match obj.find(name)
}
key!(cpu);
+ key!(ar);
key!(linker);
key!(relocation_model);
key!(code_model);
armv7s_apple_ios,
x86_64_pc_windows_gnu,
- i686_pc_windows_gnu
+ i686_pc_windows_gnu,
+
+ x86_64_pc_windows_msvc
);
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use target::TargetOptions;
+use std::default::Default;
+
+pub fn opts() -> TargetOptions {
+ TargetOptions {
+ function_sections: true,
+ linker: "link.exe".to_string(),
+ // When taking a look at the value of this `ar` field, one might expect
+ // `lib.exe` to be the value here! The `lib.exe` program is the default
+ // tool for managing `.lib` archives on Windows, but unfortunately the
+ // compiler cannot use it.
+ //
+ // To recap, we use `ar` here to manage rlibs (which are just archives).
+ // LLVM does not expose bindings for modifying archives so we have to
+ // invoke this utility for write operations (e.g. deleting files, adding
+ // files, etc). Normally archives only have object files within them,
+ // but the compiler also uses archives for storing metadata and
+ // compressed bytecode, so we don't exactly fall within "normal use
+ // cases".
+ //
+ // MSVC's `lib.exe` tool by default will choke when adding a non-object
+ // file to an archive, which we do on a regular basis, making it
+ // inoperable for us. Luckily, however, LLVM has already rewritten `ar`
+ // in the form of `llvm-ar` which is built by default when we build
+ // LLVM. This tool, unlike `lib.exe`, works just fine with non-object
+ // files, so we use it instead.
+ //
+ // Note that there's a few caveats associated with this:
+ //
+ // * This still requires that the *linker* (the consumer of rlibs) will
+ // ignore non-object files. Thankfully `link.exe` on Windows does
+ // indeed ignore non-object files in archives.
+ // * This requires `llvm-ar.exe` to be distributed with the compiler
+ // itself, but we already make sure of this elsewhere.
+ //
+ // Perhaps one day we won't even need this tool at all and we'll just be
+ // able to make library calls into LLVM!
+ ar: "llvm-ar.exe".to_string(),
+ dynamic_linking: true,
+ executables: true,
+ dll_prefix: "".to_string(),
+ dll_suffix: ".dll".to_string(),
+ exe_suffix: ".exe".to_string(),
+ staticlib_prefix: "".to_string(),
+ staticlib_suffix: ".lib".to_string(),
+ morestack: false,
+ is_like_windows: true,
+ is_like_msvc: true,
+ pre_link_args: vec![
+ "/NOLOGO".to_string(),
+ "/NXCOMPAT".to_string(),
+ ],
+
+ .. Default::default()
+ }
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use target::Target;
+
+pub fn target() -> Target {
+ let mut base = super::windows_msvc_base::opts();
+ base.cpu = "x86-64".to_string();
+
+ Target {
+ // This is currently in sync with the specification for
+ // x86_64-pc-windows-gnu but there's a comment in that file questioning
+ // whether this is valid or not. Sounds like the two should stay in sync
+ // at least for now.
+ data_layout: "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-\
+ f32:32:32-f64:64:64-v64:64:64-v128:128:128-a:0:64-\
+ s0:64:64-f80:128:128-n8:16:32:64-S128".to_string(),
+ llvm_target: "x86_64-pc-windows-msvc".to_string(),
+ target_endian: "little".to_string(),
+ target_pointer_width: "64".to_string(),
+ arch: "x86_64".to_string(),
+ target_os: "windows".to_string(),
+ target_env: "msvc".to_string(),
+ options: base,
+ }
+}
#![feature(no_std)]
#![no_std]
#![unstable(feature = "rustc_private")]
-#![cfg_attr(test, feature(hash))]
+#![cfg_attr(test, feature(hash_default))]
//! A typesafe bitmask flag generator.
that was created. In general it holds that when a path is
lent, restrictions are issued for all the owning prefixes of that
path. In this case, the path `*x` owns the path `(*x).f` and,
-because `x` is an owned pointer, the path `x` owns the path `*x`.
+because `x` has ownership, the path `x` owns the path `*x`.
Therefore, borrowing `(*x).f` yields restrictions on both
`*x` and `x`.
### Checking mutability of owned content
-Fields and owned pointers inherit their mutability from
+Fields and boxes inherit their mutability from
their base expressions, so both of their rules basically
delegate the check to the base expression `LV`:
### Checking lifetime for owned content
-The lifetime of a field or owned pointer is the same as the lifetime
+The lifetime of a field or box is the same as the lifetime
of its owner:
```text
Because the mutability of owned referents is inherited, restricting an
owned referent is similar to restricting a field, in that it implies
-restrictions on the pointer. However, owned pointers have an important
+restrictions on the pointer. However, boxes have an important
twist: if the owner `LV` is mutated, that causes the owned referent
`*LV` to be freed! So whenever an owned referent `*LV` is borrowed, we
-must prevent the owned pointer `LV` from being mutated, which means
+must prevent the box `LV` from being mutated, which means
that we always add `MUTATE` and `CLAIM` to the restriction set imposed
on `LV`:
```
Clause (2) propagates the restrictions on the referent to the pointer
-itself. This is the same as with an owned pointer, though the
+itself. This is the same as with an box, though the
reasoning is mildly different. The basic goal in all cases is to
prevent the user from establishing another route to the same data. To
see what I mean, let's examine various cases of what can go wrong and
use rustc::middle::mem_categorization as mc;
use rustc::middle::region;
use rustc::middle::ty;
-use rustc::util::ppaux::Repr;
use syntax::ast;
use syntax::codemap::Span;
consume_span: Span,
cmt: mc::cmt<'tcx>,
mode: euv::ConsumeMode) {
- debug!("consume(consume_id={}, cmt={}, mode={:?})",
- consume_id, cmt.repr(self.tcx()), mode);
+ debug!("consume(consume_id={}, cmt={:?}, mode={:?})",
+ consume_id, cmt, mode);
self.consume_common(consume_id, consume_span, cmt, mode);
}
consume_pat: &ast::Pat,
cmt: mc::cmt<'tcx>,
mode: euv::ConsumeMode) {
- debug!("consume_pat(consume_pat={}, cmt={}, mode={:?})",
- consume_pat.repr(self.tcx()),
- cmt.repr(self.tcx()),
+ debug!("consume_pat(consume_pat={:?}, cmt={:?}, mode={:?})",
+ consume_pat,
+ cmt,
mode);
self.consume_common(consume_pat.id, consume_pat.span, cmt, mode);
bk: ty::BorrowKind,
loan_cause: euv::LoanCause)
{
- debug!("borrow(borrow_id={}, cmt={}, loan_region={:?}, \
+ debug!("borrow(borrow_id={}, cmt={:?}, loan_region={:?}, \
bk={:?}, loan_cause={:?})",
- borrow_id, cmt.repr(self.tcx()), loan_region,
+ borrow_id, cmt, loan_region,
bk, loan_cause);
match opt_loan_path(&cmt) {
assignee_cmt: mc::cmt<'tcx>,
mode: euv::MutateMode)
{
- debug!("mutate(assignment_id={}, assignee_cmt={})",
- assignment_id, assignee_cmt.repr(self.tcx()));
+ debug!("mutate(assignment_id={}, assignee_cmt={:?})",
+ assignment_id, assignee_cmt);
match opt_loan_path(&assignee_cmt) {
Some(lp) => {
//! Checks whether `old_loan` and `new_loan` can safely be issued
//! simultaneously.
- debug!("report_error_if_loans_conflict(old_loan={}, new_loan={})",
- old_loan.repr(self.tcx()),
- new_loan.repr(self.tcx()));
+ debug!("report_error_if_loans_conflict(old_loan={:?}, new_loan={:?})",
+ old_loan,
+ new_loan);
// Should only be called for loans that are in scope at the same time.
assert!(self.tcx().region_maps.scopes_intersect(old_loan.kill_scope,
//! prohibit `loan2`. Returns false if an error is reported.
debug!("report_error_if_loan_conflicts_with_restriction(\
- loan1={}, loan2={})",
- loan1.repr(self.tcx()),
- loan2.repr(self.tcx()));
+ loan1={:?}, loan2={:?})",
+ loan1,
+ loan2);
if compatible_borrow_kinds(loan1.kind, loan2.kind) {
return true;
use_path: &LoanPath<'tcx>,
borrow_kind: ty::BorrowKind)
-> UseError<'tcx> {
- debug!("analyze_restrictions_on_use(expr_id={}, use_path={})",
+ debug!("analyze_restrictions_on_use(expr_id={}, use_path={:?})",
self.tcx().map.node_to_string(expr_id),
- use_path.repr(self.tcx()));
+ use_path);
let mut ret = UseOk;
span: Span,
use_kind: MovedValueUseKind,
lp: &Rc<LoanPath<'tcx>>) {
- debug!("check_if_path_is_moved(id={}, use_kind={:?}, lp={})",
- id, use_kind, lp.repr(self.bccx.tcx));
+ debug!("check_if_path_is_moved(id={}, use_kind={:?}, lp={:?})",
+ id, use_kind, lp);
// FIXME (22079): if you find yourself tempted to cut and paste
// the body below and then specializing the error reporting,
}
LpExtend(ref lp_base, _, LpInterior(InteriorField(_))) => {
match lp_base.to_type().sty {
- ty::ty_struct(def_id, _) | ty::ty_enum(def_id, _) => {
+ ty::TyStruct(def_id, _) | ty::TyEnum(def_id, _) => {
if ty::has_dtor(self.tcx(), def_id) {
// In the case where the owner implements drop, then
// the path must be initialized to prevent a case of
assignment_span: Span,
assignee_cmt: mc::cmt<'tcx>,
mode: euv::MutateMode) {
- debug!("check_assignment(assignee_cmt={})", assignee_cmt.repr(self.tcx()));
+ debug!("check_assignment(assignee_cmt={:?})", assignee_cmt);
// Mutable values can be assigned, as long as they obey loans
// and aliasing restrictions:
//! `used_mut_nodes` table here.
loop {
- debug!("mark_variable_as_used_mut(cmt={})", cmt.repr(this.tcx()));
+ debug!("mark_variable_as_used_mut(cmt={:?})", cmt);
match cmt.cat.clone() {
mc::cat_upvar(mc::Upvar { id: ty::UpvarId { var_id: id, .. }, .. }) |
mc::cat_local(id) => {
//! Safety checks related to writes to aliasable, mutable locations
let guarantor = cmt.guarantor();
- debug!("check_for_aliasable_mutable_writes(cmt={}, guarantor={})",
- cmt.repr(this.tcx()), guarantor.repr(this.tcx()));
+ debug!("check_for_aliasable_mutable_writes(cmt={:?}, guarantor={:?})",
+ cmt, guarantor);
if let mc::cat_deref(ref b, _, mc::BorrowedPtr(ty::MutBorrow, _)) = guarantor.cat {
// Statically prohibit writes to `&mut` when aliasable
check_for_aliasability_violation(this, span, b.clone());
use borrowck::move_data::{MoveData, MovePathIndex};
use rustc::middle::ty;
use rustc::middle::mem_categorization as mc;
-use rustc::util::ppaux::{Repr, UserString};
+
use std::mem;
use std::rc::Rc;
use syntax::ast;
}
impl Fragment {
- fn loan_path_repr<'tcx>(&self, move_data: &MoveData<'tcx>, tcx: &ty::ctxt<'tcx>) -> String {
- let repr = |mpi| move_data.path_loan_path(mpi).repr(tcx);
+ fn loan_path_repr(&self, move_data: &MoveData) -> String {
+ let lp = |mpi| move_data.path_loan_path(mpi);
match *self {
- Just(mpi) => repr(mpi),
- AllButOneFrom(mpi) => format!("$(allbutone {})", repr(mpi)),
+ Just(mpi) => format!("{:?}", lp(mpi)),
+ AllButOneFrom(mpi) => format!("$(allbutone {:?})", lp(mpi)),
}
}
- fn loan_path_user_string<'tcx>(&self,
- move_data: &MoveData<'tcx>,
- tcx: &ty::ctxt<'tcx>) -> String {
- let user_string = |mpi| move_data.path_loan_path(mpi).user_string(tcx);
+ fn loan_path_user_string(&self, move_data: &MoveData) -> String {
+ let lp = |mpi| move_data.path_loan_path(mpi);
match *self {
- Just(mpi) => user_string(mpi),
- AllButOneFrom(mpi) => format!("$(allbutone {})", user_string(mpi)),
+ Just(mpi) => lp(mpi).to_string(),
+ AllButOneFrom(mpi) => format!("$(allbutone {})", lp(mpi)),
}
}
}
let instrument_all_paths = |kind, vec_rc: &Vec<MovePathIndex>| {
for (i, mpi) in vec_rc.iter().enumerate() {
- let render = || this.path_loan_path(*mpi).user_string(tcx);
+ let lp = || this.path_loan_path(*mpi);
if span_err {
- tcx.sess.span_err(sp, &format!("{}: `{}`", kind, render()));
+ tcx.sess.span_err(sp, &format!("{}: `{}`", kind, lp()));
}
if print {
- println!("id:{} {}[{}] `{}`", id, kind, i, render());
+ println!("id:{} {}[{}] `{}`", id, kind, i, lp());
}
}
};
let instrument_all_fragments = |kind, vec_rc: &Vec<Fragment>| {
for (i, f) in vec_rc.iter().enumerate() {
- let render = || f.loan_path_user_string(this, tcx);
+ let render = || f.loan_path_user_string(this);
if span_err {
tcx.sess.span_err(sp, &format!("{}: `{}`", kind, render()));
}
let mut assigned = mem::replace(&mut fragments.assigned_leaf_paths, vec![]);
let path_lps = |mpis: &[MovePathIndex]| -> Vec<String> {
- mpis.iter().map(|mpi| this.path_loan_path(*mpi).repr(tcx)).collect()
+ mpis.iter().map(|mpi| format!("{:?}", this.path_loan_path(*mpi))).collect()
};
let frag_lps = |fs: &[Fragment]| -> Vec<String> {
- fs.iter().map(|f| f.loan_path_repr(this, tcx)).collect()
+ fs.iter().map(|f| f.loan_path_repr(this)).collect()
};
// First, filter out duplicates
};
match (&parent_ty.sty, enum_variant_info) {
- (&ty::ty_tup(ref v), None) => {
+ (&ty::TyTuple(ref v), None) => {
let tuple_idx = match *origin_field_name {
mc::PositionalField(tuple_idx) => tuple_idx,
mc::NamedField(_) =>
- panic!("tuple type {} should not have named fields.",
- parent_ty.repr(tcx)),
+ panic!("tuple type {:?} should not have named fields.",
+ parent_ty),
};
let tuple_len = v.len();
for i in 0..tuple_len {
}
}
- (&ty::ty_struct(def_id, ref _substs), None) => {
+ (&ty::TyStruct(def_id, ref _substs), None) => {
let fields = ty::lookup_struct_fields(tcx, def_id);
match *origin_field_name {
mc::NamedField(ast_name) => {
}
}
- (&ty::ty_enum(enum_def_id, substs), ref enum_variant_info) => {
+ (&ty::TyEnum(enum_def_id, substs), ref enum_variant_info) => {
let variant_info = {
let mut variants = ty::substd_enum_variants(tcx, enum_def_id, substs);
match *enum_variant_info {
}
ref sty_and_variant_info => {
- let msg = format!("type {} ({:?}) is not fragmentable",
- parent_ty.repr(tcx), sty_and_variant_info);
+ let msg = format!("type {:?} ({:?}) is not fragmentable",
+ parent_ty, sty_and_variant_info);
let opt_span = origin_id.and_then(|id|tcx.map.opt_span(id));
tcx.sess.opt_span_bug(opt_span, &msg[..])
}
};
let new_lp_variant = LpExtend(parent, mc, loan_path_elem);
let new_lp = LoanPath::new(new_lp_variant, new_lp_type.unwrap());
- debug!("add_fragment_sibling_core(new_lp={}, origin_lp={})",
- new_lp.repr(tcx), origin_lp.repr(tcx));
+ debug!("add_fragment_sibling_core(new_lp={:?}, origin_lp={:?})",
+ new_lp, origin_lp);
let mp = this.move_path(tcx, Rc::new(new_lp));
// Do not worry about checking for duplicates here; we will sort
use rustc::middle::mem_categorization as mc;
use rustc::middle::mem_categorization::InteriorOffsetKind as Kind;
use rustc::middle::ty;
-use rustc::util::ppaux::Repr;
+
use std::rc::Rc;
use syntax::ast;
use syntax::codemap::Span;
cmt: mc::cmt<'tcx>,
mode: euv::MatchMode) {
let tcx = bccx.tcx;
- debug!("gather_match_variant(move_pat={}, cmt={}, mode={:?})",
- move_pat.id, cmt.repr(tcx), mode);
+ debug!("gather_match_variant(move_pat={}, cmt={:?}, mode={:?})",
+ move_pat.id, cmt, mode);
let opt_lp = opt_loan_path(&cmt);
match opt_lp {
move_data: &MoveData<'tcx>,
move_error_collector: &MoveErrorCollector<'tcx>,
move_info: GatherMoveInfo<'tcx>) {
- debug!("gather_move(move_id={}, cmt={})",
- move_info.id, move_info.cmt.repr(bccx.tcx));
+ debug!("gather_move(move_id={}, cmt={:?})",
+ move_info.id, move_info.cmt);
let potentially_illegal_move =
check_and_get_illegal_move_origin(bccx, &move_info.cmt);
match potentially_illegal_move {
Some(illegal_move_origin) => {
- debug!("illegal_move_origin={}", illegal_move_origin.repr(bccx.tcx));
+ debug!("illegal_move_origin={:?}", illegal_move_origin);
let error = MoveError::with_move_info(illegal_move_origin,
move_info.span_path_opt);
move_error_collector.add_error(error);
move_info.id, move_info.kind);
}
None => {
- // move from rvalue or unsafe pointer, hence ok
+ // move from rvalue or raw pointer, hence ok
}
}
}
mc::cat_interior(ref b, mc::InteriorField(_)) |
mc::cat_interior(ref b, mc::InteriorElement(Kind::Pattern, _)) => {
match b.ty.sty {
- ty::ty_struct(did, _) | ty::ty_enum(did, _) => {
+ ty::TyStruct(did, _) | ty::TyEnum(did, _) => {
if ty::has_dtor(bccx.tcx, did) {
Some(cmt.clone())
} else {
use rustc::middle::mem_categorization as mc;
use rustc::middle::region;
use rustc::middle::ty;
-use rustc::util::ppaux::Repr;
+
use syntax::ast;
use syntax::codemap::Span;
//! Reports error if `loan_region` is larger than S
//! where S is `item_scope` if `cmt` is an upvar,
//! and is scope of `cmt` otherwise.
- debug!("guarantee_lifetime(cmt={}, loan_region={})",
- cmt.repr(bccx.tcx), loan_region.repr(bccx.tcx));
+ debug!("guarantee_lifetime(cmt={:?}, loan_region={:?})",
+ cmt, loan_region);
let ctxt = GuaranteeLifetimeContext {bccx: bccx,
item_scope: item_scope,
span: span,
//! Main routine. Walks down `cmt` until we find the
//! "guarantor". Reports an error if `self.loan_region` is
//! larger than scope of `cmt`.
- debug!("guarantee_lifetime.check(cmt={}, loan_region={})",
- cmt.repr(self.bccx.tcx),
- self.loan_region.repr(self.bccx.tcx));
+ debug!("guarantee_lifetime.check(cmt={:?}, loan_region={:?})",
+ cmt,
+ self.loan_region);
match cmt.cat {
mc::cat_rvalue(..) |
use rustc::middle::mem_categorization as mc;
use rustc::middle::region;
use rustc::middle::ty;
-use rustc::util::ppaux::Repr;
+
use syntax::ast;
use syntax::codemap::Span;
use syntax::visit;
_consume_span: Span,
cmt: mc::cmt<'tcx>,
mode: euv::ConsumeMode) {
- debug!("consume(consume_id={}, cmt={}, mode={:?})",
- consume_id, cmt.repr(self.tcx()), mode);
+ debug!("consume(consume_id={}, cmt={:?}, mode={:?})",
+ consume_id, cmt, mode);
match mode {
euv::Move(move_reason) => {
matched_pat: &ast::Pat,
cmt: mc::cmt<'tcx>,
mode: euv::MatchMode) {
- debug!("matched_pat(matched_pat={}, cmt={}, mode={:?})",
- matched_pat.repr(self.tcx()),
- cmt.repr(self.tcx()),
+ debug!("matched_pat(matched_pat={:?}, cmt={:?}, mode={:?})",
+ matched_pat,
+ cmt,
mode);
if let mc::cat_downcast(..) = cmt.cat {
consume_pat: &ast::Pat,
cmt: mc::cmt<'tcx>,
mode: euv::ConsumeMode) {
- debug!("consume_pat(consume_pat={}, cmt={}, mode={:?})",
- consume_pat.repr(self.tcx()),
- cmt.repr(self.tcx()),
+ debug!("consume_pat(consume_pat={:?}, cmt={:?}, mode={:?})",
+ consume_pat,
+ cmt,
mode);
match mode {
bk: ty::BorrowKind,
loan_cause: euv::LoanCause)
{
- debug!("borrow(borrow_id={}, cmt={}, loan_region={:?}, \
+ debug!("borrow(borrow_id={}, cmt={:?}, loan_region={:?}, \
bk={:?}, loan_cause={:?})",
- borrow_id, cmt.repr(self.tcx()), loan_region,
+ borrow_id, cmt, loan_region,
bk, loan_cause);
self.guarantee_valid(borrow_id,
mode: euv::MutateMode)
{
let opt_lp = opt_loan_path(&assignee_cmt);
- debug!("mutate(assignment_id={}, assignee_cmt={}) opt_lp={:?}",
- assignment_id, assignee_cmt.repr(self.tcx()), opt_lp);
+ debug!("mutate(assignment_id={}, assignee_cmt={:?}) opt_lp={:?}",
+ assignment_id, assignee_cmt, opt_lp);
match opt_lp {
Some(lp) => {
/* Uniquely accessible path -- OK for `&` and `&mut` */
Ok(())
}
- (mc::Aliasability::FreelyAliasable(mc::AliasableStatic(safety)), ty::ImmBorrow) => {
- // Borrow of an immutable static item:
- match safety {
- mc::InteriorUnsafe => {
- // If the static item contains an Unsafe<T>, it has interior
- // mutability. In such cases, another phase of the compiler
- // will ensure that the type is `Sync` and then trans will
- // not put it in rodata, so this is ok to allow.
- Ok(())
- }
- mc::InteriorSafe => {
- // Immutable static can be borrowed, no problem.
- Ok(())
- }
- }
+ (mc::Aliasability::FreelyAliasable(mc::AliasableStatic), ty::ImmBorrow) => {
+ // Borrow of an immutable static item.
+ Ok(())
}
- (mc::Aliasability::FreelyAliasable(mc::AliasableStaticMut(..)), _) => {
+ (mc::Aliasability::FreelyAliasable(mc::AliasableStaticMut), _) => {
// Even touching a static mut is considered unsafe. We assume the
// user knows what they're doing in these cases.
Ok(())
req_kind: ty::BorrowKind,
loan_region: ty::Region,
cause: euv::LoanCause) {
- debug!("guarantee_valid(borrow_id={}, cmt={}, \
+ debug!("guarantee_valid(borrow_id={}, cmt={:?}, \
req_mutbl={:?}, loan_region={:?})",
borrow_id,
- cmt.repr(self.tcx()),
+ cmt,
req_kind,
loan_region);
}
};
- debug!("guarantee_valid(borrow_id={}), loan={}",
- borrow_id, loan.repr(self.tcx()));
+ debug!("guarantee_valid(borrow_id={}), loan={:?}",
+ borrow_id, loan);
// let loan_path = loan.loan_path;
// let loan_gen_scope = loan.gen_scope;
req_kind: ty::BorrowKind)
-> Result<(),()> {
//! Implements the M-* rules in README.md.
- debug!("check_mutability(cause={:?} cmt={} req_kind={:?}",
- cause, cmt.repr(bccx.tcx), req_kind);
+ debug!("check_mutability(cause={:?} cmt={:?} req_kind={:?}",
+ cause, cmt, req_kind);
match req_kind {
ty::UniqueImmBorrow | ty::ImmBorrow => {
match cmt.mutbl {
pub fn gather_loans_in_static_initializer(bccx: &mut BorrowckCtxt, expr: &ast::Expr) {
- debug!("gather_loans_in_static_initializer(expr={})", expr.repr(bccx.tcx));
+ debug!("gather_loans_in_static_initializer(expr={:?})", expr);
let mut sicx = StaticInitializerCtxt {
bccx: bccx
use rustc::middle::mem_categorization as mc;
use rustc::middle::mem_categorization::InteriorOffsetKind as Kind;
use rustc::middle::ty;
-use rustc::util::ppaux::UserString;
use std::cell::RefCell;
use syntax::ast;
use syntax::codemap;
for ge in &mut *grouped_errors {
if move_from_id == ge.move_from.id && error.move_to.is_some() {
debug!("appending move_to to list");
- ge.move_to_places.extend(move_to.into_iter());
+ ge.move_to_places.extend(move_to);
return
}
}
bccx.span_err(move_from.span,
&format!("cannot move out of type `{}`, \
a non-copy fixed-size array",
- b.ty.user_string(bccx.tcx)));
+ b.ty));
}
}
mc::cat_downcast(ref b, _) |
mc::cat_interior(ref b, mc::InteriorField(_)) => {
match b.ty.sty {
- ty::ty_struct(did, _) |
- ty::ty_enum(did, _) if ty::has_dtor(bccx.tcx, did) => {
+ ty::TyStruct(did, _) |
+ ty::TyEnum(did, _) if ty::has_dtor(bccx.tcx, did) => {
bccx.span_err(
move_from.span,
&format!("cannot move out of type `{}`, \
which defines the `Drop` trait",
- b.ty.user_string(bccx.tcx)));
+ b.ty));
},
_ => {
bccx.span_bug(move_from.span, "this path should not cause illegal move")
use rustc::middle::expr_use_visitor as euv;
use rustc::middle::mem_categorization as mc;
use rustc::middle::ty;
-use rustc::util::ppaux::Repr;
use syntax::codemap::Span;
use borrowck::ToInteriorKind;
impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> {
fn restrict(&self,
cmt: mc::cmt<'tcx>) -> RestrictionResult<'tcx> {
- debug!("restrict(cmt={})", cmt.repr(self.bccx.tcx));
+ debug!("restrict(cmt={:?})", cmt);
let new_lp = |v: LoanPathKind<'tcx>| Rc::new(LoanPath::new(v, cmt.ty));
mc::Unique => {
// R-Deref-Send-Pointer
//
- // When we borrow the interior of an owned pointer, we
+ // When we borrow the interior of a box, we
// cannot permit the base to be mutated, because that
// would cause the unique pointer to be freed.
//
}
}
}
- // Borrowck is not relevant for unsafe pointers
+ // Borrowck is not relevant for raw pointers
mc::UnsafePtr(..) => Safe
}
}
use self::InteriorKind::*;
+use rustc::ast_map;
+use rustc::ast_map::blocks::{FnLikeNode, FnParts};
use rustc::middle::cfg;
use rustc::middle::dataflow::DataFlowContext;
use rustc::middle::dataflow::BitwiseOperator;
use rustc::middle::dataflow::DataFlowOperator;
use rustc::middle::dataflow::KillFrom;
use rustc::middle::expr_use_visitor as euv;
-use rustc::middle::mem_categorization as mc;
use rustc::middle::free_region::FreeRegionMap;
+use rustc::middle::infer::error_reporting::note_and_explain_region;
+use rustc::middle::mem_categorization as mc;
use rustc::middle::region;
use rustc::middle::ty::{self, Ty};
-use rustc::util::ppaux::{note_and_explain_region, Repr, UserString};
+
+use std::fmt;
use std::mem;
use std::rc::Rc;
-use std::string::String;
use syntax::ast;
-use syntax::ast_map;
-use syntax::ast_map::blocks::{FnLikeNode, FnParts};
use syntax::ast_util;
use syntax::codemap::Span;
use syntax::parse::token;
}
}
-#[derive(Eq, Hash, Debug)]
+#[derive(Eq, Hash)]
pub struct LoanPath<'tcx> {
kind: LoanPathKind<'tcx>,
ty: ty::Ty<'tcx>,
// information that is not relevant to loan-path analysis. (In
// particular, the distinction between how precisely a array-element
// is tracked is irrelevant here.)
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub enum InteriorKind {
InteriorField(mc::FieldName),
InteriorElement(mc::ElementKind),
let (ol, moved_lp_msg) = match the_move.kind {
move_data::Declared => {
- self.tcx.sess.span_err(
- use_span,
- &format!("{} of possibly uninitialized variable: `{}`",
- verb,
- self.loan_path_to_string(lp)));
+ span_err!(
+ self.tcx.sess, use_span, E0381,
+ "{} of possibly uninitialized variable: `{}`",
+ verb,
+ self.loan_path_to_string(lp));
+
(self.loan_path_to_string(moved_lp),
String::new())
}
let msg = if !has_fork && partial { "partially " }
else if has_fork && !has_common { "collaterally "}
else { "" };
- self.tcx.sess.span_err(
- use_span,
- &format!("{} of {}moved value: `{}`",
- verb,
- msg,
- nl));
+ span_err!(
+ self.tcx.sess, use_span, E0382,
+ "{} of {}moved value: `{}`",
+ verb, msg, nl);
(ol, moved_lp_msg)
}
};
which is {}",
ol,
moved_lp_msg,
- expr_ty.user_string(self.tcx),
+ expr_ty,
suggestion));
} else {
self.tcx.sess.span_note(
&format!("`{}` moved here{} because it has type `{}`, which is {}",
ol,
moved_lp_msg,
- expr_ty.user_string(self.tcx),
+ expr_ty,
suggestion));
}
}
which is moved by default",
ol,
moved_lp_msg,
- pat_ty.user_string(self.tcx)));
+ pat_ty));
self.tcx.sess.fileline_help(span,
"use `ref` to override");
}
has type `{}`, which is {}",
ol,
moved_lp_msg,
- expr_ty.user_string(self.tcx),
+ expr_ty,
suggestion));
self.tcx.sess.fileline_help(expr_span, help);
}
&self,
span: Span,
lp: &LoanPath<'tcx>) {
- self.tcx
- .sess
- .span_err(span,
- &format!("partial reinitialization of uninitialized \
- structure `{}`",
- self.loan_path_to_string(lp)));
+ span_err!(
+ self.tcx.sess, span, E0383,
+ "partial reinitialization of uninitialized structure `{}`",
+ self.loan_path_to_string(lp));
}
pub fn report_reassigned_immutable_variable(&self,
lp: &LoanPath<'tcx>,
assign:
&move_data::Assignment) {
- self.tcx.sess.span_err(
- span,
- &format!("re-assignment of immutable variable `{}`",
- self.loan_path_to_string(lp)));
+ span_err!(
+ self.tcx.sess, span, E0384,
+ "re-assignment of immutable variable `{}`",
+ self.loan_path_to_string(lp));
self.tcx.sess.span_note(assign.span, "prior assignment occurs here");
}
match cause {
mc::AliasableOther => {
- self.tcx.sess.span_err(
- span,
- &format!("{} in an aliasable location",
- prefix));
+ span_err!(
+ self.tcx.sess, span, E0385,
+ "{} in an aliasable location", prefix);
}
mc::AliasableReason::UnaliasableImmutable => {
- self.tcx.sess.span_err(
- span,
- &format!("{} in an immutable container",
- prefix));
+ span_err!(
+ self.tcx.sess, span, E0386,
+ "{} in an immutable container", prefix);
}
mc::AliasableClosure(id) => {
- self.tcx.sess.span_err(span,
- &format!("{} in a captured outer \
- variable in an `Fn` closure", prefix));
+ span_err!(
+ self.tcx.sess, span, E0387,
+ "{} in a captured outer variable in an `Fn` closure", prefix);
if let BorrowViolation(euv::ClosureCapture(_)) = kind {
// The aliasability violation with closure captures can
// happen for nested closures, so we know the enclosing
}
mc::AliasableStatic(..) |
mc::AliasableStaticMut(..) => {
- self.tcx.sess.span_err(
- span,
- &format!("{} in a static location", prefix));
+ span_err!(
+ self.tcx.sess, span, E0388,
+ "{} in a static location", prefix);
}
mc::AliasableBorrowed => {
- self.tcx.sess.span_err(
- span,
- &format!("{} in a `&` reference", prefix));
+ span_err!(
+ self.tcx.sess, span, E0389,
+ "{} in a `&` reference", prefix);
}
}
"reference must be valid for ",
sub_scope,
"...");
- let suggestion = if is_statement_scope(self.tcx, super_scope) {
- Some("consider using a `let` binding to increase its lifetime")
- } else {
- None
- };
- let span = note_and_explain_region(
+ note_and_explain_region(
self.tcx,
"...but borrowed value is only valid for ",
super_scope,
"");
- match (span, suggestion) {
- (_, None) => {},
- (Some(span), Some(msg)) => self.tcx.sess.span_help(span, msg),
- (None, Some(msg)) => self.tcx.sess.help(msg),
+ if let Some(span) = statement_scope_span(self.tcx, super_scope) {
+ self.tcx.sess.span_help(span,
+ "consider using a `let` binding to increase its lifetime");
}
}
}
}
-fn is_statement_scope(tcx: &ty::ctxt, region: ty::Region) -> bool {
- match region {
- ty::ReScope(scope) => {
- match tcx.map.find(scope.node_id()) {
- Some(ast_map::NodeStmt(_)) => true,
- _ => false
- }
- }
- _ => false
- }
+fn statement_scope_span(tcx: &ty::ctxt, region: ty::Region) -> Option<Span> {
+ match region {
+ ty::ReScope(scope) => {
+ match tcx.map.find(scope.node_id()) {
+ Some(ast_map::NodeStmt(stmt)) => Some(stmt.span),
+ _ => None
+ }
+ }
+ _ => None
+ }
}
impl BitwiseOperator for LoanDataFlowOperator {
}
}
-impl<'tcx> Repr<'tcx> for InteriorKind {
- fn repr(&self, _tcx: &ty::ctxt<'tcx>) -> String {
+impl<'tcx> fmt::Debug for InteriorKind {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
- InteriorField(mc::NamedField(fld)) =>
- format!("{}", token::get_name(fld)),
- InteriorField(mc::PositionalField(i)) => format!("#{}", i),
- InteriorElement(..) => "[]".to_string(),
+ InteriorField(mc::NamedField(fld)) => write!(f, "{}", fld),
+ InteriorField(mc::PositionalField(i)) => write!(f, "#{}", i),
+ InteriorElement(..) => write!(f, "[]"),
}
}
}
-impl<'tcx> Repr<'tcx> for Loan<'tcx> {
- fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
- format!("Loan_{}({}, {:?}, {:?}-{:?}, {})",
- self.index,
- self.loan_path.repr(tcx),
- self.kind,
- self.gen_scope,
- self.kill_scope,
- self.restricted_paths.repr(tcx))
+impl<'tcx> fmt::Debug for Loan<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "Loan_{}({:?}, {:?}, {:?}-{:?}, {:?})",
+ self.index,
+ self.loan_path,
+ self.kind,
+ self.gen_scope,
+ self.kill_scope,
+ self.restricted_paths)
}
}
-impl<'tcx> Repr<'tcx> for LoanPath<'tcx> {
- fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
+impl<'tcx> fmt::Debug for LoanPath<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.kind {
LpVar(id) => {
- format!("$({})", tcx.map.node_to_string(id))
+ write!(f, "$({})", ty::tls::with(|tcx| tcx.map.node_to_string(id)))
}
LpUpvar(ty::UpvarId{ var_id, closure_expr_id }) => {
- let s = tcx.map.node_to_string(var_id);
- format!("$({} captured by id={})", s, closure_expr_id)
+ let s = ty::tls::with(|tcx| tcx.map.node_to_string(var_id));
+ write!(f, "$({} captured by id={})", s, closure_expr_id)
}
LpDowncast(ref lp, variant_def_id) => {
let variant_str = if variant_def_id.krate == ast::LOCAL_CRATE {
- ty::item_path_str(tcx, variant_def_id)
+ ty::tls::with(|tcx| ty::item_path_str(tcx, variant_def_id))
} else {
- variant_def_id.repr(tcx)
+ format!("{:?}", variant_def_id)
};
- format!("({}{}{})", lp.repr(tcx), DOWNCAST_PRINTED_OPERATOR, variant_str)
+ write!(f, "({:?}{}{})", lp, DOWNCAST_PRINTED_OPERATOR, variant_str)
}
LpExtend(ref lp, _, LpDeref(_)) => {
- format!("{}.*", lp.repr(tcx))
+ write!(f, "{:?}.*", lp)
}
LpExtend(ref lp, _, LpInterior(ref interior)) => {
- format!("{}.{}", lp.repr(tcx), interior.repr(tcx))
+ write!(f, "{:?}.{:?}", lp, interior)
}
}
}
}
-impl<'tcx> UserString<'tcx> for LoanPath<'tcx> {
- fn user_string(&self, tcx: &ty::ctxt<'tcx>) -> String {
+impl<'tcx> fmt::Display for LoanPath<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.kind {
LpVar(id) => {
- format!("$({})", tcx.map.node_to_user_string(id))
+ write!(f, "$({})", ty::tls::with(|tcx| tcx.map.node_to_user_string(id)))
}
LpUpvar(ty::UpvarId{ var_id, closure_expr_id: _ }) => {
- let s = tcx.map.node_to_user_string(var_id);
- format!("$({} captured by closure)", s)
+ let s = ty::tls::with(|tcx| tcx.map.node_to_user_string(var_id));
+ write!(f, "$({} captured by closure)", s)
}
LpDowncast(ref lp, variant_def_id) => {
let variant_str = if variant_def_id.krate == ast::LOCAL_CRATE {
- ty::item_path_str(tcx, variant_def_id)
+ ty::tls::with(|tcx| ty::item_path_str(tcx, variant_def_id))
} else {
- variant_def_id.repr(tcx)
+ format!("{:?}", variant_def_id)
};
- format!("({}{}{})", lp.user_string(tcx), DOWNCAST_PRINTED_OPERATOR, variant_str)
+ write!(f, "({}{}{})", lp, DOWNCAST_PRINTED_OPERATOR, variant_str)
}
LpExtend(ref lp, _, LpDeref(_)) => {
- format!("{}.*", lp.user_string(tcx))
+ write!(f, "{}.*", lp)
}
LpExtend(ref lp, _, LpInterior(ref interior)) => {
- format!("{}.{}", lp.user_string(tcx), interior.repr(tcx))
+ write!(f, "{}.{:?}", lp, interior)
}
}
}
use rustc::middle::expr_use_visitor as euv;
use rustc::middle::ty;
use rustc::util::nodemap::{FnvHashMap, NodeSet};
-use rustc::util::ppaux::Repr;
+
use std::cell::RefCell;
use std::rc::Rc;
use std::usize;
}
};
- debug!("move_path(lp={}, index={:?})",
- lp.repr(tcx),
+ debug!("move_path(lp={:?}, index={:?})",
+ lp,
index);
assert_eq!(index.get(), self.paths.borrow().len() - 1);
lp: Rc<LoanPath<'tcx>>,
id: ast::NodeId,
kind: MoveKind) {
- debug!("add_move(lp={}, id={}, kind={:?})",
- lp.repr(tcx),
+ debug!("add_move(lp={:?}, id={}, kind={:?})",
+ lp,
id,
kind);
span: Span,
assignee_id: ast::NodeId,
mode: euv::MutateMode) {
- debug!("add_assignment(lp={}, assign_id={}, assignee_id={}",
- lp.repr(tcx), assign_id, assignee_id);
+ debug!("add_assignment(lp={:?}, assign_id={}, assignee_id={}",
+ lp, assign_id, assignee_id);
let path_index = self.move_path(tcx, lp.clone());
};
if self.is_var_path(path_index) {
- debug!("add_assignment[var](lp={}, assignment={}, path_index={:?})",
- lp.repr(tcx), self.var_assignments.borrow().len(), path_index);
+ debug!("add_assignment[var](lp={:?}, assignment={}, path_index={:?})",
+ lp, self.var_assignments.borrow().len(), path_index);
self.var_assignments.borrow_mut().push(assignment);
} else {
- debug!("add_assignment[path](lp={}, path_index={:?})",
- lp.repr(tcx), path_index);
+ debug!("add_assignment[path](lp={:?}, path_index={:?})",
+ lp, path_index);
self.path_assignments.borrow_mut().push(assignment);
}
pattern_id: ast::NodeId,
base_lp: Rc<LoanPath<'tcx>>,
mode: euv::MatchMode) {
- debug!("add_variant_match(lp={}, pattern_id={})",
- lp.repr(tcx), pattern_id);
+ debug!("add_variant_match(lp={:?}, pattern_id={})",
+ lp, pattern_id);
let path_index = self.move_path(tcx, lp.clone());
let base_path_index = self.move_path(tcx, base_lp.clone());
KillFrom::Execution, dfcx_moves);
}
- for assignment in &*self.path_assignments.borrow() {
+ for assignment in self.path_assignments.borrow().iter() {
self.kill_moves(assignment.path, assignment.id,
KillFrom::Execution, dfcx_moves);
}
// Kill all moves related to a variable `x` when
// it goes out of scope:
- for path in &*self.paths.borrow() {
+ for path in self.paths.borrow().iter() {
match path.loan_path.kind {
LpVar(..) | LpUpvar(..) | LpDowncast(..) => {
let kill_scope = path.loan_path.kill_scope(tcx);
#![allow(non_snake_case)]
+register_long_diagnostics! {
+
+E0381: r##"
+It is not allowed to use or capture an uninitialized variable. For example:
+
+```
+fn main() {
+ let x: i32;
+ let y = x; // error, use of possibly uninitialized variable
+```
+
+To fix this, ensure that any declared variables are initialized before being
+used.
+"##
+
+}
+
register_diagnostics! {
- E0373 // closure may outlive current fn, but it borrows {}, which is owned by current fn
+ E0373, // closure may outlive current fn, but it borrows {}, which is owned by current fn
+ E0382, // use of partially/collaterally moved value
+ E0383, // partial reinitialization of uninitialized structure
+ E0384, // reassignment of immutable variable
+ E0385, // {} in an aliasable location
+ E0386, // {} in an immutable container
+ E0387, // {} in a captured outer variable in an `Fn` closure
+ E0388, // {} in a static location
+ E0389 // {} in a `&` reference
}
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
- html_favicon_url = "http://www.rust-lang.org/favicon.ico",
+ html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/")]
#![allow(non_camel_case_types)]
pub mod graphviz;
-#[cfg(stage0)]
-__build_diagnostic_array! { DIAGNOSTICS }
-#[cfg(not(stage0))]
__build_diagnostic_array! { librustc_borrowck, DIAGNOSTICS }
}
impl<'g, N:Debug, E:Debug> Iterator for DepthFirstTraversal<'g, N, E> {
- type Item = &'g N;
+ type Item = NodeIndex;
- fn next(&mut self) -> Option<&'g N> {
+ fn next(&mut self) -> Option<NodeIndex> {
while let Some(idx) = self.stack.pop() {
if !self.visited.insert(idx.node_id()) {
continue;
}
}
- return Some(self.graph.node_data(idx));
+ return Some(idx);
}
return None;
use rustc::session::Session;
use rustc::session::config::{self, Input, OutputFilenames};
use rustc::session::search_paths::PathKind;
+use rustc::ast_map;
use rustc::lint;
use rustc::metadata;
use rustc::metadata::creader::CrateReader;
use serialize::json;
use std::env;
-use std::ffi::OsString;
+use std::ffi::{OsString, OsStr};
use std::fs;
use std::io::{self, Write};
use std::path::{Path, PathBuf};
use syntax::ast;
-use syntax::ast_map;
use syntax::attr;
use syntax::attr::AttrMetaMethods;
use syntax::diagnostics;
// We need nested scopes here, because the intermediate results can keep
// large chunks of memory alive and we want to free them as soon as
// possible to keep the peak memory usage low
- let (outputs, trans, sess) = {
+ let (sess, result) = {
let (outputs, expanded_crate, id) = {
let krate = phase_1_parse_input(&sess, cfg, input);
&ast_map.krate(),
&id[..]));
- let analysis = phase_3_run_analysis_passes(sess,
- ast_map,
- &arenas,
- id,
- control.make_glob_map);
-
- controller_entry_point!(after_analysis,
- analysis.ty_cx.sess,
- CompileState::state_after_analysis(input,
- &analysis.ty_cx.sess,
- outdir,
- analysis.ty_cx.map.krate(),
- &analysis,
- &analysis.ty_cx));
-
- if log_enabled!(::log::INFO) {
- println!("Pre-trans");
- analysis.ty_cx.print_debug_stats();
- }
- let (tcx, trans) = phase_4_translate_to_llvm(analysis);
+ phase_3_run_analysis_passes(sess,
+ ast_map,
+ &arenas,
+ id,
+ control.make_glob_map,
+ |tcx, analysis| {
+
+ {
+ let state = CompileState::state_after_analysis(input,
+ &tcx.sess,
+ outdir,
+ tcx.map.krate(),
+ &analysis,
+ tcx);
+ (control.after_analysis.callback)(state);
+
+ tcx.sess.abort_if_errors();
+ if control.after_analysis.stop == Compilation::Stop {
+ return Err(());
+ }
+ }
- if log_enabled!(::log::INFO) {
- println!("Post-trans");
- tcx.print_debug_stats();
- }
+ if log_enabled!(::log::INFO) {
+ println!("Pre-trans");
+ tcx.print_debug_stats();
+ }
+ let trans = phase_4_translate_to_llvm(tcx, analysis);
- // Discard interned strings as they are no longer required.
- token::get_ident_interner().clear();
+ if log_enabled!(::log::INFO) {
+ println!("Post-trans");
+ tcx.print_debug_stats();
+ }
+
+ // Discard interned strings as they are no longer required.
+ token::get_ident_interner().clear();
- (outputs, trans, tcx.sess)
+ Ok((outputs, trans))
+ })
};
+
+ let (outputs, trans) = if let Ok(out) = result {
+ out
+ } else {
+ return;
+ };
+
phase_5_run_llvm_passes(&sess, &trans, &outputs);
controller_entry_point!(after_llvm,
pub out_dir: Option<&'a Path>,
pub expanded_crate: Option<&'a ast::Crate>,
pub ast_map: Option<&'a ast_map::Map<'ast>>,
- pub analysis: Option<&'a ty::CrateAnalysis<'tcx>>,
+ pub analysis: Option<&'a ty::CrateAnalysis>,
pub tcx: Option<&'a ty::ctxt<'tcx>>,
pub trans: Option<&'a trans::CrateTranslation>,
}
session: &'a Session,
out_dir: &'a Option<PathBuf>,
expanded_crate: &'a ast::Crate,
- analysis: &'a ty::CrateAnalysis<'tcx>,
+ analysis: &'a ty::CrateAnalysis,
tcx: &'a ty::ctxt<'tcx>)
-> CompileState<'a, 'ast, 'tcx> {
CompileState {
}
});
- let Registry { syntax_exts, lint_passes, lint_groups, llvm_passes, .. } = registry;
+ let Registry { syntax_exts, lint_passes, lint_groups,
+ llvm_passes, attributes, .. } = registry;
{
let mut ls = sess.lint_store.borrow_mut();
}
*sess.plugin_llvm_passes.borrow_mut() = llvm_passes;
+ *sess.plugin_attributes.borrow_mut() = attributes.clone();
}
// Lint plugins are registered; now we can process command line flags.
let mut new_path = sess.host_filesearch(PathKind::All)
.get_dylib_search_paths();
new_path.extend(env::split_paths(&_old_path));
- env::set_var("PATH", &env::join_paths(new_path.iter()).unwrap());
+ env::set_var("PATH", &env::join_paths(new_path).unwrap());
}
let features = sess.features.borrow();
let cfg = syntax::ext::expand::ExpansionConfig {
let features =
syntax::feature_gate::check_crate(sess.codemap(),
&sess.parse_sess.span_diagnostic,
- &krate);
+ &krate, &attributes,
+ sess.opts.unstable_features);
*sess.features.borrow_mut() = features;
sess.abort_if_errors();
});
let features =
syntax::feature_gate::check_crate(sess.codemap(),
&sess.parse_sess.span_diagnostic,
- &krate);
+ &krate, &attributes,
+ sess.opts.unstable_features);
*sess.features.borrow_mut() = features;
sess.abort_if_errors();
});
/// Run the resolution, typechecking, region checking and other
/// miscellaneous analysis passes on the crate. Return various
/// structures carrying the results of the analysis.
-pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
- ast_map: ast_map::Map<'tcx>,
- arenas: &'tcx ty::CtxtArenas<'tcx>,
- name: String,
- make_glob_map: resolve::MakeGlobMap)
- -> ty::CrateAnalysis<'tcx> {
+pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: Session,
+ ast_map: ast_map::Map<'tcx>,
+ arenas: &'tcx ty::CtxtArenas<'tcx>,
+ name: String,
+ make_glob_map: resolve::MakeGlobMap,
+ f: F)
+ -> (Session, R)
+ where F: FnOnce(&ty::ctxt<'tcx>,
+ ty::CrateAnalysis) -> R
+{
let time_passes = sess.time_passes();
let krate = ast_map.krate();
glob_map,
} =
time(time_passes, "resolution", (),
- |_| resolve::resolve_crate(&sess,
- &ast_map,
- &lang_items,
- krate,
- make_glob_map));
+ |_| resolve::resolve_crate(&sess, &ast_map, make_glob_map));
// Discard MTWT tables that aren't required past resolution.
syntax::ext::mtwt::clear_tables();
time(time_passes, "static item recursion checking", (), |_|
middle::check_static_recursion::check_crate(&sess, krate, &def_map, &ast_map));
- let ty_cx = ty::mk_ctxt(sess,
- arenas,
- def_map,
- named_region_map,
- ast_map,
- freevars,
- region_map,
- lang_items,
- stability::Index::new(krate));
-
- // passes are timed inside typeck
- typeck::check_crate(&ty_cx, trait_map);
-
- time(time_passes, "const checking", (), |_|
- middle::check_const::check_crate(&ty_cx));
-
- let (exported_items, public_items) =
- time(time_passes, "privacy checking", (), |_|
- rustc_privacy::check_crate(&ty_cx, &export_map, external_exports));
-
- // Do not move this check past lint
- time(time_passes, "stability index", (), |_|
- ty_cx.stability.borrow_mut().build(&ty_cx.sess, krate, &public_items));
-
- time(time_passes, "intrinsic checking", (), |_|
- middle::intrinsicck::check_crate(&ty_cx));
-
- time(time_passes, "effect checking", (), |_|
- middle::effect::check_crate(&ty_cx));
-
- time(time_passes, "match checking", (), |_|
- middle::check_match::check_crate(&ty_cx));
-
- time(time_passes, "liveness checking", (), |_|
- middle::liveness::check_crate(&ty_cx));
-
- time(time_passes, "borrow checking", (), |_|
- borrowck::check_crate(&ty_cx));
-
- time(time_passes, "rvalue checking", (), |_|
- middle::check_rvalues::check_crate(&ty_cx, krate));
-
- // Avoid overwhelming user with errors if type checking failed.
- // I'm not sure how helpful this is, to be honest, but it avoids a
- // lot of annoying errors in the compile-fail tests (basically,
- // lint warnings and so on -- kindck used to do this abort, but
- // kindck is gone now). -nmatsakis
- ty_cx.sess.abort_if_errors();
-
- let reachable_map =
- time(time_passes, "reachability checking", (), |_|
- reachable::find_reachable(&ty_cx, &exported_items));
-
- time(time_passes, "death checking", (), |_| {
- middle::dead::check_crate(&ty_cx,
- &exported_items,
- &reachable_map)
- });
-
- let ref lib_features_used =
- time(time_passes, "stability checking", (), |_|
- stability::check_unstable_api_usage(&ty_cx));
-
- time(time_passes, "unused lib feature checking", (), |_|
- stability::check_unused_or_stable_features(
- &ty_cx.sess, lib_features_used));
-
- time(time_passes, "lint checking", (), |_|
- lint::check_crate(&ty_cx, &exported_items));
-
- // The above three passes generate errors w/o aborting
- ty_cx.sess.abort_if_errors();
-
- ty::CrateAnalysis {
- export_map: export_map,
- ty_cx: ty_cx,
- exported_items: exported_items,
- public_items: public_items,
- reachable: reachable_map,
- name: name,
- glob_map: glob_map,
- }
+ ty::with_ctxt(sess,
+ arenas,
+ def_map,
+ named_region_map,
+ ast_map,
+ freevars,
+ region_map,
+ lang_items,
+ stability::Index::new(krate),
+ |tcx| {
+
+ // passes are timed inside typeck
+ typeck::check_crate(tcx, trait_map);
+
+ time(time_passes, "const checking", (), |_|
+ middle::check_const::check_crate(tcx));
+
+ let (exported_items, public_items) =
+ time(time_passes, "privacy checking", (), |_|
+ rustc_privacy::check_crate(tcx, &export_map, external_exports));
+
+ // Do not move this check past lint
+ time(time_passes, "stability index", (), |_|
+ tcx.stability.borrow_mut().build(tcx, krate, &public_items));
+
+ time(time_passes, "intrinsic checking", (), |_|
+ middle::intrinsicck::check_crate(tcx));
+
+ time(time_passes, "effect checking", (), |_|
+ middle::effect::check_crate(tcx));
+
+ time(time_passes, "match checking", (), |_|
+ middle::check_match::check_crate(tcx));
+
+ time(time_passes, "liveness checking", (), |_|
+ middle::liveness::check_crate(tcx));
+
+ time(time_passes, "borrow checking", (), |_|
+ borrowck::check_crate(tcx));
+
+ time(time_passes, "rvalue checking", (), |_|
+ middle::check_rvalues::check_crate(tcx, krate));
+
+ // Avoid overwhelming user with errors if type checking failed.
+ // I'm not sure how helpful this is, to be honest, but it avoids a
+ // lot of annoying errors in the compile-fail tests (basically,
+ // lint warnings and so on -- kindck used to do this abort, but
+ // kindck is gone now). -nmatsakis
+ tcx.sess.abort_if_errors();
+
+ let reachable_map =
+ time(time_passes, "reachability checking", (), |_|
+ reachable::find_reachable(tcx, &exported_items));
+
+ time(time_passes, "death checking", (), |_| {
+ middle::dead::check_crate(tcx,
+ &exported_items,
+ &reachable_map)
+ });
+
+ let ref lib_features_used =
+ time(time_passes, "stability checking", (), |_|
+ stability::check_unstable_api_usage(tcx));
+
+ time(time_passes, "unused lib feature checking", (), |_|
+ stability::check_unused_or_stable_features(
+ &tcx.sess, lib_features_used));
+
+ time(time_passes, "lint checking", (), |_|
+ lint::check_crate(tcx, &exported_items));
+
+ // The above three passes generate errors w/o aborting
+ tcx.sess.abort_if_errors();
+
+ f(tcx, ty::CrateAnalysis {
+ export_map: export_map,
+ exported_items: exported_items,
+ public_items: public_items,
+ reachable: reachable_map,
+ name: name,
+ glob_map: glob_map,
+ })
+ })
}
/// Run the translation phase to LLVM, after which the AST and analysis can
/// be discarded.
-pub fn phase_4_translate_to_llvm<'tcx>(analysis: ty::CrateAnalysis<'tcx>)
- -> (ty::ctxt<'tcx>, trans::CrateTranslation) {
- let time_passes = analysis.ty_cx.sess.time_passes();
+pub fn phase_4_translate_to_llvm(tcx: &ty::ctxt, analysis: ty::CrateAnalysis)
+ -> trans::CrateTranslation {
+ let time_passes = tcx.sess.time_passes();
time(time_passes, "resolving dependency formats", (), |_|
- dependency_format::calculate(&analysis.ty_cx));
+ dependency_format::calculate(tcx));
// Option dance to work around the lack of stack once closures.
time(time_passes, "translation", analysis, |analysis|
- trans::trans_crate(analysis))
+ trans::trans_crate(tcx, analysis))
}
/// Run LLVM itself, producing a bitcode file, assembly file or object file
pub fn phase_6_link_output(sess: &Session,
trans: &trans::CrateTranslation,
outputs: &OutputFilenames) {
- let old_path = env::var_os("PATH").unwrap_or(OsString::new());
- let mut new_path = sess.host_filesearch(PathKind::All).get_tools_search_paths();
- new_path.extend(env::split_paths(&old_path));
- env::set_var("PATH", &env::join_paths(new_path.iter()).unwrap());
-
time(sess.time_passes(), "linking", (), |_|
link::link_binary(sess,
trans,
outputs,
&trans.link.crate_name));
-
- env::set_var("PATH", &old_path);
}
fn escape_dep_filename(filename: &str) -> String {
let file = outputs.path(*output_type);
match *output_type {
config::OutputTypeExe => {
- for output in &*sess.crate_types.borrow() {
+ for output in sess.crate_types.borrow().iter() {
let p = link::filename_for_input(sess, *output,
id, &file);
out_filenames.push(p);
// will be found in crate attributes.
let mut base = session.opts.crate_types.clone();
if base.is_empty() {
- base.extend(attr_types.into_iter());
+ base.extend(attr_types);
if base.is_empty() {
base.push(link::default_output_for_target(session));
}
OutputFilenames {
out_directory: out_file.parent().unwrap_or(cur_dir).to_path_buf(),
- out_filestem: out_file.file_stem().unwrap()
+ out_filestem: out_file.file_stem().unwrap_or(OsStr::new(""))
.to_str().unwrap().to_string(),
single_output_file: ofile,
extra: sess.opts.cg.extra_filename.clone(),
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
- html_favicon_url = "http://www.rust-lang.org/favicon.ico",
+ html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/")]
#![feature(box_syntax)]
-#![feature(collections)]
#![feature(libc)]
#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
-#![feature(staged_api)]
-#![feature(exit_status)]
#![feature(set_stdio)]
+#![feature(staged_api)]
+#![feature(vec_push_all)]
extern crate arena;
extern crate flate;
use std::io::{self, Read, Write};
use std::iter::repeat;
use std::path::PathBuf;
+use std::process;
use std::str;
use std::sync::{Arc, Mutex};
use std::thread;
if sess.opts.debugging_opts.save_analysis {
control.after_analysis.callback = box |state| {
time(state.session.time_passes(),
- "save analysis",
- state.expanded_crate.unwrap(),
- |krate| save::process_crate(state.session,
- krate,
- state.analysis.unwrap(),
- state.out_dir));
+ "save analysis", (),
+ |_| save::process_crate(state.tcx.unwrap(),
+ state.analysis.unwrap(),
+ state.out_dir));
};
control.make_glob_map = resolve::MakeGlobMap::Yes;
}
&Input::File(ref ifile) => {
let path = &(*ifile);
let mut v = Vec::new();
- metadata::loader::list_file_metadata(sess.target.target.options.is_like_osx,
+ metadata::loader::list_file_metadata(&sess.target.target,
path,
&mut v).unwrap();
println!("{}", String::from_utf8(v).unwrap());
let plugin_groups = sort_lint_groups(plugin_groups);
let builtin_groups = sort_lint_groups(builtin_groups);
- let max_name_len = plugin.iter().chain(builtin.iter())
+ let max_name_len = plugin.iter().chain(&builtin)
.map(|&s| s.name.chars().count())
.max().unwrap_or(0);
let padded = |x: &str| {
- let max_name_len = plugin_groups.iter().chain(builtin_groups.iter())
+ let max_name_len = plugin_groups.iter().chain(&builtin_groups)
.map(|&(s, _)| s.chars().count())
.max().unwrap_or(0);
let padded = |x: &str| {
"the compiler unexpectedly panicked. this is a bug.".to_string(),
format!("we would appreciate a bug report: {}",
BUG_REPORT_URL),
- "run with `RUST_BACKTRACE=1` for a backtrace".to_string(),
];
for note in &xs {
emitter.emit(None, ¬e[..], None, diagnostic::Note)
}
+ if let None = env::var_os("RUST_BACKTRACE") {
+ emitter.emit(None, "run with `RUST_BACKTRACE=1` for a backtrace",
+ None, diagnostic::Note);
+ }
println!("{}", str::from_utf8(&data.lock().unwrap()).unwrap());
}
pub fn main() {
let result = run(env::args().collect());
- std::env::set_exit_status(result as i32);
+ process::exit(result as i32);
}
use driver;
+use rustc::ast_map::{self, blocks, NodePrinter};
use rustc::middle::ty;
use rustc::middle::cfg;
use rustc::middle::cfg::graphviz::LabelledCFG;
use rustc::session::Session;
use rustc::session::config::Input;
-use rustc::util::ppaux;
use rustc_borrowck as borrowck;
use rustc_borrowck::graphviz as borrowck_dot;
use rustc_resolve as resolve;
use syntax::ast;
-use syntax::ast_map::{self, blocks, NodePrinter};
use syntax::codemap;
use syntax::fold::{self, Folder};
use syntax::print::{pp, pprust};
}
PpmTyped => {
let ast_map = ast_map.expect("--pretty=typed missing ast_map");
- let analysis = driver::phase_3_run_analysis_passes(sess,
- ast_map,
- arenas,
- id,
- resolve::MakeGlobMap::No);
- let annotation = TypedAnnotation { analysis: analysis };
- f(&annotation, payload)
+ driver::phase_3_run_analysis_passes(sess,
+ ast_map,
+ arenas,
+ id,
+ resolve::MakeGlobMap::No,
+ |tcx, _| {
+ let annotation = TypedAnnotation { tcx: tcx };
+ f(&annotation, payload)
+ }).1
}
}
}
}
-struct TypedAnnotation<'tcx> {
- analysis: ty::CrateAnalysis<'tcx>,
+struct TypedAnnotation<'a, 'tcx: 'a> {
+ tcx: &'a ty::ctxt<'tcx>,
}
-impl<'tcx> PrinterSupport<'tcx> for TypedAnnotation<'tcx> {
- fn sess<'a>(&'a self) -> &'a Session { &self.analysis.ty_cx.sess }
+impl<'b, 'tcx> PrinterSupport<'tcx> for TypedAnnotation<'b, 'tcx> {
+ fn sess<'a>(&'a self) -> &'a Session { &self.tcx.sess }
fn ast_map<'a>(&'a self) -> Option<&'a ast_map::Map<'tcx>> {
- Some(&self.analysis.ty_cx.map)
+ Some(&self.tcx.map)
}
fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn { self }
}
-impl<'tcx> pprust::PpAnn for TypedAnnotation<'tcx> {
+impl<'a, 'tcx> pprust::PpAnn for TypedAnnotation<'a, 'tcx> {
fn pre(&self,
s: &mut pprust::State,
node: pprust::AnnNode) -> io::Result<()> {
fn post(&self,
s: &mut pprust::State,
node: pprust::AnnNode) -> io::Result<()> {
- let tcx = &self.analysis.ty_cx;
match node {
pprust::NodeExpr(expr) => {
try!(pp::space(&mut s.s));
try!(pp::word(&mut s.s, "as"));
try!(pp::space(&mut s.s));
try!(pp::word(&mut s.s,
- &ppaux::ty_to_string(
- tcx,
- ty::expr_ty(tcx, expr))));
+ &ty::expr_ty(self.tcx, expr).to_string()));
s.pclose()
}
_ => Ok(())
match code {
Some(code) => {
let variants = gather_flowgraph_variants(&sess);
- let analysis = driver::phase_3_run_analysis_passes(sess,
- ast_map,
- &arenas,
- id,
- resolve::MakeGlobMap::No);
- print_flowgraph(variants, analysis, code, mode, out)
+ driver::phase_3_run_analysis_passes(sess,
+ ast_map,
+ &arenas,
+ id,
+ resolve::MakeGlobMap::No,
+ |tcx, _| {
+ print_flowgraph(variants, tcx, code, mode, out)
+ }).1
}
None => {
let message = format!("--pretty=flowgraph needs \
}
fn print_flowgraph<W: Write>(variants: Vec<borrowck_dot::Variant>,
- analysis: ty::CrateAnalysis,
+ tcx: &ty::ctxt,
code: blocks::Code,
mode: PpFlowGraphMode,
mut out: W) -> io::Result<()> {
- let ty_cx = &analysis.ty_cx;
let cfg = match code {
- blocks::BlockCode(block) => cfg::CFG::new(ty_cx, &*block),
- blocks::FnLikeCode(fn_like) => cfg::CFG::new(ty_cx, &*fn_like.body()),
+ blocks::BlockCode(block) => cfg::CFG::new(tcx, &*block),
+ blocks::FnLikeCode(fn_like) => cfg::CFG::new(tcx, &*fn_like.body()),
};
let labelled_edges = mode != PpFlowGraphMode::UnlabelledEdges;
let lcfg = LabelledCFG {
- ast_map: &ty_cx.map,
+ ast_map: &tcx.map,
cfg: &cfg,
name: format!("node_{}", code.id()),
labelled_edges: labelled_edges,
return expand_err_details(r);
}
blocks::BlockCode(_) => {
- ty_cx.sess.err("--pretty flowgraph with -Z flowgraph-print \
- annotations requires fn-like node id.");
+ tcx.sess.err("--pretty flowgraph with -Z flowgraph-print \
+ annotations requires fn-like node id.");
return Ok(())
}
blocks::FnLikeCode(fn_like) => {
let fn_parts = borrowck::FnPartsWithCFG::from_fn_like(&fn_like, &cfg);
let (bccx, analysis_data) =
- borrowck::build_borrowck_dataflow_data_for_fn(ty_cx, fn_parts);
+ borrowck::build_borrowck_dataflow_data_for_fn(tcx, fn_parts);
let lcfg = borrowck_dot::DataflowLabeller {
inner: lcfg,
use rustc_typeck::middle::infer::lub::Lub;
use rustc_typeck::middle::infer::glb::Glb;
use rustc_typeck::middle::infer::sub::Sub;
-use rustc_typeck::util::ppaux::{ty_to_string, Repr, UserString};
+use rustc::ast_map;
use rustc::session::{self,config};
-use syntax::{abi, ast, ast_map};
+use syntax::{abi, ast};
use syntax::codemap;
use syntax::codemap::{Span, CodeMap, DUMMY_SP};
use syntax::diagnostic::{Level, RenderSpan, Bug, Fatal, Error, Warning, Note, Help};
use syntax::parse::token;
+use syntax::feature_gate::UnstableFeatures;
struct Env<'a, 'tcx: 'a> {
infcx: &'a infer::InferCtxt<'a, 'tcx>,
let mut options =
config::basic_options();
options.debugging_opts.verbose = true;
+ options.unstable_features = UnstableFeatures::Allow;
let codemap =
CodeMap::new();
let diagnostic_handler =
- diagnostic::mk_handler(true, emitter);
+ diagnostic::Handler::with_emitter(true, emitter);
let span_diagnostic_handler =
- diagnostic::mk_span_handler(diagnostic_handler, codemap);
+ diagnostic::SpanHandler::new(diagnostic_handler, codemap);
let sess = session::build_session_(options, None, span_diagnostic_handler);
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
// run just enough stuff to build a tcx:
let lang_items = lang_items::collect_language_items(krate, &sess);
let resolve::CrateMap { def_map, freevars, .. } =
- resolve::resolve_crate(&sess, &ast_map, &lang_items, krate, resolve::MakeGlobMap::No);
+ resolve::resolve_crate(&sess, &ast_map, resolve::MakeGlobMap::No);
let named_region_map = resolve_lifetime::krate(&sess, krate, &def_map);
let region_map = region::resolve_crate(&sess, krate);
- let tcx = ty::mk_ctxt(sess,
- &arenas,
- def_map,
- named_region_map,
- ast_map,
- freevars,
- region_map,
- lang_items,
- stability::Index::new(krate));
- let infcx = infer::new_infer_ctxt(&tcx);
- body(Env { infcx: &infcx });
- let free_regions = FreeRegionMap::new();
- infcx.resolve_regions_and_report_errors(&free_regions, ast::CRATE_NODE_ID);
- assert_eq!(tcx.sess.err_count(), expected_err_count);
+ ty::with_ctxt(sess,
+ &arenas,
+ def_map,
+ named_region_map,
+ ast_map,
+ freevars,
+ region_map,
+ lang_items,
+ stability::Index::new(krate),
+ |tcx| {
+ let infcx = infer::new_infer_ctxt(tcx);
+ body(Env { infcx: &infcx });
+ let free_regions = FreeRegionMap::new();
+ infcx.resolve_regions_and_report_errors(&free_regions, ast::CRATE_NODE_ID);
+ assert_eq!(tcx.sess.err_count(), expected_err_count);
+ });
}
impl<'a, 'tcx> Env<'a, 'tcx> {
-> Option<ast::NodeId> {
assert!(idx < names.len());
for item in &m.items {
- if item.ident.user_string(this.infcx.tcx) == names[idx] {
+ if item.ident.to_string() == names[idx] {
return search(this, &**item, idx+1, names);
}
}
pub fn make_subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
match infer::mk_subty(self.infcx, true, infer::Misc(DUMMY_SP), a, b) {
Ok(_) => true,
- Err(ref e) => panic!("Encountered error: {}",
- ty::type_err_to_str(self.infcx.tcx, e))
+ Err(ref e) => panic!("Encountered error: {}", e)
}
}
pub fn assert_subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) {
if !self.is_subtype(a, b) {
- panic!("{} is not a subtype of {}, but it should be",
- self.ty_to_string(a),
- self.ty_to_string(b));
+ panic!("{} is not a subtype of {}, but it should be", a, b);
}
}
self.assert_subtype(b, a);
}
- pub fn ty_to_string(&self, a: Ty<'tcx>) -> String {
- ty_to_string(self.infcx.tcx, a)
- }
-
pub fn t_fn(&self,
input_tys: &[Ty<'tcx>],
output_ty: Ty<'tcx>)
pub fn make_lub_ty(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> Ty<'tcx> {
match self.lub().relate(&t1, &t2) {
Ok(t) => t,
- Err(ref e) => panic!("unexpected error computing LUB: {}",
- ty::type_err_to_str(self.infcx.tcx, e))
+ Err(ref e) => panic!("unexpected error computing LUB: {}", e)
}
}
match self.sub().relate(&t1, &t2) {
Ok(_) => { }
Err(ref e) => {
- panic!("unexpected error computing sub({},{}): {}",
- t1.repr(self.infcx.tcx),
- t2.repr(self.infcx.tcx),
- ty::type_err_to_str(self.infcx.tcx, e));
+ panic!("unexpected error computing sub({:?},{:?}): {}",
+ t1,
+ t2,
+ e);
}
}
}
match self.sub().relate(&t1, &t2) {
Err(_) => { }
Ok(_) => {
- panic!("unexpected success computing sub({},{})",
- t1.repr(self.infcx.tcx),
- t2.repr(self.infcx.tcx));
+ panic!("unexpected success computing sub({:?},{:?})",
+ t1,
+ t2);
}
}
}
self.assert_eq(t, t_lub);
}
Err(ref e) => {
- panic!("unexpected error in LUB: {}",
- ty::type_err_to_str(self.infcx.tcx, e))
+ panic!("unexpected error in LUB: {}", e)
}
}
}
/// Checks that `GLB(t1,t2) == t_glb`
pub fn check_glb(&self, t1: Ty<'tcx>, t2: Ty<'tcx>, t_glb: Ty<'tcx>) {
- debug!("check_glb(t1={}, t2={}, t_glb={})",
- self.ty_to_string(t1),
- self.ty_to_string(t2),
- self.ty_to_string(t_glb));
+ debug!("check_glb(t1={}, t2={}, t_glb={})", t1, t2, t_glb);
match self.glb().relate(&t1, &t2) {
Err(e) => {
panic!("unexpected error computing LUB: {:?}", e)
// `&'_ isize`
let t_resolve1 = env.infcx.shallow_resolve(t_infer1);
match t_resolve1.sty {
- ty::ty_rptr(..) => { }
- _ => { panic!("t_resolve1={}", t_resolve1.repr(env.infcx.tcx)); }
+ ty::TyRef(..) => { }
+ _ => { panic!("t_resolve1={:?}", t_resolve1); }
}
})
}
env.t_fn(&[t_ptr_bound2], env.t_nil())
};
- debug!("subst_bound: t_source={} substs={} t_substituted={} t_expected={}",
- t_source.repr(env.infcx.tcx),
- substs.repr(env.infcx.tcx),
- t_substituted.repr(env.infcx.tcx),
- t_expected.repr(env.infcx.tcx));
+ debug!("subst_bound: t_source={:?} substs={:?} t_substituted={:?} t_expected={:?}",
+ t_source,
+ substs,
+ t_substituted,
+ t_expected);
assert_eq!(t_substituted, t_expected);
})
env.t_pair(t_rptr_bound1, env.t_fn(&[t_rptr_bound2], env.t_nil()))
};
- debug!("subst_bound: t_source={} substs={} t_substituted={} t_expected={}",
- t_source.repr(env.infcx.tcx),
- substs.repr(env.infcx.tcx),
- t_substituted.repr(env.infcx.tcx),
- t_expected.repr(env.infcx.tcx));
+ debug!("subst_bound: t_source={:?} substs={:?} t_substituted={:?} t_expected={:?}",
+ t_source,
+ substs,
+ t_substituted,
+ t_expected);
assert_eq!(t_substituted, t_expected);
})
env.t_fn(&[t_rptr_bound2], env.t_nil())
};
- debug!("subst_bound: t_source={} substs={} t_substituted={} t_expected={}",
- t_source.repr(env.infcx.tcx),
- substs.repr(env.infcx.tcx),
- t_substituted.repr(env.infcx.tcx),
- t_expected.repr(env.infcx.tcx));
+ debug!("subst_bound: t_source={:?} substs={:?} t_substituted={:?} t_expected={:?}",
+ t_source,
+ substs,
+ t_substituted,
+ t_expected);
assert_eq!(t_substituted, t_expected);
})
use middle::subst::Substs;
use middle::ty::{self, Ty};
use middle::{def, pat_util, stability};
-use middle::const_eval::{eval_const_expr_partial, const_int, const_uint};
+use middle::const_eval::{eval_const_expr_partial, ConstVal};
use middle::cfg;
-use util::ppaux::ty_to_string;
+use rustc::ast_map;
use util::nodemap::{FnvHashMap, NodeSet};
use lint::{Level, Context, LintPass, LintArray, Lint};
use std::{cmp, slice};
use std::{i8, i16, i32, i64, u8, u16, u32, u64, f32, f64};
-use syntax::{abi, ast, ast_map};
+use syntax::{abi, ast};
use syntax::ast_util::{self, is_shift_binop, local_def};
use syntax::attr::{self, AttrMetaMethods};
use syntax::codemap::{self, Span};
_ => {
let t = ty::expr_ty(cx.tcx, &**expr);
match t.sty {
- ty::ty_uint(_) => {
+ ty::TyUint(_) => {
cx.span_lint(UNSIGNED_NEGATION, e.span,
"negation of unsigned int variable may \
be unintentional");
if is_shift_binop(binop.node) {
let opt_ty_bits = match ty::expr_ty(cx.tcx, &**l).sty {
- ty::ty_int(t) => Some(int_ty_bits(t, cx.sess().target.int_type)),
- ty::ty_uint(t) => Some(uint_ty_bits(t, cx.sess().target.uint_type)),
+ ty::TyInt(t) => Some(int_ty_bits(t, cx.sess().target.int_type)),
+ ty::TyUint(t) => Some(uint_ty_bits(t, cx.sess().target.uint_type)),
_ => None
};
else { false }
} else {
match eval_const_expr_partial(cx.tcx, &**r, Some(cx.tcx.types.usize)) {
- Ok(const_int(shift)) => { shift as u64 >= bits },
- Ok(const_uint(shift)) => { shift >= bits },
+ Ok(ConstVal::Int(shift)) => { shift as u64 >= bits },
+ Ok(ConstVal::Uint(shift)) => { shift >= bits },
_ => { false }
}
};
},
ast::ExprLit(ref lit) => {
match ty::expr_ty(cx.tcx, e).sty {
- ty::ty_int(t) => {
+ ty::TyInt(t) => {
match lit.node {
ast::LitInt(v, ast::SignedIntLit(_, ast::Plus)) |
ast::LitInt(v, ast::UnsuffixedIntLit(ast::Plus)) => {
} else {
t
};
- let (min, max) = int_ty_range(int_type);
+ let (_, max) = int_ty_range(int_type);
let negative = self.negated_expr_id == e.id;
- if (negative && v > (min.abs() as u64)) ||
- (!negative && v > (max.abs() as u64)) {
+ // Detect literal value out of range [min, max] inclusive
+ // avoiding use of -min to prevent overflow/panic
+ if (negative && v > max as u64 + 1) ||
+ (!negative && v > max as u64) {
cx.span_lint(OVERFLOWING_LITERALS, e.span,
&*format!("literal out of range for {:?}", t));
return;
_ => panic!()
};
},
- ty::ty_uint(t) => {
+ ty::TyUint(t) => {
let uint_type = if let ast::TyUs = t {
cx.sess().target.uint_type
} else {
&*format!("literal out of range for {:?}", t));
}
},
- ty::ty_float(t) => {
+ ty::TyFloat(t) => {
let (min, max) = float_ty_range(t);
let lit_val: f64 = match lit.node {
ast::LitFloat(ref v, _) |
binop
};
match ty::expr_ty(tcx, expr).sty {
- ty::ty_int(int_ty) => {
+ ty::TyInt(int_ty) => {
let (min, max) = int_ty_range(int_ty);
let lit_val: i64 = match lit.node {
ast::ExprLit(ref li) => match li.node {
};
is_valid(norm_binop, lit_val, min, max)
}
- ty::ty_uint(uint_ty) => {
+ ty::TyUint(uint_ty) => {
let (min, max): (u64, u64) = uint_ty_range(uint_ty);
let lit_val: u64 = match lit.node {
ast::ExprLit(ref li) => match li.node {
let mut n_uniq: usize = 0;
ty::fold_ty(cx.tcx, ty, |t| {
match t.sty {
- ty::ty_uniq(_) => {
+ ty::TyBox(_) => {
n_uniq += 1;
}
_ => ()
});
if n_uniq > 0 {
- let s = ty_to_string(cx.tcx, ty);
- let m = format!("type uses owned (Box type) pointers: {}", s);
+ let m = format!("type uses owned (Box type) pointers: {}", ty);
cx.span_lint(BOX_POINTERS, span, &m[..]);
}
}
}
match ty::node_id_to_type(cx.tcx, item.id).sty {
- ty::ty_enum(did, _) => did,
- ty::ty_struct(did, _) => did,
+ ty::TyEnum(did, _) => did,
+ ty::TyStruct(did, _) => did,
_ => return,
}
}
}
}
+ let plugin_attributes = cx.sess().plugin_attributes.borrow_mut();
+ for &(ref name, ty) in plugin_attributes.iter() {
+ if ty == AttributeType::Whitelisted && attr.check_name(&*name) {
+ break;
+ }
+ }
+
if !attr::is_used(attr) {
cx.span_lint(UNUSED_ATTRIBUTES, attr.span, "unused attribute");
- if KNOWN_ATTRIBUTES.contains(&(&attr.name(), AttributeType::CrateLevel)) {
+ // Is it a builtin attribute that must be used at the crate level?
+ let known_crate = KNOWN_ATTRIBUTES.contains(&(&attr.name(),
+ AttributeType::CrateLevel));
+ // Has a plugin registered this attribute as one which must be used at
+ // the crate level?
+ let plugin_crate = plugin_attributes.iter()
+ .find(|&&(ref x, t)| {
+ &*attr.name() == &*x &&
+ AttributeType::CrateLevel == t
+ }).is_some();
+ if known_crate || plugin_crate {
let msg = match attr.node.style {
ast::AttrOuter => "crate-level attribute should be an inner \
attribute: add an exclamation mark: #![foo]",
let t = ty::expr_ty(cx.tcx, expr);
let warned = match t.sty {
- ty::ty_tup(ref tys) if tys.is_empty() => return,
- ty::ty_bool => return,
- ty::ty_struct(did, _) |
- ty::ty_enum(did, _) => {
+ ty::TyTuple(ref tys) if tys.is_empty() => return,
+ ty::TyBool => return,
+ ty::TyStruct(did, _) |
+ ty::TyEnum(did, _) => {
if ast_util::is_local(did) {
if let ast_map::NodeItem(it) = cx.tcx.map.get(did.node) {
check_must_use(cx, &it.attrs, s.span)
}
fn check_generics(&mut self, cx: &Context, it: &ast::Generics) {
- for gen in &*it.ty_params {
+ for gen in it.ty_params.iter() {
self.check_case(cx, "type parameter", gen.ident, gen.span);
}
}
},
_ => (),
},
- visit::FkItemFn(ident, _, _, _, _) => {
+ visit::FkItemFn(ident, _, _, _, _, _) => {
self.check_snake_case(cx, "function", &token::get_ident(ident), Some(span))
},
_ => (),
fn check_fn(&mut self, cx: &Context, fk: visit::FnKind, _: &ast::FnDecl,
_: &ast::Block, span: Span, _: ast::NodeId) {
match fk {
- visit::FkItemFn(_, _, ast::Unsafety::Unsafe, _, _) =>
+ visit::FkItemFn(_, _, ast::Unsafety::Unsafe, _, _, _) =>
cx.span_lint(UNSAFE_CODE, span, "declaration of an `unsafe` function"),
visit::FkMethod(_, sig, _) => {
pub struct Stability;
impl Stability {
- fn lint(&self, cx: &Context, _id: ast::DefId, span: Span, stability: &Option<attr::Stability>) {
+ fn lint(&self, cx: &Context, _id: ast::DefId,
+ span: Span, stability: &Option<&attr::Stability>) {
// Deprecated attributes apply in-crate and cross-crate.
let (lint, label) = match *stability {
- Some(attr::Stability { deprecated_since: Some(_), .. }) =>
+ Some(&attr::Stability { deprecated_since: Some(_), .. }) =>
(DEPRECATED, "deprecated"),
_ => return
};
output(cx, span, stability, lint, label);
- fn output(cx: &Context, span: Span, stability: &Option<attr::Stability>,
+ fn output(cx: &Context, span: Span, stability: &Option<&attr::Stability>,
lint: &'static Lint, label: &'static str) {
let msg = match *stability {
- Some(attr::Stability { reason: Some(ref s), .. }) => {
+ Some(&attr::Stability { reason: Some(ref s), .. }) => {
format!("use of {} item: {}", label, *s)
}
_ => format!("use of {} item", label)
ast::NodeId, ast::NodeId, ast::Ident, ast::NodeId) -> bool;
let (name, checker) = match fn_kind {
- visit::FkItemFn(name, _, _, _, _) => (name, id_refers_to_this_fn as F),
+ visit::FkItemFn(name, _, _, _, _, _) => (name, id_refers_to_this_fn as F),
visit::FkMethod(name, _, _) => (name, id_refers_to_this_method as F),
// closures can't recur, so they don't matter.
visit::FkFnBlock => return
let msg = "mutating transmuted &mut T from &T may cause undefined behavior,\
consider instead using an UnsafeCell";
match get_transmute_from_to(cx, expr) {
- Some((&ty::ty_rptr(_, from_mt), &ty::ty_rptr(_, to_mt))) => {
+ Some((&ty::TyRef(_, from_mt), &ty::TyRef(_, to_mt))) => {
if to_mt.mutbl == ast::Mutability::MutMutable
&& from_mt.mutbl == ast::Mutability::MutImmutable {
cx.span_lint(MUTABLE_TRANSMUTES, expr.span, msg);
}
fn get_transmute_from_to<'a, 'tcx>(cx: &Context<'a, 'tcx>, expr: &ast::Expr)
- -> Option<(&'tcx ty::sty<'tcx>, &'tcx ty::sty<'tcx>)> {
+ -> Option<(&'tcx ty::TypeVariants<'tcx>, &'tcx ty::TypeVariants<'tcx>)> {
match expr.node {
ast::ExprPath(..) => (),
_ => return None
}
let typ = ty::node_id_to_type(cx.tcx, expr.id);
match typ.sty {
- ty::ty_bare_fn(_, ref bare_fn) if bare_fn.abi == RustIntrinsic => {
+ ty::TyBareFn(_, ref bare_fn) if bare_fn.abi == RustIntrinsic => {
if let ty::FnConverging(to) = bare_fn.sig.0.output {
let from = bare_fn.sig.0.inputs[0];
return Some((&from.sty, &to.sty));
fn def_id_is_transmute(cx: &Context, def_id: DefId) -> bool {
match ty::lookup_item_type(cx.tcx, def_id).ty.sty {
- ty::ty_bare_fn(_, ref bfty) if bfty.abi == RustIntrinsic => (),
+ ty::TyBareFn(_, ref bfty) if bfty.abi == RustIntrinsic => (),
_ => return false
}
ty::with_path(cx.tcx, def_id, |path| match path.last() {
declare_lint! {
UNSTABLE_FEATURES,
Allow,
- "enabling unstable features"
+ "enabling unstable features (deprecated. do not use)"
}
impl LintPass for UnstableFeatures {
}
fn check_attribute(&mut self, ctx: &Context, attr: &ast::Attribute) {
if attr::contains_name(&[attr.node.value.clone()], "feature") {
- ctx.span_lint(UNSTABLE_FEATURES, attr.span, "unstable feature");
+ if let Some(items) = attr.node.value.meta_item_list() {
+ for item in items {
+ ctx.span_lint(UNSTABLE_FEATURES, item.span, "unstable feature");
+ }
+ }
}
}
}
};
match dtor_self_type.sty {
- ty::ty_enum(self_type_did, _) |
- ty::ty_struct(self_type_did, _) |
- ty::ty_closure(self_type_did, _) => {
+ ty::TyEnum(self_type_did, _) |
+ ty::TyStruct(self_type_did, _) |
+ ty::TyClosure(self_type_did, _) => {
let hints = ty::lookup_repr_hints(ctx.tcx, self_type_did);
if hints.iter().any(|attr| *attr == attr::ReprExtern) &&
ty::ty_dtor(ctx.tcx, self_type_did).has_drop_flag() {
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
- html_favicon_url = "http://www.rust-lang.org/favicon.ico",
+ html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/")]
+#![cfg_attr(test, feature(test))]
#![feature(box_patterns)]
#![feature(box_syntax)]
-#![feature(collections)]
-#![feature(core)]
+#![feature(num_bits_bytes)]
#![feature(quote)]
+#![feature(ref_slice)]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
#![feature(staged_api)]
#![feature(str_char)]
-#![cfg_attr(test, feature(test))]
extern crate syntax;
#[macro_use]
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
- html_favicon_url = "http://www.rust-lang.org/favicon.ico",
+ html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/")]
#![feature(associated_consts)]
#![feature(box_syntax)]
-#![feature(collections)]
#![feature(libc)]
#![feature(link_args)]
#![feature(staged_api)]
+#![feature(vec_push_all)]
extern crate libc;
#[macro_use] #[no_link] extern crate rustc_bitflags;
pub use self::Visibility::*;
pub use self::DiagnosticSeverity::*;
pub use self::Linkage::*;
+pub use self::DLLStorageClassTypes::*;
use std::ffi::CString;
use std::cell::RefCell;
Note,
}
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub enum DLLStorageClassTypes {
+ DefaultStorageClass = 0,
+ DLLImportStorageClass = 1,
+ DLLExportStorageClass = 2,
+}
+
bitflags! {
flags Attribute : u32 {
const ZExt = 1 << 0,
pub enum ExecutionEngine_opaque {}
pub type ExecutionEngineRef = *mut ExecutionEngine_opaque;
#[allow(missing_copy_implementations)]
-pub enum RustJITMemoryManager_opaque {}
-pub type RustJITMemoryManagerRef = *mut RustJITMemoryManager_opaque;
-#[allow(missing_copy_implementations)]
pub enum MemoryBuffer_opaque {}
pub type MemoryBufferRef = *mut MemoryBuffer_opaque;
#[allow(missing_copy_implementations)]
pub fn LLVMAddDereferenceableAttr(Fn: ValueRef, index: c_uint, bytes: uint64_t);
pub fn LLVMAddFunctionAttribute(Fn: ValueRef, index: c_uint, PA: uint64_t);
pub fn LLVMAddFunctionAttrString(Fn: ValueRef, index: c_uint, Name: *const c_char);
+ pub fn LLVMAddFunctionAttrStringValue(Fn: ValueRef, index: c_uint,
+ Name: *const c_char,
+ Value: *const c_char);
pub fn LLVMRemoveFunctionAttrString(Fn: ValueRef, index: c_uint, Name: *const c_char);
pub fn LLVMGetFunctionAttr(Fn: ValueRef) -> c_ulonglong;
pub fn LLVMRemoveFunctionAttr(Fn: ValueRef, val: c_ulonglong);
pub fn LLVMDisposeBuilder(Builder: BuilderRef);
/* Execution engine */
- pub fn LLVMRustCreateJITMemoryManager(morestack: *const ())
- -> RustJITMemoryManagerRef;
- pub fn LLVMBuildExecutionEngine(Mod: ModuleRef,
- MM: RustJITMemoryManagerRef) -> ExecutionEngineRef;
+ pub fn LLVMBuildExecutionEngine(Mod: ModuleRef) -> ExecutionEngineRef;
pub fn LLVMDisposeExecutionEngine(EE: ExecutionEngineRef);
pub fn LLVMExecutionEngineFinalizeObject(EE: ExecutionEngineRef);
pub fn LLVMRustLoadDynamicLibrary(path: *const c_char) -> Bool;
-> ValueRef;
/* Memory */
- pub fn LLVMBuildMalloc(B: BuilderRef, Ty: TypeRef, Name: *const c_char)
- -> ValueRef;
- pub fn LLVMBuildArrayMalloc(B: BuilderRef,
- Ty: TypeRef,
- Val: ValueRef,
- Name: *const c_char)
- -> ValueRef;
pub fn LLVMBuildAlloca(B: BuilderRef, Ty: TypeRef, Name: *const c_char)
-> ValueRef;
- pub fn LLVMBuildArrayAlloca(B: BuilderRef,
- Ty: TypeRef,
- Val: ValueRef,
- Name: *const c_char)
- -> ValueRef;
pub fn LLVMBuildFree(B: BuilderRef, PointerVal: ValueRef) -> ValueRef;
pub fn LLVMBuildLoad(B: BuilderRef,
PointerVal: ValueRef,
Dialect: c_uint)
-> ValueRef;
- pub static LLVMRustDebugMetadataVersion: u32;
+ pub fn LLVMRustDebugMetadataVersion() -> u32;
+ pub fn LLVMVersionMajor() -> u32;
+ pub fn LLVMVersionMinor() -> u32;
pub fn LLVMRustAddModuleFlag(M: ModuleRef,
name: *const c_char,
VarInfo: DIVariable,
AddrOps: *const i64,
AddrOpsCount: c_uint,
+ DL: ValueRef,
InsertAtEnd: BasicBlockRef)
-> ValueRef;
VarInfo: DIVariable,
AddrOps: *const i64,
AddrOpsCount: c_uint,
+ DL: ValueRef,
InsertBefore: ValueRef)
-> ValueRef;
Level: CodeGenOptLevel,
EnableSegstk: bool,
UseSoftFP: bool,
- NoFramePointerElim: bool,
PositionIndependentExecutable: bool,
FunctionSections: bool,
DataSections: bool) -> TargetMachineRef;
pub fn LLVMRustAddBuilderLibraryInfo(PMB: PassManagerBuilderRef,
M: ModuleRef,
DisableSimplifyLibCalls: bool);
+ pub fn LLVMRustConfigurePassManagerBuilder(PMB: PassManagerBuilderRef,
+ OptLevel: CodeGenOptLevel,
+ MergeFunctions: bool,
+ SLPVectorize: bool,
+ LoopVectorize: bool);
pub fn LLVMRustAddLibraryInfo(PM: PassManagerRef, M: ModuleRef,
DisableSimplifyLibCalls: bool);
pub fn LLVMRustRunFunctionPassManager(PM: PassManagerRef, M: ModuleRef);
pub fn LLVMRustArchiveIteratorFree(AIR: ArchiveIteratorRef);
pub fn LLVMRustDestroyArchive(AR: ArchiveRef);
- pub fn LLVMRustSetDLLExportStorageClass(V: ValueRef);
+ pub fn LLVMRustSetDLLStorageClass(V: ValueRef,
+ C: DLLStorageClassTypes);
pub fn LLVMRustGetSectionName(SI: SectionIteratorRef,
data: *mut *const c_char) -> c_int;
pub fn LLVMWriteSMDiagnosticToString(d: SMDiagnosticRef, s: RustStringRef);
}
+// LLVM requires symbols from this library, but apparently they're not printed
+// during llvm-config?
+#[cfg(windows)]
+#[link(name = "ole32")]
+extern {}
+
pub fn SetInstructionCallConv(instr: ValueRef, cc: CallConv) {
unsafe {
LLVMSetInstructionCallConv(instr, cc as c_uint);
}
}
+pub fn SetDLLStorageClass(global: ValueRef, class: DLLStorageClassTypes) {
+ unsafe {
+ LLVMRustSetDLLStorageClass(global, class);
+ }
+}
+
pub fn SetUnnamedAddr(global: ValueRef, unnamed: bool) {
unsafe {
LLVMSetUnnamedAddr(global, unnamed as Bool);
}
}
+pub fn get_params(llfn: ValueRef) -> Vec<ValueRef> {
+ unsafe {
+ let num_params = LLVMCountParams(llfn);
+ let mut params = Vec::with_capacity(num_params as usize);
+ for idx in 0..num_params {
+ params.push(LLVMGetParam(llfn, idx));
+ }
+
+ params
+ }
+}
+
#[allow(missing_copy_implementations)]
pub enum RustString_opaque {}
pub type RustStringRef = *mut RustString_opaque;
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
- html_favicon_url = "http://www.rust-lang.org/favicon.ico",
+ html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/")]
#![feature(rustc_diagnostic_macros)]
use std::mem::replace;
+use rustc::ast_map;
use rustc::metadata::csearch;
use rustc::middle::def;
use rustc::middle::privacy::ImportUse::*;
use rustc::middle::ty::{self, Ty};
use rustc::util::nodemap::{NodeMap, NodeSet};
-use syntax::{ast, ast_map};
+use syntax::ast;
use syntax::ast_util::{is_local, local_def};
use syntax::codemap::Span;
use syntax::parse::token;
let struct_type = ty::lookup_item_type(self.tcx, id).ty;
let struct_desc = match struct_type.sty {
- ty::ty_struct(_, _) =>
+ ty::TyStruct(_, _) =>
format!("struct `{}`", ty::item_path_str(self.tcx, id)),
// struct variant fields have inherited visibility
- ty::ty_enum(..) => return,
+ ty::TyEnum(..) => return,
_ => self.tcx.sess.span_bug(span, "can't find struct for field")
};
let msg = match name {
fn visit_expr(&mut self, expr: &ast::Expr) {
match expr.node {
ast::ExprField(ref base, ident) => {
- if let ty::ty_struct(id, _) = ty::expr_ty_adjusted(self.tcx, &**base).sty {
+ if let ty::TyStruct(id, _) = ty::expr_ty_adjusted(self.tcx, &**base).sty {
self.check_field(expr.span, id, NamedField(ident.node.name));
}
}
ast::ExprTupField(ref base, idx) => {
- if let ty::ty_struct(id, _) = ty::expr_ty_adjusted(self.tcx, &**base).sty {
+ if let ty::TyStruct(id, _) = ty::expr_ty_adjusted(self.tcx, &**base).sty {
self.check_field(expr.span, id, UnnamedField(idx.node));
}
}
}
ast::ExprStruct(_, ref fields, _) => {
match ty::expr_ty(self.tcx, expr).sty {
- ty::ty_struct(ctor_id, _) => {
+ ty::TyStruct(ctor_id, _) => {
// RFC 736: ensure all unmentioned fields are visible.
// Rather than computing the set of unmentioned fields
// (i.e. `all_fields - fields`), just check them all.
NamedField(field.name));
}
}
- ty::ty_enum(_, _) => {
+ ty::TyEnum(_, _) => {
match self.tcx.def_map.borrow().get(&expr.id).unwrap().full_def() {
def::DefVariant(_, variant_id, _) => {
for field in fields {
match pattern.node {
ast::PatStruct(_, ref fields, _) => {
match ty::pat_ty(self.tcx, pattern).sty {
- ty::ty_struct(id, _) => {
+ ty::TyStruct(id, _) => {
for field in fields {
self.check_field(pattern.span, id,
NamedField(field.node.ident.name));
}
}
- ty::ty_enum(_, _) => {
+ ty::TyEnum(_, _) => {
match self.tcx.def_map.borrow().get(&pattern.id).map(|d| d.full_def()) {
Some(def::DefVariant(_, variant_id, _)) => {
for field in fields {
// elsewhere).
ast::PatEnum(_, Some(ref fields)) => {
match ty::pat_ty(self.tcx, pattern).sty {
- ty::ty_struct(id, _) => {
+ ty::TyStruct(id, _) => {
for (i, field) in fields.iter().enumerate() {
if let ast::PatWild(..) = field.node {
continue
self.check_field(field.span, id, UnnamedField(i));
}
}
- ty::ty_enum(..) => {
+ ty::TyEnum(..) => {
// enum fields have no privacy at this time
}
_ => {}
return
}
- for bound in &**bounds {
+ for bound in bounds.iter() {
self.check_ty_param_bound(bound)
}
}
}
fn visit_generics(&mut self, generics: &ast::Generics) {
- for ty_param in &*generics.ty_params {
- for bound in &*ty_param.bounds {
+ for ty_param in generics.ty_params.iter() {
+ for bound in ty_param.bounds.iter() {
self.check_ty_param_bound(bound)
}
}
for predicate in &generics.where_clause.predicates {
match predicate {
&ast::WherePredicate::BoundPredicate(ref bound_pred) => {
- for bound in &*bound_pred.bounds {
+ for bound in bound_pred.bounds.iter() {
self.check_ty_param_bound(bound)
}
}
.define_value(DefConst(local_def(item.id)), sp, modifiers);
parent.clone()
}
- ItemFn(_, _, _, _, _) => {
+ ItemFn(_, _, _, _, _, _) => {
let name_bindings = self.add_child(name, parent, ForbidDuplicateValues, sp);
let def = DefFn(local_def(item.id), false);
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
- html_favicon_url = "http://www.rust-lang.org/favicon.ico",
+ html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/")]
-#![feature(alloc)]
#![feature(associated_consts)]
-#![feature(collections)]
+#![feature(rc_weak)]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
+#![feature(slice_extras)]
#![feature(staged_api)]
#[macro_use] extern crate log;
use self::ModuleKind::*;
use self::FallbackChecks::*;
+use rustc::ast_map;
use rustc::session::Session;
use rustc::lint;
use rustc::metadata::csearch;
use rustc::metadata::decoder::{DefLike, DlDef, DlField, DlImpl};
use rustc::middle::def::*;
-use rustc::middle::lang_items::LanguageItems;
use rustc::middle::pat_util::pat_bindings;
use rustc::middle::privacy::*;
use rustc::middle::subst::{ParamSpace, FnSpace, TypeSpace};
use syntax::ast::{TyRptr, TyStr, TyUs, TyU8, TyU16, TyU32, TyU64, TyUint};
use syntax::ast::TypeImplItem;
use syntax::ast;
-use syntax::ast_map;
use syntax::ast_util::{local_def, walk_pat};
use syntax::attr::AttrMetaMethods;
use syntax::ext::mtwt;
// `visit::walk_variant` without the discriminant expression.
match variant.node.kind {
ast::TupleVariantKind(ref variant_arguments) => {
- for variant_argument in variant_arguments.iter() {
+ for variant_argument in variant_arguments {
self.visit_ty(&*variant_argument.ty);
}
}
_: Span,
node_id: NodeId) {
let rib_kind = match function_kind {
- visit::FkItemFn(_, generics, _, _, _) => {
+ visit::FkItemFn(_, generics, _, _, _, _) => {
self.visit_generics(generics);
ItemRibKind
}
// Descend into children and anonymous children.
build_reduced_graph::populate_module_if_necessary(self, &module_);
- for (_, child_node) in &*module_.children.borrow() {
+ for (_, child_node) in module_.children.borrow().iter() {
match child_node.get_module_if_available() {
None => {
// Continue.
}
}
- for (_, module_) in &*module_.anonymous_children.borrow() {
+ for (_, module_) in module_.anonymous_children.borrow().iter() {
self.report_unresolved_imports(module_.clone());
}
}
ItemRibKind),
|this| visit::walk_item(this, item));
}
- ItemFn(_, _, _, ref generics, _) => {
+ ItemFn(_, _, _, _, ref generics, _) => {
self.with_type_parameter_rib(HasTypeParameters(generics,
FnSpace,
ItemRibKind),
}
fn resolve_generics(&mut self, generics: &Generics) {
- for type_parameter in &*generics.ty_params {
+ for type_parameter in generics.ty_params.iter() {
self.check_if_primitive_type_name(type_parameter.ident.name, type_parameter.span);
}
for predicate in &generics.where_clause.predicates {
"type name"
};
- let msg = format!("use of undeclared {} `{}`", kind,
- path_names_to_string(path, 0));
+ let self_type_name = special_idents::type_self.name;
+ let is_invalid_self_type_name =
+ path.segments.len() > 0 &&
+ maybe_qself.is_none() &&
+ path.segments[0].identifier.name == self_type_name;
+ let msg = if is_invalid_self_type_name {
+ "use of `Self` outside of an impl or trait".to_string()
+ } else {
+ format!("use of undeclared {} `{}`",
+ kind, path_names_to_string(path, 0))
+ };
+
self.resolve_error(ty.span, &msg[..]);
}
}
NoSuggestion
}
- fn find_best_match_for_name(&mut self, name: &str, max_distance: usize)
- -> Option<String> {
- let this = &mut *self;
-
+ fn find_best_match_for_name(&mut self, name: &str) -> Option<String> {
let mut maybes: Vec<token::InternedString> = Vec::new();
let mut values: Vec<usize> = Vec::new();
- for rib in this.value_ribs.iter().rev() {
+ for rib in self.value_ribs.iter().rev() {
for (&k, _) in &rib.bindings {
maybes.push(token::get_name(k));
values.push(usize::MAX);
}
}
+ // As a loose rule to avoid obviously incorrect suggestions, clamp the
+ // maximum edit distance we will accept for a suggestion to one third of
+ // the typo'd name's length.
+ let max_distance = std::cmp::max(name.len(), 3) / 3;
+
if !values.is_empty() &&
- values[smallest] != usize::MAX &&
- values[smallest] < name.len() + 2 &&
values[smallest] <= max_distance &&
name != &maybes[smallest][..] {
NoSuggestion => {
// limit search to 5 to reduce the number
// of stupid suggestions
- self.find_best_match_for_name(&path_name, 5)
+ self.find_best_match_for_name(&path_name)
.map_or("".to_string(),
|x| format!("`{}`", x))
}
build_reduced_graph::populate_module_if_necessary(self, &search_module);
{
- for (_, child_names) in &*search_module.children.borrow() {
+ for (_, child_names) in search_module.children.borrow().iter() {
let def = match child_names.def_for_namespace(TypeNS) {
Some(def) => def,
None => continue
}
// Look for imports.
- for (_, import) in &*search_module.import_resolutions.borrow() {
+ for (_, import) in search_module.import_resolutions.borrow().iter() {
let target = match import.target_for_namespace(TypeNS) {
None => continue,
Some(target) => target,
debug!("Children:");
build_reduced_graph::populate_module_if_necessary(self, &module_);
- for (&name, _) in &*module_.children.borrow() {
+ for (&name, _) in module_.children.borrow().iter() {
debug!("* {}", token::get_name(name));
}
debug!("Import resolutions:");
let import_resolutions = module_.import_resolutions.borrow();
- for (&name, import_resolution) in &*import_resolutions {
+ for (&name, import_resolution) in import_resolutions.iter() {
let value_repr;
match import_resolution.target_for_namespace(ValueNS) {
None => { value_repr = "".to_string(); }
/// Entry point to crate resolution.
pub fn resolve_crate<'a, 'tcx>(session: &'a Session,
ast_map: &'a ast_map::Map<'tcx>,
- _: &LanguageItems,
- krate: &Crate,
make_glob_map: MakeGlobMap)
-> CrateMap {
+ let krate = ast_map.krate();
let mut resolver = Resolver::new(session, ast_map, krate.span, make_glob_map);
build_reduced_graph::build_reduced_graph(&mut resolver, krate);
}
}
-#[cfg(stage0)]
-__build_diagnostic_array! { DIAGNOSTICS }
-#[cfg(not(stage0))]
__build_diagnostic_array! { librustc_resolve, DIAGNOSTICS }
self.record_exports_for_module(&*module_);
build_reduced_graph::populate_module_if_necessary(self.resolver, &module_);
- for (_, child_name_bindings) in &*module_.children.borrow() {
+ for (_, child_name_bindings) in module_.children.borrow().iter() {
match child_name_bindings.get_module_if_available() {
None => {
// Nothing to do.
}
}
- for (_, child_module) in &*module_.anonymous_children.borrow() {
+ for (_, child_module) in module_.anonymous_children.borrow().iter() {
self.record_exports_for_module_subtree(child_module.clone());
}
}
fn add_exports_for_module(&mut self,
exports: &mut Vec<Export>,
module_: &Module) {
- for (name, import_resolution) in &*module_.import_resolutions.borrow() {
+ for (name, import_resolution) in module_.import_resolutions.borrow().iter() {
if !import_resolution.is_public {
continue
}
use DefModifiers;
use Module;
+use ModuleKind;
use Namespace::{self, TypeNS, ValueNS};
use NameBindings;
use NamespaceResult::{BoundResult, UnboundResult, UnknownResult};
self.resolver.current_module = orig_module;
build_reduced_graph::populate_module_if_necessary(self.resolver, &module_);
- for (_, child_node) in &*module_.children.borrow() {
+ for (_, child_node) in module_.children.borrow().iter() {
match child_node.get_module_if_available() {
None => {
// Nothing to do.
}
}
- for (_, child_module) in &*module_.anonymous_children.borrow() {
+ for (_, child_module) in module_.anonymous_children.borrow().iter() {
self.resolve_imports_for_module_subtree(child_module.clone());
}
}
// Add all resolved imports from the containing module.
let import_resolutions = target_module.import_resolutions.borrow();
- for (ident, target_import_resolution) in &*import_resolutions {
+ for (ident, target_import_resolution) in import_resolutions.iter() {
debug!("(resolving glob import) writing module resolution \
{} into `{}`",
token::get_name(*ident),
// Add all children from the containing module.
build_reduced_graph::populate_module_if_necessary(self.resolver, &target_module);
- for (&name, name_bindings) in &*target_module.children.borrow() {
+ for (&name, name_bindings) in target_module.children.borrow().iter() {
self.merge_import_resolution(module_,
target_module.clone(),
import_directive,
}
// Add external module children from the containing module.
- for (&name, module) in &*target_module.external_module_children.borrow() {
+ for (&name, module) in target_module.external_module_children.borrow().iter() {
let name_bindings =
Rc::new(Resolver::create_name_bindings_from_module(module.clone()));
self.merge_import_resolution(module_,
match target {
Some(ref target) if target.shadowable != Shadowable::Always => {
let ns_word = match namespace {
- TypeNS => "type",
+ TypeNS => {
+ if let Some(ref ty_def) = *target.bindings.type_def.borrow() {
+ match ty_def.module_def {
+ Some(ref module)
+ if module.kind.get() == ModuleKind::NormalModuleKind =>
+ "module",
+ Some(ref module)
+ if module.kind.get() == ModuleKind::TraitModuleKind =>
+ "trait",
+ _ => "type",
+ }
+ } else { "type" }
+ },
ValueNS => "value",
};
span_err!(self.resolver.session, import_span, E0252,
match import_resolution.type_target {
Some(ref target) if target.shadowable != Shadowable::Always => {
if let Some(ref ty) = *name_bindings.type_def.borrow() {
- let (what, note) = if ty.module_def.is_some() {
- ("existing submodule", "note conflicting module here")
- } else {
- ("type in this module", "note conflicting type here")
+ let (what, note) = match ty.module_def {
+ Some(ref module)
+ if module.kind.get() == ModuleKind::NormalModuleKind =>
+ ("existing submodule", "note conflicting module here"),
+ Some(ref module)
+ if module.kind.get() == ModuleKind::TraitModuleKind =>
+ ("trait in this module", "note conflicting trait here"),
+ _ => ("type in this module", "note conflicting type here"),
};
span_err!(self.resolver.session, import_span, E0256,
"import `{}` conflicts with {}",
// except according to those terms.
use super::archive::{Archive, ArchiveBuilder, ArchiveConfig, METADATA_FILENAME};
-use super::archive;
-use super::rpath;
+use super::linker::{Linker, GnuLinker, MsvcLinker};
use super::rpath::RPathConfig;
+use super::rpath;
use super::svh::Svh;
use session::config;
use session::config::NoDebugInfo;
use metadata::common::LinkMeta;
use metadata::{encoder, cstore, filesearch, csearch, creader};
use metadata::filesearch::FileDoesntMatch;
-use trans::{CrateContext, CrateTranslation, gensym_name};
use middle::ty::{self, Ty};
+use rustc::ast_map::{PathElem, PathElems, PathName};
+use trans::{CrateContext, CrateTranslation, gensym_name};
use util::common::time;
-use util::ppaux;
use util::sha2::{Digest, Sha256};
use util::fs::fix_windows_verbatim_for_gcc;
use rustc_back::tempdir::TempDir;
+use std::env;
use std::ffi::OsString;
use std::fs::{self, PathExt};
use std::io::{self, Read, Write};
use flate;
use serialize::hex::ToHex;
use syntax::ast;
-use syntax::ast_map::{PathElem, PathElems, PathName};
use syntax::attr::AttrMetaMethods;
use syntax::codemap::Span;
use syntax::parse::token;
symbol_hasher.input_str(&link_meta.crate_name);
symbol_hasher.input_str("-");
symbol_hasher.input_str(link_meta.crate_hash.as_str());
- for meta in &*tcx.sess.crate_metadata.borrow() {
+ for meta in tcx.sess.crate_metadata.borrow().iter() {
symbol_hasher.input_str(&meta[..]);
}
symbol_hasher.input_str("-");
symbol_hasher.input_str(&encoder::encoded_ty(tcx, t));
// Prefix with 'h' so that it never blends into adjacent digits
- let mut hash = String::from_str("h");
+ let mut hash = String::from("h");
hash.push_str(&truncated_hash_result(symbol_hasher));
hash
}
}
pub fn mangle<PI: Iterator<Item=PathElem>>(path: PI,
- hash: Option<&str>) -> String {
+ hash: Option<&str>) -> String {
// Follow C++ namespace-mangling style, see
// http://en.wikipedia.org/wiki/Name_mangling for more info.
//
// To be able to work on all platforms and get *some* reasonable output, we
// use C++ name-mangling.
- let mut n = String::from_str("_ZN"); // _Z == Begin name-sequence, N == nested
+ let mut n = String::from("_ZN"); // _Z == Begin name-sequence, N == nested
fn push(n: &mut String, s: &str) {
let sani = sanitize(s);
pub fn mangle_internal_name_by_type_and_seq<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
t: Ty<'tcx>,
name: &str) -> String {
- let s = ppaux::ty_to_string(ccx.tcx(), t);
- let path = [PathName(token::intern(&s[..])),
+ let path = [PathName(token::intern(&t.to_string())),
gensym_name(name)];
let hash = get_symbol_hash(ccx, t);
mangle(path.iter().cloned(), Some(&hash[..]))
}
pub fn mangle_internal_name_by_path_and_seq(path: PathElems, flav: &str) -> String {
- mangle(path.chain(Some(gensym_name(flav)).into_iter()), None)
+ mangle(path.chain(Some(gensym_name(flav))), None)
}
pub fn get_cc_prog(sess: &Session) -> String {
}
}
+pub fn get_ar_prog(sess: &Session) -> String {
+ sess.opts.cg.ar.clone().unwrap_or_else(|| {
+ sess.target.target.options.ar.clone()
+ })
+}
+
+fn command_path(sess: &Session) -> OsString {
+ // The compiler's sysroot often has some bundled tools, so add it to the
+ // PATH for the child.
+ let mut new_path = sess.host_filesearch(PathKind::All)
+ .get_tools_search_paths();
+ if let Some(path) = env::var_os("PATH") {
+ new_path.extend(env::split_paths(&path));
+ }
+ env::join_paths(new_path).unwrap()
+}
+
pub fn remove(sess: &Session, path: &Path) {
match fs::remove_file(path) {
Ok(..) => {}
outputs: &OutputFilenames,
crate_name: &str) -> Vec<PathBuf> {
let mut out_filenames = Vec::new();
- for &crate_type in &*sess.crate_types.borrow() {
+ for &crate_type in sess.crate_types.borrow().iter() {
if invalid_output_for_target(sess, crate_type) {
sess.bug(&format!("invalid output type `{:?}` for target os `{}`",
crate_type, sess.opts.target_triple));
trans: Option<&CrateTranslation>, // None == no metadata/bytecode
obj_filename: &Path,
out_filename: &Path) -> ArchiveBuilder<'a> {
+ info!("preparing rlib from {:?} to {:?}", obj_filename, out_filename);
let handler = &sess.diagnostic().handler;
let config = ArchiveConfig {
handler: handler,
lib_search_paths: archive_search_paths(sess),
slib_prefix: sess.target.target.options.staticlib_prefix.clone(),
slib_suffix: sess.target.target.options.staticlib_suffix.clone(),
- maybe_ar_prog: sess.opts.cg.ar.clone()
+ ar_prog: get_ar_prog(sess),
+ command_path: command_path(sess),
};
let mut ab = ArchiveBuilder::create(config);
ab.add_file(obj_filename).unwrap();
- for &(ref l, kind) in &*sess.cstore.get_used_libraries().borrow() {
+ for &(ref l, kind) in sess.cstore.get_used_libraries().borrow().iter() {
match kind {
- cstore::NativeStatic => {
- ab.add_native_library(&l[..]).unwrap();
- }
+ cstore::NativeStatic => ab.add_native_library(&l).unwrap(),
cstore::NativeFramework | cstore::NativeUnknown => {}
}
}
}) {
Ok(..) => {}
Err(e) => {
- sess.err(&format!("failed to write {}: {}",
- metadata.display(),
- e));
- sess.abort_if_errors();
+ sess.fatal(&format!("failed to write {}: {}",
+ metadata.display(), e));
}
}
ab.add_file(&metadata).unwrap();
&bc_data_deflated) {
Ok(()) => {}
Err(e) => {
- sess.err(&format!("failed to write compressed bytecode: \
- {}", e));
- sess.abort_if_errors()
+ sess.fatal(&format!("failed to write compressed \
+ bytecode: {}", e));
}
};
ab.add_rlib(&p, &name[..], sess.lto()).unwrap();
let native_libs = csearch::get_native_libraries(&sess.cstore, cnum);
- all_native_libs.extend(native_libs.into_iter());
+ all_native_libs.extend(native_libs);
}
ab.update_symbols();
// links to all upstream files as well.
fn link_natively(sess: &Session, trans: &CrateTranslation, dylib: bool,
obj_filename: &Path, out_filename: &Path) {
+ info!("preparing dylib? ({}) from {:?} to {:?}", dylib, obj_filename,
+ out_filename);
let tmpdir = TempDir::new("rustc").ok().expect("needs a temp dir");
// The invocations of cc share some flags across platforms
let pname = get_cc_prog(sess);
- let mut cmd = Command::new(&pname[..]);
+ let mut cmd = Command::new(&pname);
+ cmd.env("PATH", command_path(sess));
let root = sess.target_filesearch(PathKind::Native).get_lib_path();
cmd.args(&sess.target.target.options.pre_link_args);
cmd.arg(root.join(obj));
}
- link_args(&mut cmd, sess, dylib, tmpdir.path(),
- trans, obj_filename, out_filename);
- if !sess.target.target.options.no_compiler_rt {
- cmd.arg("-lcompiler-rt");
+ {
+ let mut linker = if sess.target.target.options.is_like_msvc {
+ Box::new(MsvcLinker { cmd: &mut cmd, sess: &sess }) as Box<Linker>
+ } else {
+ Box::new(GnuLinker { cmd: &mut cmd, sess: &sess }) as Box<Linker>
+ };
+ link_args(&mut *linker, sess, dylib, tmpdir.path(),
+ trans, obj_filename, out_filename);
+ if !sess.target.target.options.no_compiler_rt {
+ linker.link_staticlib("compiler-rt");
+ }
}
for obj in &sess.target.target.options.post_link_objects {
cmd.arg(root.join(obj));
sess.abort_if_errors();
// Invoke the system linker
- debug!("{:?}", &cmd);
+ info!("{:?}", &cmd);
let prog = time(sess.time_passes(), "running linker", (), |()| cmd.output());
match prog {
Ok(prog) => {
sess.note(str::from_utf8(&output[..]).unwrap());
sess.abort_if_errors();
}
- debug!("linker stderr:\n{}", String::from_utf8(prog.stderr).unwrap());
- debug!("linker stdout:\n{}", String::from_utf8(prog.stdout).unwrap());
+ info!("linker stderr:\n{}", String::from_utf8(prog.stderr).unwrap());
+ info!("linker stdout:\n{}", String::from_utf8(prog.stdout).unwrap());
},
Err(e) => {
- sess.err(&format!("could not exec the linker `{}`: {}",
- pname,
- e));
- sess.abort_if_errors();
+ sess.fatal(&format!("could not exec the linker `{}`: {}", pname, e));
}
}
if sess.target.target.options.is_like_osx && sess.opts.debuginfo != NoDebugInfo {
match Command::new("dsymutil").arg(out_filename).output() {
Ok(..) => {}
- Err(e) => {
- sess.err(&format!("failed to run dsymutil: {}", e));
- sess.abort_if_errors();
- }
+ Err(e) => sess.fatal(&format!("failed to run dsymutil: {}", e)),
}
}
}
-fn link_args(cmd: &mut Command,
+fn link_args(cmd: &mut Linker,
sess: &Session,
dylib: bool,
tmpdir: &Path,
// target descriptor
let t = &sess.target.target;
- cmd.arg("-L").arg(&fix_windows_verbatim_for_gcc(&lib_path));
-
- cmd.arg("-o").arg(out_filename).arg(obj_filename);
-
+ cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path));
+ cmd.add_object(obj_filename);
+ cmd.output_filename(out_filename);
// Stack growth requires statically linking a __morestack function. Note
// that this is listed *before* all other libraries. Due to the usage of the
// will include the __morestack symbol 100% of the time, always resolving
// references to it even if the object above didn't use it.
if t.options.morestack {
- if t.options.is_like_osx {
- let morestack = lib_path.join("libmorestack.a");
-
- let mut v = OsString::from("-Wl,-force_load,");
- v.push(&morestack);
- cmd.arg(&v);
- } else {
- cmd.args(&["-Wl,--whole-archive", "-lmorestack", "-Wl,--no-whole-archive"]);
- }
+ cmd.link_whole_staticlib("morestack", &[lib_path]);
}
// When linking a dynamic library, we put the metadata into a section of the
// executable. This metadata is in a separate object file from the main
// object file, so we link that in here.
if dylib {
- cmd.arg(&obj_filename.with_extension("metadata.o"));
+ cmd.add_object(&obj_filename.with_extension("metadata.o"));
}
- if t.options.is_like_osx {
- // The dead_strip option to the linker specifies that functions and data
- // unreachable by the entry point will be removed. This is quite useful
- // with Rust's compilation model of compiling libraries at a time into
- // one object file. For example, this brings hello world from 1.7MB to
- // 458K.
- //
- // Note that this is done for both executables and dynamic libraries. We
- // won't get much benefit from dylibs because LLVM will have already
- // stripped away as much as it could. This has not been seen to impact
- // link times negatively.
- //
- // -dead_strip can't be part of the pre_link_args because it's also used
- // for partial linking when using multiple codegen units (-r). So we
- // insert it here.
- cmd.arg("-Wl,-dead_strip");
- }
-
- // If we're building a dylib, we don't use --gc-sections because LLVM has
- // already done the best it can do, and we also don't want to eliminate the
- // metadata. If we're building an executable, however, --gc-sections drops
- // the size of hello world from 1.8MB to 597K, a 67% reduction.
- if !dylib && !t.options.is_like_osx {
- cmd.arg("-Wl,--gc-sections");
- }
+ // Try to strip as much out of the generated object by removing unused
+ // sections if possible. See more comments in linker.rs
+ cmd.gc_sections(dylib);
let used_link_args = sess.cstore.get_used_link_args().borrow();
- if t.options.position_independent_executables {
+ if !dylib && t.options.position_independent_executables {
let empty_vec = Vec::new();
let empty_str = String::new();
let args = sess.opts.cg.link_args.as_ref().unwrap_or(&empty_vec);
let mut args = args.iter().chain(used_link_args.iter());
- if !dylib
- && (t.options.relocation_model == "pic"
- || *sess.opts.cg.relocation_model.as_ref()
- .unwrap_or(&empty_str) == "pic")
+ let relocation_model = sess.opts.cg.relocation_model.as_ref()
+ .unwrap_or(&empty_str);
+ if (t.options.relocation_model == "pic" || *relocation_model == "pic")
&& !args.any(|x| *x == "-static") {
- cmd.arg("-pie");
+ cmd.position_independent_executable();
}
}
- if t.options.linker_is_gnu {
- // GNU-style linkers support optimization with -O. GNU ld doesn't need a
- // numeric argument, but other linkers do.
- if sess.opts.optimize == config::Default ||
- sess.opts.optimize == config::Aggressive {
- cmd.arg("-Wl,-O1");
- }
- }
+ // Pass optimization flags down to the linker.
+ cmd.optimize();
// We want to prevent the compiler from accidentally leaking in any system
// libraries, so we explicitly ask gcc to not link to any libraries by
// default. Note that this does not happen for windows because windows pulls
// in some large number of libraries and I couldn't quite figure out which
// subset we wanted.
- if !t.options.is_like_windows {
- cmd.arg("-nodefaultlibs");
- }
-
- // Mark all dynamic libraries and executables as compatible with ASLR
- // FIXME #17098: ASLR breaks gdb
- if t.options.is_like_windows && sess.opts.debuginfo == NoDebugInfo {
- // cmd.arg("-Wl,--dynamicbase");
- }
+ cmd.no_default_libraries();
// Take careful note of the ordering of the arguments we pass to the linker
// here. Linkers will assume that things on the left depend on things to the
// # Telling the linker what we're doing
if dylib {
- // On mac we need to tell the linker to let this library be rpathed
- if sess.target.target.options.is_like_osx {
- cmd.args(&["-dynamiclib", "-Wl,-dylib"]);
-
- if sess.opts.cg.rpath {
- let mut v = OsString::from("-Wl,-install_name,@rpath/");
- v.push(out_filename.file_name().unwrap());
- cmd.arg(&v);
- }
- } else {
- cmd.arg("-shared");
- }
+ cmd.build_dylib(out_filename);
}
// FIXME (#2397): At some point we want to rpath our guesses as to
// Finally add all the linker arguments provided on the command line along
// with any #[link_args] attributes found inside the crate
- let empty = Vec::new();
- cmd.args(&sess.opts.cg.link_args.as_ref().unwrap_or(&empty));
- cmd.args(&used_link_args[..]);
+ if let Some(ref args) = sess.opts.cg.link_args {
+ cmd.args(args);
+ }
+ cmd.args(&used_link_args);
}
// # Native library linking
// Also note that the native libraries linked here are only the ones located
// in the current crate. Upstream crates with native library dependencies
// may have their native library pulled in above.
-fn add_local_native_libraries(cmd: &mut Command, sess: &Session) {
+fn add_local_native_libraries(cmd: &mut Linker, sess: &Session) {
sess.target_filesearch(PathKind::All).for_each_lib_search_path(|path, k| {
match k {
- PathKind::Framework => { cmd.arg("-F").arg(path); }
- _ => { cmd.arg("-L").arg(&fix_windows_verbatim_for_gcc(path)); }
+ PathKind::Framework => { cmd.framework_path(path); }
+ _ => { cmd.include_path(&fix_windows_verbatim_for_gcc(path)); }
}
FileDoesntMatch
});
- // Some platforms take hints about whether a library is static or dynamic.
- // For those that support this, we ensure we pass the option if the library
- // was flagged "static" (most defaults are dynamic) to ensure that if
- // libfoo.a and libfoo.so both exist that the right one is chosen.
- let takes_hints = !sess.target.target.options.is_like_osx;
-
let libs = sess.cstore.get_used_libraries();
let libs = libs.borrow();
kind != cstore::NativeStatic
});
- // Platforms that take hints generally also support the --whole-archive
- // flag. We need to pass this flag when linking static native libraries to
- // ensure the entire library is included.
- //
- // For more details see #15460, but the gist is that the linker will strip
- // away any unused objects in the archive if we don't otherwise explicitly
- // reference them. This can occur for libraries which are just providing
- // bindings, libraries with generic functions, etc.
- if takes_hints {
- cmd.arg("-Wl,--whole-archive").arg("-Wl,-Bstatic");
- }
+ // Some platforms take hints about whether a library is static or dynamic.
+ // For those that support this, we ensure we pass the option if the library
+ // was flagged "static" (most defaults are dynamic) to ensure that if
+ // libfoo.a and libfoo.so both exist that the right one is chosen.
+ cmd.hint_static();
+
let search_path = archive_search_paths(sess);
for l in staticlibs {
- if takes_hints {
- cmd.arg(&format!("-l{}", l));
- } else {
- // -force_load is the OSX equivalent of --whole-archive, but it
- // involves passing the full path to the library to link.
- let lib = archive::find_library(&l[..],
- &sess.target.target.options.staticlib_prefix,
- &sess.target.target.options.staticlib_suffix,
- &search_path[..],
- &sess.diagnostic().handler);
- let mut v = OsString::from("-Wl,-force_load,");
- v.push(&lib);
- cmd.arg(&v);
- }
- }
- if takes_hints {
- cmd.arg("-Wl,--no-whole-archive").arg("-Wl,-Bdynamic");
+ // Here we explicitly ask that the entire archive is included into the
+ // result artifact. For more details see #15460, but the gist is that
+ // the linker will strip away any unused objects in the archive if we
+ // don't otherwise explicitly reference them. This can occur for
+ // libraries which are just providing bindings, libraries with generic
+ // functions, etc.
+ cmd.link_whole_staticlib(l, &search_path);
}
+ cmd.hint_dynamic();
+
for &(ref l, kind) in others {
match kind {
- cstore::NativeUnknown => {
- cmd.arg(&format!("-l{}", l));
- }
- cstore::NativeFramework => {
- cmd.arg("-framework").arg(&l[..]);
- }
+ cstore::NativeUnknown => cmd.link_dylib(l),
+ cstore::NativeFramework => cmd.link_framework(l),
cstore::NativeStatic => unreachable!(),
}
}
// Rust crates are not considered at all when creating an rlib output. All
// dependencies will be linked when producing the final output (instead of
// the intermediate rlib version)
-fn add_upstream_rust_crates(cmd: &mut Command, sess: &Session,
+fn add_upstream_rust_crates(cmd: &mut Linker, sess: &Session,
dylib: bool, tmpdir: &Path,
trans: &CrateTranslation) {
// All of the heavy lifting has previously been accomplished by the
}
// Adds the static "rlib" versions of all crates to the command line.
- fn add_static_crate(cmd: &mut Command, sess: &Session, tmpdir: &Path,
+ fn add_static_crate(cmd: &mut Linker, sess: &Session, tmpdir: &Path,
cratepath: &Path) {
// When performing LTO on an executable output, all of the
// bytecode from the upstream libraries has already been
match fs::copy(&cratepath, &dst) {
Ok(..) => {}
Err(e) => {
- sess.err(&format!("failed to copy {} to {}: {}",
- cratepath.display(),
- dst.display(),
- e));
- sess.abort_if_errors();
+ sess.fatal(&format!("failed to copy {} to {}: {}",
+ cratepath.display(),
+ dst.display(), e));
}
}
// Fix up permissions of the copy, as fs::copy() preserves
}) {
Ok(..) => {}
Err(e) => {
- sess.err(&format!("failed to chmod {} when preparing \
- for LTO: {}", dst.display(),
- e));
- sess.abort_if_errors();
+ sess.fatal(&format!("failed to chmod {} when preparing \
+ for LTO: {}", dst.display(), e));
}
}
let handler = &sess.diagnostic().handler;
lib_search_paths: archive_search_paths(sess),
slib_prefix: sess.target.target.options.staticlib_prefix.clone(),
slib_suffix: sess.target.target.options.staticlib_suffix.clone(),
- maybe_ar_prog: sess.opts.cg.ar.clone()
+ ar_prog: get_ar_prog(sess),
+ command_path: command_path(sess),
};
let mut archive = Archive::open(config);
archive.remove_file(&format!("{}.o", name));
let files = archive.files();
if files.iter().any(|s| s.ends_with(".o")) {
- cmd.arg(&dst);
+ cmd.link_rlib(&dst);
}
});
} else {
- cmd.arg(&fix_windows_verbatim_for_gcc(cratepath));
+ cmd.link_rlib(&fix_windows_verbatim_for_gcc(cratepath));
}
}
// Same thing as above, but for dynamic crates instead of static crates.
- fn add_dynamic_crate(cmd: &mut Command, sess: &Session, cratepath: &Path) {
+ fn add_dynamic_crate(cmd: &mut Linker, sess: &Session, cratepath: &Path) {
// If we're performing LTO, then it should have been previously required
// that all upstream rust dependencies were available in an rlib format.
assert!(!sess.lto());
// Just need to tell the linker about where the library lives and
// what its name is
if let Some(dir) = cratepath.parent() {
- cmd.arg("-L").arg(&fix_windows_verbatim_for_gcc(dir));
+ cmd.include_path(&fix_windows_verbatim_for_gcc(dir));
}
let filestem = cratepath.file_stem().unwrap().to_str().unwrap();
- cmd.arg(&format!("-l{}", unlib(&sess.target, filestem)));
+ cmd.link_dylib(&unlib(&sess.target, filestem));
}
}
// generic function calls a native function, then the generic function must
// be instantiated in the target crate, meaning that the native symbol must
// also be resolved in the target crate.
-fn add_upstream_native_libraries(cmd: &mut Command, sess: &Session) {
+fn add_upstream_native_libraries(cmd: &mut Linker, sess: &Session) {
// Be sure to use a topological sorting of crates because there may be
// interdependencies between native libraries. When passing -nodefaultlibs,
// for example, almost all native libraries depend on libc, so we have to
let libs = csearch::get_native_libraries(&sess.cstore, cnum);
for &(kind, ref lib) in &libs {
match kind {
- cstore::NativeUnknown => {
- cmd.arg(&format!("-l{}", *lib));
- }
- cstore::NativeFramework => {
- cmd.arg("-framework");
- cmd.arg(&lib[..]);
- }
+ cstore::NativeUnknown => cmd.link_dylib(lib),
+ cstore::NativeFramework => cmd.link_framework(lib),
cstore::NativeStatic => {
sess.bug("statics shouldn't be propagated");
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::ffi::OsString;
+use std::path::{Path, PathBuf};
+use std::process::Command;
+
+use rustc_back::archive;
+use session::Session;
+use session::config;
+
+/// Linker abstraction used by back::link to build up the command to invoke a
+/// linker.
+///
+/// This trait is the total list of requirements needed by `back::link` and
+/// represents the meaning of each option being passed down. This trait is then
+/// used to dispatch on whether a GNU-like linker (generally `ld.exe`) or an
+/// MSVC linker (e.g. `link.exe`) is being used.
+pub trait Linker {
+ fn link_dylib(&mut self, lib: &str);
+ fn link_framework(&mut self, framework: &str);
+ fn link_staticlib(&mut self, lib: &str);
+ fn link_rlib(&mut self, lib: &Path);
+ fn link_whole_staticlib(&mut self, lib: &str, search_path: &[PathBuf]);
+ fn include_path(&mut self, path: &Path);
+ fn framework_path(&mut self, path: &Path);
+ fn output_filename(&mut self, path: &Path);
+ fn add_object(&mut self, path: &Path);
+ fn gc_sections(&mut self, is_dylib: bool);
+ fn position_independent_executable(&mut self);
+ fn optimize(&mut self);
+ fn no_default_libraries(&mut self);
+ fn build_dylib(&mut self, out_filename: &Path);
+ fn args(&mut self, args: &[String]);
+ fn hint_static(&mut self);
+ fn hint_dynamic(&mut self);
+ fn whole_archives(&mut self);
+ fn no_whole_archives(&mut self);
+}
+
+pub struct GnuLinker<'a> {
+ pub cmd: &'a mut Command,
+ pub sess: &'a Session,
+}
+
+impl<'a> GnuLinker<'a> {
+ fn takes_hints(&self) -> bool {
+ !self.sess.target.target.options.is_like_osx
+ }
+}
+
+impl<'a> Linker for GnuLinker<'a> {
+ fn link_dylib(&mut self, lib: &str) { self.cmd.arg("-l").arg(lib); }
+ fn link_staticlib(&mut self, lib: &str) { self.cmd.arg("-l").arg(lib); }
+ fn link_rlib(&mut self, lib: &Path) { self.cmd.arg(lib); }
+ fn include_path(&mut self, path: &Path) { self.cmd.arg("-L").arg(path); }
+ fn framework_path(&mut self, path: &Path) { self.cmd.arg("-F").arg(path); }
+ fn output_filename(&mut self, path: &Path) { self.cmd.arg("-o").arg(path); }
+ fn add_object(&mut self, path: &Path) { self.cmd.arg(path); }
+ fn position_independent_executable(&mut self) { self.cmd.arg("-pie"); }
+ fn args(&mut self, args: &[String]) { self.cmd.args(args); }
+
+ fn link_framework(&mut self, framework: &str) {
+ self.cmd.arg("-framework").arg(framework);
+ }
+
+ fn link_whole_staticlib(&mut self, lib: &str, search_path: &[PathBuf]) {
+ let target = &self.sess.target.target;
+ if !target.options.is_like_osx {
+ self.cmd.arg("-Wl,--whole-archive")
+ .arg("-l").arg(lib)
+ .arg("-Wl,--no-whole-archive");
+ } else {
+ // -force_load is the OSX equivalent of --whole-archive, but it
+ // involves passing the full path to the library to link.
+ let mut v = OsString::from("-Wl,-force_load,");
+ v.push(&archive::find_library(lib,
+ &target.options.staticlib_prefix,
+ &target.options.staticlib_suffix,
+ search_path,
+ &self.sess.diagnostic().handler));
+ self.cmd.arg(&v);
+ }
+ }
+
+ fn gc_sections(&mut self, is_dylib: bool) {
+ // The dead_strip option to the linker specifies that functions and data
+ // unreachable by the entry point will be removed. This is quite useful
+ // with Rust's compilation model of compiling libraries at a time into
+ // one object file. For example, this brings hello world from 1.7MB to
+ // 458K.
+ //
+ // Note that this is done for both executables and dynamic libraries. We
+ // won't get much benefit from dylibs because LLVM will have already
+ // stripped away as much as it could. This has not been seen to impact
+ // link times negatively.
+ //
+ // -dead_strip can't be part of the pre_link_args because it's also used
+ // for partial linking when using multiple codegen units (-r). So we
+ // insert it here.
+ if self.sess.target.target.options.is_like_osx {
+ self.cmd.arg("-Wl,-dead_strip");
+
+ // If we're building a dylib, we don't use --gc-sections because LLVM
+ // has already done the best it can do, and we also don't want to
+ // eliminate the metadata. If we're building an executable, however,
+ // --gc-sections drops the size of hello world from 1.8MB to 597K, a 67%
+ // reduction.
+ } else if !is_dylib {
+ self.cmd.arg("-Wl,--gc-sections");
+ }
+ }
+
+ fn optimize(&mut self) {
+ if !self.sess.target.target.options.linker_is_gnu { return }
+
+ // GNU-style linkers support optimization with -O. GNU ld doesn't
+ // need a numeric argument, but other linkers do.
+ if self.sess.opts.optimize == config::Default ||
+ self.sess.opts.optimize == config::Aggressive {
+ self.cmd.arg("-Wl,-O1");
+ }
+ }
+
+ fn no_default_libraries(&mut self) {
+ // Unfortunately right now passing -nodefaultlibs to gcc on windows
+ // doesn't work so hot (in terms of native dependencies). This if
+ // statement should hopefully be removed one day though!
+ if !self.sess.target.target.options.is_like_windows {
+ self.cmd.arg("-nodefaultlibs");
+ }
+ }
+
+ fn build_dylib(&mut self, out_filename: &Path) {
+ // On mac we need to tell the linker to let this library be rpathed
+ if self.sess.target.target.options.is_like_osx {
+ self.cmd.args(&["-dynamiclib", "-Wl,-dylib"]);
+
+ if self.sess.opts.cg.rpath {
+ let mut v = OsString::from("-Wl,-install_name,@rpath/");
+ v.push(out_filename.file_name().unwrap());
+ self.cmd.arg(&v);
+ }
+ } else {
+ self.cmd.arg("-shared");
+ }
+ }
+
+ fn whole_archives(&mut self) {
+ if !self.takes_hints() { return }
+ self.cmd.arg("-Wl,--whole-archive");
+ }
+
+ fn no_whole_archives(&mut self) {
+ if !self.takes_hints() { return }
+ self.cmd.arg("-Wl,--no-whole-archive");
+ }
+
+ fn hint_static(&mut self) {
+ if !self.takes_hints() { return }
+ self.cmd.arg("-Wl,-Bstatic");
+ }
+
+ fn hint_dynamic(&mut self) {
+ if !self.takes_hints() { return }
+ self.cmd.arg("-Wl,-Bdynamic");
+ }
+}
+
+pub struct MsvcLinker<'a> {
+ pub cmd: &'a mut Command,
+ pub sess: &'a Session,
+}
+
+impl<'a> Linker for MsvcLinker<'a> {
+ fn link_rlib(&mut self, lib: &Path) { self.cmd.arg(lib); }
+ fn add_object(&mut self, path: &Path) { self.cmd.arg(path); }
+ fn args(&mut self, args: &[String]) { self.cmd.args(args); }
+ fn build_dylib(&mut self, _out_filename: &Path) { self.cmd.arg("/DLL"); }
+ fn gc_sections(&mut self, _is_dylib: bool) { self.cmd.arg("/OPT:REF,ICF"); }
+
+ fn link_dylib(&mut self, lib: &str) {
+ self.cmd.arg(&format!("{}.lib", lib));
+ }
+ fn link_staticlib(&mut self, lib: &str) {
+ self.cmd.arg(&format!("{}.lib", lib));
+ }
+
+ fn position_independent_executable(&mut self) {
+ // noop
+ }
+
+ fn no_default_libraries(&mut self) {
+ // Currently we don't pass the /NODEFAULTLIB flag to the linker on MSVC
+ // as there's been trouble in the past of linking the C++ standard
+ // library required by LLVM. This likely needs to happen one day, but
+ // in general Windows is also a more controlled environment than
+ // Unix, so it's not necessarily as critical that this be implemented.
+ //
+ // Note that there are also some licensing worries about statically
+ // linking some libraries which require a specific agreement, so it may
+ // not ever be possible for us to pass this flag.
+ }
+
+ fn include_path(&mut self, path: &Path) {
+ let mut arg = OsString::from("/LIBPATH:");
+ arg.push(path);
+ self.cmd.arg(&arg);
+ }
+
+ fn output_filename(&mut self, path: &Path) {
+ let mut arg = OsString::from("/OUT:");
+ arg.push(path);
+ self.cmd.arg(&arg);
+ }
+
+ fn framework_path(&mut self, _path: &Path) {
+ panic!("frameworks are not supported on windows")
+ }
+ fn link_framework(&mut self, _framework: &str) {
+ panic!("frameworks are not supported on windows")
+ }
+
+ fn link_whole_staticlib(&mut self, lib: &str, _search_path: &[PathBuf]) {
+ // not supported?
+ self.link_staticlib(lib);
+ }
+ fn optimize(&mut self) {
+ // Needs more investigation of `/OPT` arguments
+ }
+ fn whole_archives(&mut self) {
+ // hints not supported?
+ }
+ fn no_whole_archives(&mut self) {
+ // hints not supported?
+ }
+
+ // On windows static libraries are of the form `foo.lib` and dynamic
+ // libraries are not linked against directly, but rather through their
+ // import libraries also called `foo.lib`. As a result there's no
+ // possibility for a native library to appear both dynamically and
+ // statically in the same folder so we don't have to worry about hints like
+ // we do on Unix platforms.
+ fn hint_static(&mut self) {}
+ fn hint_dynamic(&mut self) {}
+}
}
// Make sure we actually can run LTO
- for crate_type in &*sess.crate_types.borrow() {
+ for crate_type in sess.crate_types.borrow().iter() {
match *crate_type {
config::CrateTypeExecutable | config::CrateTypeStaticlib => {}
_ => {
use back::lto;
use back::link::{get_cc_prog, remove};
-use session::config::{OutputFilenames, NoDebugInfo, Passes, SomePasses, AllPasses};
+use session::config::{OutputFilenames, Passes, SomePasses, AllPasses};
use session::Session;
use session::config;
use llvm;
use util::common::path2cstr;
use syntax::codemap;
use syntax::diagnostic;
-use syntax::diagnostic::{Emitter, Handler, Level, mk_handler};
+use syntax::diagnostic::{Emitter, Handler, Level};
use std::ffi::{CStr, CString};
use std::fs;
-use std::iter::Unfold;
use std::mem;
use std::path::Path;
use std::process::{Command, Stdio};
let opt_level = get_llvm_opt_level(sess.opts.optimize);
let use_softfp = sess.opts.cg.soft_float;
- // FIXME: #11906: Omitting frame pointers breaks retrieving the value of a parameter.
- let no_fp_elim = (sess.opts.debuginfo != NoDebugInfo) ||
- !sess.target.target.options.eliminate_frame_pointer;
-
let any_library = sess.crate_types.borrow().iter().any(|ty| {
*ty != config::CrateTypeExecutable
});
opt_level,
true /* EnableSegstk */,
use_softfp,
- no_fp_elim,
!any_library && reloc_model == llvm::RelocPIC,
ffunction_sections,
fdata_sections,
no_prepopulate_passes: bool,
no_builtins: bool,
time_passes: bool,
+ vectorize_loop: bool,
+ vectorize_slp: bool,
+ merge_functions: bool,
}
unsafe impl Send for ModuleConfig { }
no_prepopulate_passes: false,
no_builtins: false,
time_passes: false,
+ vectorize_loop: false,
+ vectorize_slp: false,
+ merge_functions: false,
}
}
self.no_prepopulate_passes = sess.opts.cg.no_prepopulate_passes;
self.no_builtins = trans.no_builtins;
self.time_passes = sess.time_passes();
+
+ // Copy what clang does by turning on loop vectorization at O2 and
+ // slp vectorization at O3. Otherwise configure other optimization aspects
+ // of this pass manager builder.
+ self.vectorize_loop = !sess.opts.cg.no_vectorize_loops &&
+ (sess.opts.optimize == config::Default ||
+ sess.opts.optimize == config::Aggressive);
+ self.vectorize_slp = !sess.opts.cg.no_vectorize_slp &&
+ sess.opts.optimize == config::Aggressive;
+
+ self.merge_functions = sess.opts.optimize == config::Default ||
+ sess.opts.optimize == config::Aggressive;
}
}
}
unsafe extern "C" fn report_inline_asm<'a, 'b>(cgcx: &'a CodegenContext<'a>,
- msg: &'b str,
- cookie: c_uint) {
+ msg: &'b str,
+ cookie: c_uint) {
use syntax::codemap::ExpnId;
match cgcx.lto_ctxt {
let pass = CString::new(pass).unwrap();
llvm::LLVMRustAddPass(fpm, pass.as_ptr())
};
- if !config.no_verify { assert!(addpass("verify")); }
+ if !config.no_verify { assert!(addpass("verify")); }
if !config.no_prepopulate_passes {
llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod);
llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod);
- populate_llvm_passes(fpm, mpm, llmod, opt_level,
- config.no_builtins);
+ populate_llvm_passes(fpm, mpm, llmod, opt_level, &config);
}
for pass in &config.passes {
- let pass = CString::new(pass.clone()).unwrap();
- if !llvm::LLVMRustAddPass(mpm, pass.as_ptr()) {
- cgcx.handler.warn(&format!("unknown pass {:?}, ignoring", pass));
+ if !addpass(pass) {
+ cgcx.handler.warn(&format!("unknown pass `{}`, ignoring",
+ pass));
}
}
for pass in &cgcx.plugin_passes {
- let pass = CString::new(pass.clone()).unwrap();
- if !llvm::LLVMRustAddPass(mpm, pass.as_ptr()) {
- cgcx.handler.err(&format!("a plugin asked for LLVM pass {:?} but LLVM \
- does not recognize it", pass));
+ if !addpass(pass) {
+ cgcx.handler.err(&format!("a plugin asked for LLVM pass \
+ `{}` but LLVM does not \
+ recognize it", pass));
}
}
llvm::LLVMRustAddAnalysisPasses(tm, cpm, llmod);
llvm::LLVMRustAddLibraryInfo(cpm, llmod, no_builtins);
f(cpm);
- llvm::LLVMDisposePassManager(cpm);
}
if config.emit_bc {
let out = path2cstr(&out);
with_codegen(tm, llmod, config.no_builtins, |cpm| {
llvm::LLVMRustPrintModule(cpm, llmod, out.as_ptr());
+ llvm::LLVMDisposePassManager(cpm);
})
}
if config.emit_asm {
let path = output_names.with_extension(&format!("{}.s", name_extra));
with_codegen(tm, llmod, config.no_builtins, |cpm| {
- write_output_file(cgcx.handler, tm, cpm, llmod, &path, llvm::AssemblyFileType);
+ write_output_file(cgcx.handler, tm, cpm, llmod, &path,
+ llvm::AssemblyFileType);
});
}
reachable: &[String],
work_items: Vec<WorkItem>) {
let cgcx = CodegenContext::new_with_session(sess, reachable);
- let mut work_items = work_items;
// Since we're running single-threaded, we can pass the session to
// the proc, allowing `optimize_and_codegen` to perform LTO.
- for work in Unfold::new((), |_| work_items.pop()) {
+ for work in work_items.into_iter().rev() {
execute_work_item(&cgcx, work);
}
}
futures.push(rx);
thread::Builder::new().name(format!("codegen-{}", i)).spawn(move || {
- let diag_handler = mk_handler(true, box diag_emitter);
+ let diag_handler = Handler::with_emitter(true, box diag_emitter);
// Must construct cgcx inside the proc because it has non-Send
// fields.
}
unsafe fn configure_llvm(sess: &Session) {
- use std::sync::{Once, ONCE_INIT};
- static INIT: Once = ONCE_INIT;
-
- // Copy what clang does by turning on loop vectorization at O2 and
- // slp vectorization at O3
- let vectorize_loop = !sess.opts.cg.no_vectorize_loops &&
- (sess.opts.optimize == config::Default ||
- sess.opts.optimize == config::Aggressive);
- let vectorize_slp = !sess.opts.cg.no_vectorize_slp &&
- sess.opts.optimize == config::Aggressive;
+ use std::sync::Once;
+ static INIT: Once = Once::new();
let mut llvm_c_strs = Vec::new();
let mut llvm_args = Vec::new();
+
{
let mut add = |arg: &str| {
let s = CString::new(arg).unwrap();
llvm_c_strs.push(s);
};
add("rustc"); // fake program name
- if vectorize_loop { add("-vectorize-loops"); }
- if vectorize_slp { add("-vectorize-slp"); }
if sess.time_llvm_passes() { add("-time-passes"); }
if sess.print_llvm_passes() { add("-debug-pass=Structure"); }
mpm: llvm::PassManagerRef,
llmod: ModuleRef,
opt: llvm::CodeGenOptLevel,
- no_builtins: bool) {
+ config: &ModuleConfig) {
// Create the PassManagerBuilder for LLVM. We configure it with
// reasonable defaults and prepare it to actually populate the pass
// manager.
let builder = llvm::LLVMPassManagerBuilderCreate();
+
+ llvm::LLVMRustConfigurePassManagerBuilder(builder, opt,
+ config.merge_functions,
+ config.vectorize_slp,
+ config.vectorize_loop);
+
+ llvm::LLVMRustAddBuilderLibraryInfo(builder, llmod, config.no_builtins);
+
+ // Here we match what clang does (kinda). For O0 we only inline
+ // always-inline functions (but don't add lifetime intrinsics), at O1 we
+ // inline with lifetime intrinsics, and O2+ we add an inliner with a
+ // thresholds copied from clang.
match opt {
llvm::CodeGenLevelNone => {
- // Don't add lifetime intrinsics at O0
llvm::LLVMRustAddAlwaysInlinePass(builder, false);
}
llvm::CodeGenLevelLess => {
llvm::LLVMRustAddAlwaysInlinePass(builder, true);
}
- // numeric values copied from clang
llvm::CodeGenLevelDefault => {
- llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder,
- 225);
+ llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 225);
}
llvm::CodeGenLevelAggressive => {
- llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder,
- 275);
+ llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 275);
}
}
- llvm::LLVMPassManagerBuilderSetOptLevel(builder, opt as c_uint);
- llvm::LLVMRustAddBuilderLibraryInfo(builder, llmod, no_builtins);
// Use the builder to populate the function/module pass managers.
llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(builder, fpm);
llvm::LLVMPassManagerBuilderPopulateModulePassManager(builder, mpm);
llvm::LLVMPassManagerBuilderDispose(builder);
-
- match opt {
- llvm::CodeGenLevelDefault | llvm::CodeGenLevelAggressive => {
- llvm::LLVMRustAddPass(mpm, "mergefunc\0".as_ptr() as *const _);
- }
- _ => {}
- };
}
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
- html_favicon_url = "http://www.rust-lang.org/favicon.ico",
+ html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/")]
-#![feature(alloc)]
#![feature(box_patterns)]
#![feature(box_syntax)]
-#![feature(collections)]
-#![feature(core)]
+#![feature(const_fn)]
+#![feature(iter_cmp)]
+#![feature(iter_arith)]
#![feature(libc)]
+#![feature(path_ext)]
+#![feature(path_ext)]
+#![feature(path_relative_from)]
+#![feature(path_relative_from)]
#![feature(quote)]
+#![feature(rc_weak)]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
#![feature(staged_api)]
#![feature(unicode)]
-#![feature(path_ext)]
-#![feature(path_relative_from)]
+#![feature(unicode)]
+#![feature(vec_push_all)]
#![allow(trivial_casts)]
pub use rustc_back::x86;
pub use rustc_back::x86_64;
+ pub mod linker;
pub mod link;
pub mod lto;
pub mod write;
use middle::def;
use middle::ty::{self, Ty};
+use rustc::ast_map::NodeItem;
use std::cell::Cell;
use std::fs::File;
use syntax::ast_util;
use syntax::ast::{self, NodeId, DefId};
-use syntax::ast_map::NodeItem;
use syntax::codemap::*;
use syntax::parse::token::{self, get_ident, keywords};
use syntax::owned_slice::OwnedSlice;
use super::span_utils::SpanUtils;
use super::recorder::{Recorder, FmtStrs};
-use util::ppaux;
-
+macro_rules! down_cast_data {
+ ($id:ident, $kind:ident, $this:ident, $sp:expr) => {
+ let $id = if let super::Data::$kind(data) = $id {
+ data
+ } else {
+ $this.sess.span_bug($sp, &format!("unexpected data kind: {:?}", $id));
+ };
+ };
+}
pub struct DumpCsvVisitor<'l, 'tcx: 'l> {
save_ctxt: SaveContext<'l, 'tcx>,
sess: &'l Session,
- analysis: &'l ty::CrateAnalysis<'tcx>,
+ tcx: &'l ty::ctxt<'tcx>,
+ analysis: &'l ty::CrateAnalysis,
span: SpanUtils<'l>,
fmt: FmtStrs<'l>,
}
impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
- pub fn new(sess: &'l Session,
- analysis: &'l ty::CrateAnalysis<'tcx>,
+ pub fn new(tcx: &'l ty::ctxt<'tcx>,
+ analysis: &'l ty::CrateAnalysis,
output_file: Box<File>) -> DumpCsvVisitor<'l, 'tcx> {
+ let span_utils = SpanUtils {
+ sess: &tcx.sess,
+ err_count: Cell::new(0)
+ };
DumpCsvVisitor {
- sess: sess,
- save_ctxt: SaveContext::new(sess, analysis, SpanUtils {
- sess: sess,
- err_count: Cell::new(0)
- }),
+ sess: &tcx.sess,
+ tcx: tcx,
+ save_ctxt: SaveContext::new(tcx, span_utils.clone()),
analysis: analysis,
- span: SpanUtils {
- sess: sess,
- err_count: Cell::new(0)
- },
+ span: span_utils.clone(),
fmt: FmtStrs::new(box Recorder {
out: output_file,
dump_spans: false,
- },
- SpanUtils {
- sess: sess,
- err_count: Cell::new(0)
- }),
+ }, span_utils),
cur_scope: 0
}
}
let mut result: Vec<(Span, String)> = vec!();
let mut segs = vec!();
- for (i, (seg, span)) in path.segments.iter().zip(spans.iter()).enumerate() {
+ for (i, (seg, span)) in path.segments.iter().zip(&spans).enumerate() {
segs.push(seg.clone());
let sub_path = ast::Path{span: *span, // span for the last segment
global: path.global,
};
self.fmt.sub_mod_ref_str(path.span,
*span,
- &qualname[..],
+ &qualname,
self.cur_scope);
}
}
};
self.fmt.sub_mod_ref_str(path.span,
*span,
- &qualname[..],
+ &qualname,
self.cur_scope);
}
}
let (ref span, ref qualname) = sub_paths[len-2];
self.fmt.sub_type_ref_str(path.span,
*span,
- &qualname[..]);
+ &qualname);
// write the other sub-paths
if len <= 2 {
for &(ref span, ref qualname) in sub_paths {
self.fmt.sub_mod_ref_str(path.span,
*span,
- &qualname[..],
+ &qualname,
self.cur_scope);
}
}
// looks up anything, not just a type
fn lookup_type_ref(&self, ref_id: NodeId) -> Option<DefId> {
- if !self.analysis.ty_cx.def_map.borrow().contains_key(&ref_id) {
+ if !self.tcx.def_map.borrow().contains_key(&ref_id) {
self.sess.bug(&format!("def_map has no key for {} in lookup_type_ref",
ref_id));
}
- let def = self.analysis.ty_cx.def_map.borrow().get(&ref_id).unwrap().full_def();
+ let def = self.tcx.def_map.borrow().get(&ref_id).unwrap().full_def();
match def {
def::DefPrimTy(_) => None,
_ => Some(def.def_id()),
}
fn lookup_def_kind(&self, ref_id: NodeId, span: Span) -> Option<recorder::Row> {
- let def_map = self.analysis.ty_cx.def_map.borrow();
+ let def_map = self.tcx.def_map.borrow();
if !def_map.contains_key(&ref_id) {
self.sess.span_bug(span, &format!("def_map has no key for {} in lookup_def_kind",
ref_id));
match def {
def::DefMod(_) |
def::DefForeignMod(_) => Some(recorder::ModRef),
- def::DefStruct(_) => Some(recorder::StructRef),
+ def::DefStruct(_) => Some(recorder::TypeRef),
def::DefTy(..) |
def::DefAssociatedTy(..) |
def::DefTrait(_) => Some(recorder::TypeRef),
collector.visit_pat(&arg.pat);
let span_utils = self.span.clone();
for &(id, ref p, _, _) in &collector.collected_paths {
- let typ =
- ppaux::ty_to_string(
- &self.analysis.ty_cx,
- *self.analysis.ty_cx.node_types().get(&id).unwrap());
+ let typ = self.tcx.node_types().get(&id).unwrap().to_string();
// get the span only for the name of the variable (I hope the path is only ever a
// variable name, but who knows?)
self.fmt.formal_str(p.span,
id,
qualname,
&path_to_string(p),
- &typ[..]);
+ &typ);
}
}
}
let mut scope_id;
// The qualname for a method is the trait name or name of the struct in an impl in
// which the method is declared in, followed by the method's name.
- let qualname = match ty::impl_of_method(&self.analysis.ty_cx,
- ast_util::local_def(id)) {
- Some(impl_id) => match self.analysis.ty_cx.map.get(impl_id.node) {
+ let qualname = match ty::impl_of_method(self.tcx, ast_util::local_def(id)) {
+ Some(impl_id) => match self.tcx.map.get(impl_id.node) {
NodeItem(item) => {
scope_id = item.id;
match item.node {
ast::ItemImpl(_, _, _, _, ref ty, _) => {
- let mut result = String::from_str("<");
+ let mut result = String::from("<");
result.push_str(&ty_to_string(&**ty));
- match ty::trait_of_item(&self.analysis.ty_cx,
- ast_util::local_def(id)) {
+ match ty::trait_of_item(self.tcx, ast_util::local_def(id)) {
Some(def_id) => {
result.push_str(" as ");
result.push_str(
- &ty::item_path_str(&self.analysis.ty_cx, def_id));
+ &ty::item_path_str(self.tcx, def_id));
},
None => {}
}
_ => {
self.sess.span_bug(span,
&format!("Container {} for method {} is not a node item {:?}",
- impl_id.node, id, self.analysis.ty_cx.map.get(impl_id.node)));
+ impl_id.node, id, self.tcx.map.get(impl_id.node)));
},
},
- None => match ty::trait_of_item(&self.analysis.ty_cx,
- ast_util::local_def(id)) {
+ None => match ty::trait_of_item(self.tcx, ast_util::local_def(id)) {
Some(def_id) => {
scope_id = def_id.node;
- match self.analysis.ty_cx.map.get(def_id.node) {
+ match self.tcx.map.get(def_id.node) {
NodeItem(_) => {
- format!("::{}", ty::item_path_str(&self.analysis.ty_cx, def_id))
+ format!("::{}", ty::item_path_str(self.tcx, def_id))
}
_ => {
self.sess.span_bug(span,
let qualname = &format!("{}::{}", qualname, &token::get_name(name));
// record the decl for this def (if it has one)
- let decl_id = ty::trait_item_of_item(&self.analysis.ty_cx,
- ast_util::local_def(id))
+ let decl_id = ty::trait_item_of_item(self.tcx, ast_util::local_def(id))
.and_then(|new_id| {
let def_id = new_id.def_id();
if def_id.node != 0 && def_id != ast_util::local_def(id) {
id);
}
- fn process_trait_ref(&mut self,
- trait_ref: &ast::TraitRef) {
- match self.lookup_type_ref(trait_ref.ref_id) {
- Some(id) => {
- let sub_span = self.span.sub_span_for_type_name(trait_ref.path.span);
- self.fmt.ref_str(recorder::TypeRef,
- trait_ref.path.span,
- sub_span,
- id,
- self.cur_scope);
- visit::walk_path(self, &trait_ref.path);
- },
- None => ()
+ fn process_trait_ref(&mut self, trait_ref: &ast::TraitRef) {
+ let trait_ref_data = self.save_ctxt.get_trait_ref_data(trait_ref, self.cur_scope);
+ if let Some(trait_ref_data) = trait_ref_data {
+ self.fmt.ref_str(recorder::TypeRef,
+ trait_ref.path.span,
+ Some(trait_ref_data.span),
+ trait_ref_data.ref_id,
+ trait_ref_data.scope);
+ visit::walk_path(self, &trait_ref.path);
}
}
fn process_struct_field_def(&mut self,
field: &ast::StructField,
- qualname: &str,
- scope_id: NodeId) {
- match field.node.kind {
- ast::NamedField(ident, _) => {
- let name = get_ident(ident);
- let qualname = format!("{}::{}", qualname, name);
- let typ =
- ppaux::ty_to_string(
- &self.analysis.ty_cx,
- *self.analysis.ty_cx.node_types().get(&field.node.id).unwrap());
- match self.span.sub_span_before_token(field.span, token::Colon) {
- Some(sub_span) => self.fmt.field_str(field.span,
- Some(sub_span),
- field.node.id,
- &name[..],
- &qualname[..],
- &typ[..],
- scope_id),
- None => self.sess.span_bug(field.span,
- &format!("Could not find sub-span for field {}",
- qualname)),
- }
- },
- _ => (),
+ parent_id: NodeId) {
+ let field_data = self.save_ctxt.get_field_data(field, parent_id);
+ if let Some(field_data) = field_data {
+ down_cast_data!(field_data, VariableData, self, field.span);
+ self.fmt.field_str(field.span,
+ Some(field_data.span),
+ field_data.id,
+ &field_data.name,
+ &field_data.qualname,
+ &field_data.type_value,
+ field_data.scope);
}
}
// the first few to match the number of generics we're looking for.
let param_sub_spans = self.span.spans_for_ty_params(full_span,
(generics.ty_params.len() as isize));
- for (param, param_ss) in generics.ty_params.iter().zip(param_sub_spans.iter()) {
+ for (param, param_ss) in generics.ty_params.iter().zip(param_sub_spans) {
// Append $id to name to make sure each one is unique
let name = format!("{}::{}${}",
prefix,
- escape(self.span.snippet(*param_ss)),
+ escape(self.span.snippet(param_ss)),
id);
self.fmt.typedef_str(full_span,
- Some(*param_ss),
+ Some(param_ss),
param.id,
- &name[..],
+ &name,
"");
}
self.visit_generics(generics);
ty_params: &ast::Generics,
body: &ast::Block) {
let fn_data = self.save_ctxt.get_item_data(item);
- if let super::Data::FunctionData(fn_data) = fn_data {
- self.fmt.fn_str(item.span,
- Some(fn_data.span),
- fn_data.id,
- &fn_data.qualname,
- fn_data.scope);
+ down_cast_data!(fn_data, FunctionData, self, item.span);
+ self.fmt.fn_str(item.span,
+ Some(fn_data.span),
+ fn_data.id,
+ &fn_data.qualname,
+ fn_data.scope);
- self.process_formals(&decl.inputs, &fn_data.qualname);
- self.process_generic_params(ty_params, item.span, &fn_data.qualname, item.id);
- } else {
- unreachable!();
- }
+ self.process_formals(&decl.inputs, &fn_data.qualname);
+ self.process_generic_params(ty_params, item.span, &fn_data.qualname, item.id);
for arg in &decl.inputs {
self.visit_ty(&arg.ty);
expr: &ast::Expr)
{
let var_data = self.save_ctxt.get_item_data(item);
- if let super::Data::VariableData(var_data) = var_data {
- self.fmt.static_str(item.span,
- Some(var_data.span),
- var_data.id,
- &var_data.name,
- &var_data.qualname,
- &var_data.value,
- &var_data.type_value,
- var_data.scope);
- } else {
- unreachable!();
- }
+ down_cast_data!(var_data, VariableData, self, item.span);
+ self.fmt.static_str(item.span,
+ Some(var_data.span),
+ var_data.id,
+ &var_data.name,
+ &var_data.qualname,
+ &var_data.value,
+ &var_data.type_value,
+ var_data.scope);
self.visit_ty(&typ);
self.visit_expr(expr);
typ: &ast::Ty,
expr: &ast::Expr)
{
- let qualname = format!("::{}", self.analysis.ty_cx.map.path_to_string(id));
+ let qualname = format!("::{}", self.tcx.map.path_to_string(id));
let sub_span = self.span.sub_span_after_keyword(span,
keywords::Const);
sub_span,
id,
&get_ident((*ident).clone()),
- &qualname[..],
+ &qualname,
&self.span.snippet(expr.span),
&ty_to_string(&*typ),
self.cur_scope);
item: &ast::Item,
def: &ast::StructDef,
ty_params: &ast::Generics) {
- let qualname = format!("::{}", self.analysis.ty_cx.map.path_to_string(item.id));
+ let qualname = format!("::{}", self.tcx.map.path_to_string(item.id));
let ctor_id = match def.ctor_id {
Some(node_id) => node_id,
sub_span,
item.id,
ctor_id,
- &qualname[..],
+ &qualname,
self.cur_scope,
- &val[..]);
+ &val);
// fields
for field in &def.fields {
- self.process_struct_field_def(field, &qualname[..], item.id);
- self.visit_ty(&*field.node.ty);
+ self.process_struct_field_def(field, item.id);
+ self.visit_ty(&field.node.ty);
}
- self.process_generic_params(ty_params, item.span, &qualname[..], item.id);
+ self.process_generic_params(ty_params, item.span, &qualname, item.id);
}
fn process_enum(&mut self,
item: &ast::Item,
enum_definition: &ast::EnumDef,
ty_params: &ast::Generics) {
- let enum_name = format!("::{}", self.analysis.ty_cx.map.path_to_string(item.id));
- let val = self.span.snippet(item.span);
- match self.span.sub_span_after_keyword(item.span, keywords::Enum) {
- Some(sub_span) => self.fmt.enum_str(item.span,
- Some(sub_span),
- item.id,
- &enum_name[..],
- self.cur_scope,
- &val[..]),
- None => self.sess.span_bug(item.span,
- &format!("Could not find subspan for enum {}",
- enum_name)),
- }
+ let enum_data = self.save_ctxt.get_item_data(item);
+ down_cast_data!(enum_data, EnumData, self, item.span);
+ self.fmt.enum_str(item.span,
+ Some(enum_data.span),
+ enum_data.id,
+ &enum_data.qualname,
+ enum_data.scope,
+ &enum_data.value);
+
for variant in &enum_definition.variants {
- let name = get_ident(variant.node.name);
- let name = &name;
- let mut qualname = enum_name.clone();
+ let name = &get_ident(variant.node.name);
+ let mut qualname = enum_data.qualname.clone();
qualname.push_str("::");
qualname.push_str(name);
let val = self.span.snippet(variant.span);
self.span.span_for_first_ident(variant.span),
variant.node.id,
name,
- &qualname[..],
- &enum_name[..],
- &val[..],
- item.id);
+ &qualname,
+ &enum_data.qualname,
+ &val,
+ enum_data.id);
for arg in args {
self.visit_ty(&*arg.ty);
}
Some(node_id) => node_id,
None => -1,
};
- self.fmt.struct_variant_str(
- variant.span,
- self.span.span_for_first_ident(variant.span),
- variant.node.id,
- ctor_id,
- &qualname[..],
- &enum_name[..],
- &val[..],
- item.id);
+ self.fmt.struct_variant_str(variant.span,
+ self.span.span_for_first_ident(variant.span),
+ variant.node.id,
+ ctor_id,
+ &qualname,
+ &enum_data.qualname,
+ &val,
+ enum_data.id);
for field in &struct_def.fields {
- self.process_struct_field_def(field, &qualname, variant.node.id);
+ self.process_struct_field_def(field, variant.node.id);
self.visit_ty(&*field.node.ty);
}
}
}
}
-
- self.process_generic_params(ty_params, item.span, &enum_name[..], item.id);
+ self.process_generic_params(ty_params, item.span, &enum_data.qualname, enum_data.id);
}
fn process_impl(&mut self,
trait_ref: &Option<ast::TraitRef>,
typ: &ast::Ty,
impl_items: &[P<ast::ImplItem>]) {
- let trait_id = trait_ref.as_ref().and_then(|tr| self.lookup_type_ref(tr.ref_id));
- match typ.node {
- // Common case impl for a struct or something basic.
- ast::TyPath(None, ref path) => {
- let sub_span = self.span.sub_span_for_type_name(path.span);
- let self_id = self.lookup_type_ref(typ.id).map(|id| {
- self.fmt.ref_str(recorder::TypeRef,
- path.span,
- sub_span,
- id,
- self.cur_scope);
- id
- });
- self.fmt.impl_str(path.span,
- sub_span,
- item.id,
- self_id,
- trait_id,
- self.cur_scope);
- },
- _ => {
- // Less useful case, impl for a compound type.
- self.visit_ty(&*typ);
-
- let sub_span = self.span.sub_span_for_type_name(typ.span);
- self.fmt.impl_str(typ.span,
- sub_span,
- item.id,
- None,
- trait_id,
- self.cur_scope);
+ let impl_data = self.save_ctxt.get_item_data(item);
+ down_cast_data!(impl_data, ImplData, self, item.span);
+ match impl_data.self_ref {
+ Some(ref self_ref) => {
+ self.fmt.ref_str(recorder::TypeRef,
+ item.span,
+ Some(self_ref.span),
+ self_ref.ref_id,
+ self_ref.scope);
+ }
+ None => {
+ self.visit_ty(&typ);
}
}
-
- match *trait_ref {
- Some(ref trait_ref) => self.process_trait_ref(trait_ref),
- None => (),
+ if let Some(ref trait_ref_data) = impl_data.trait_ref {
+ self.fmt.ref_str(recorder::TypeRef,
+ item.span,
+ Some(trait_ref_data.span),
+ trait_ref_data.ref_id,
+ trait_ref_data.scope);
+ visit::walk_path(self, &trait_ref.as_ref().unwrap().path);
}
+ self.fmt.impl_str(item.span,
+ Some(impl_data.span),
+ impl_data.id,
+ impl_data.self_ref.map(|data| data.ref_id),
+ impl_data.trait_ref.map(|data| data.ref_id),
+ impl_data.scope);
+
self.process_generic_params(type_parameters, item.span, "", item.id);
for impl_item in impl_items {
self.visit_impl_item(impl_item);
generics: &ast::Generics,
trait_refs: &OwnedSlice<ast::TyParamBound>,
methods: &[P<ast::TraitItem>]) {
- let qualname = format!("::{}", self.analysis.ty_cx.map.path_to_string(item.id));
+ let qualname = format!("::{}", self.tcx.map.path_to_string(item.id));
let val = self.span.snippet(item.span);
let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Trait);
self.fmt.trait_str(item.span,
sub_span,
item.id,
- &qualname[..],
+ &qualname,
self.cur_scope,
- &val[..]);
+ &val);
// super-traits
- for super_bound in &**trait_refs {
+ for super_bound in trait_refs.iter() {
let trait_ref = match *super_bound {
ast::TraitTyParamBound(ref trait_ref, _) => {
trait_ref
}
// walk generics and methods
- self.process_generic_params(generics, item.span, &qualname[..], item.id);
+ self.process_generic_params(generics, item.span, &qualname, item.id);
for method in methods {
self.visit_trait_item(method)
}
}
fn process_mod(&mut self,
- item: &ast::Item, // The module in question, represented as an item.
- m: &ast::Mod) {
- let qualname = format!("::{}", self.analysis.ty_cx.map.path_to_string(item.id));
-
- let cm = self.sess.codemap();
- let filename = cm.span_to_filename(m.inner);
-
- let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Mod);
+ item: &ast::Item) { // The module in question, represented as an item.
+ let mod_data = self.save_ctxt.get_item_data(item);
+ down_cast_data!(mod_data, ModData, self, item.span);
self.fmt.mod_str(item.span,
- sub_span,
- item.id,
- &qualname[..],
- self.cur_scope,
- &filename[..]);
-
- self.nest(item.id, |v| visit::walk_mod(v, m));
+ Some(mod_data.span),
+ mod_data.id,
+ &mod_data.qualname,
+ mod_data.scope,
+ &mod_data.filename);
}
fn process_path(&mut self,
return
}
- let def_map = self.analysis.ty_cx.def_map.borrow();
+ let def_map = self.tcx.def_map.borrow();
if !def_map.contains_key(&id) {
self.sess.span_bug(span,
&format!("def_map has no key for {} in visit_expr", id));
sub_span,
def.def_id(),
self.cur_scope),
- def::DefStruct(def_id) => self.fmt.ref_str(recorder::StructRef,
+ def::DefStruct(def_id) => self.fmt.ref_str(recorder::TypeRef,
span,
sub_span,
def_id,
def::DefMethod(declid, provenence) => {
let sub_span = self.span.sub_span_for_meth_name(span);
let defid = if declid.krate == ast::LOCAL_CRATE {
- let ti = ty::impl_or_trait_item(&self.analysis.ty_cx,
- declid);
+ let ti = ty::impl_or_trait_item(self.tcx, declid);
match provenence {
def::FromTrait(def_id) => {
- Some(ty::trait_items(&self.analysis.ty_cx,
- def_id)
+ Some(ty::trait_items(self.tcx, def_id)
.iter()
.find(|mr| {
mr.name() == ti.name()
.def_id())
}
def::FromImpl(def_id) => {
- let impl_items = self.analysis
- .ty_cx
- .impl_items
- .borrow();
+ let impl_items = self.tcx.impl_items.borrow();
Some(impl_items.get(&def_id)
.unwrap()
.iter()
.find(|mr| {
ty::impl_or_trait_item(
- &self.analysis.ty_cx,
+ self.tcx,
mr.def_id()
).name() == ti.name()
})
// modules or types in the path prefix
match def {
def::DefMethod(did, _) => {
- let ti = ty::impl_or_trait_item(&self.analysis.ty_cx, did);
+ let ti = ty::impl_or_trait_item(self.tcx, did);
if let ty::MethodTraitItem(m) = ti {
if m.explicit_self == ty::StaticExplicitSelfCategory {
self.write_sub_path_trait_truncated(path);
self.write_sub_paths_truncated(path, false);
- let ty = &ty::expr_ty_adjusted(&self.analysis.ty_cx, ex).sty;
- let struct_def = match *ty {
- ty::ty_struct(def_id, _) => {
- let sub_span = self.span.span_for_last_ident(path.span);
- self.fmt.ref_str(recorder::StructRef,
- path.span,
- sub_span,
- def_id,
- self.cur_scope);
- Some(def_id)
- }
- _ => None
- };
-
- for field in fields {
- match struct_def {
- Some(struct_def) => {
- let fields = ty::lookup_struct_fields(&self.analysis.ty_cx, struct_def);
- for f in &fields {
- if generated_code(field.ident.span) {
- continue;
- }
- if f.name == field.ident.node.name {
- // We don't really need a sub-span here, but no harm done
- let sub_span = self.span.span_for_last_ident(field.ident.span);
- self.fmt.ref_str(recorder::VarRef,
- field.ident.span,
- sub_span,
- f.id,
- self.cur_scope);
- }
- }
+ if let Some(struct_lit_data) = self.save_ctxt.get_expr_data(ex) {
+ down_cast_data!(struct_lit_data, TypeRefData, self, ex.span);
+ self.fmt.ref_str(recorder::TypeRef,
+ ex.span,
+ Some(struct_lit_data.span),
+ struct_lit_data.ref_id,
+ struct_lit_data.scope);
+ let struct_def = struct_lit_data.ref_id;
+
+ for field in fields {
+ if generated_code(field.ident.span) {
+ continue;
}
- None => {}
- }
- self.visit_expr(&*field.expr)
+ let field_data = self.save_ctxt.get_field_ref_data(field,
+ struct_def,
+ self.cur_scope);
+ self.fmt.ref_str(recorder::VarRef,
+ field.ident.span,
+ Some(field_data.span),
+ field_data.ref_id,
+ field_data.scope);
+
+ self.visit_expr(&field.expr)
+ }
}
+
visit::walk_expr_opt(self, base)
}
fn process_method_call(&mut self,
ex: &ast::Expr,
args: &Vec<P<ast::Expr>>) {
- let method_map = self.analysis.ty_cx.method_map.borrow();
+ let method_map = self.tcx.method_map.borrow();
let method_callee = method_map.get(&ty::MethodCall::expr(ex.id)).unwrap();
let (def_id, decl_id) = match method_callee.origin {
ty::MethodStatic(def_id) |
ty::MethodStaticClosure(def_id) => {
// method invoked on an object with a concrete type (not a static method)
let decl_id =
- match ty::trait_item_of_item(&self.analysis.ty_cx,
- def_id) {
+ match ty::trait_item_of_item(self.tcx, def_id) {
None => None,
Some(decl_id) => Some(decl_id.def_id()),
};
// This incantation is required if the method referenced is a
// trait's default implementation.
- let def_id = match ty::impl_or_trait_item(&self.analysis
- .ty_cx,
- def_id) {
+ let def_id = match ty::impl_or_trait_item(self.tcx, def_id) {
ty::MethodTraitItem(method) => {
method.provided_source.unwrap_or(def_id)
}
}
ty::MethodTypeParam(ref mp) => {
// method invoked on a type parameter
- let trait_item = ty::trait_item(&self.analysis.ty_cx,
+ let trait_item = ty::trait_item(self.tcx,
mp.trait_ref.def_id,
mp.method_num);
(None, Some(trait_item.def_id()))
}
ty::MethodTraitObject(ref mo) => {
// method invoked on a trait instance
- let trait_item = ty::trait_item(&self.analysis.ty_cx,
+ let trait_item = ty::trait_item(self.tcx,
mo.trait_ref.def_id,
mo.method_num);
(None, Some(trait_item.def_id()))
self.cur_scope);
// walk receiver and args
- visit::walk_exprs(self, &args[..]);
+ visit::walk_exprs(self, &args);
}
fn process_pat(&mut self, p:&ast::Pat) {
ast::PatStruct(ref path, ref fields, _) => {
visit::walk_path(self, path);
- let def = self.analysis.ty_cx.def_map.borrow().get(&p.id).unwrap().full_def();
+ let def = self.tcx.def_map.borrow().get(&p.id).unwrap().full_def();
let struct_def = match def {
def::DefConst(..) | def::DefAssociatedConst(..) => None,
def::DefVariant(_, variant_id, _) => Some(variant_id),
_ => {
- match ty::ty_to_def_id(ty::node_id_to_type(&self.analysis.ty_cx, p.id)) {
+ match ty::ty_to_def_id(ty::node_id_to_type(self.tcx, p.id)) {
None => {
self.sess.span_bug(p.span,
&format!("Could not find struct_def for `{}`",
};
if let Some(struct_def) = struct_def {
- let struct_fields = ty::lookup_struct_fields(&self.analysis.ty_cx, struct_def);
+ let struct_fields = ty::lookup_struct_fields(self.tcx, struct_def);
for &Spanned { node: ref field, span } in fields {
let sub_span = self.span.span_for_first_ident(span);
for f in &struct_fields {
item.id,
cnum,
name,
- &location[..],
+ &location,
self.cur_scope);
}
- ast::ItemFn(ref decl, _, _, ref ty_params, ref body) =>
+ ast::ItemFn(ref decl, _, _, _, ref ty_params, ref body) =>
self.process_fn(item, &**decl, ty_params, &**body),
ast::ItemStatic(ref typ, _, ref expr) =>
self.process_static_or_const_item(item, typ, expr),
self.process_impl(item,
ty_params,
trait_ref,
- &**typ,
+ &typ,
impl_items)
}
ast::ItemTrait(_, ref generics, ref trait_refs, ref methods) =>
self.process_trait(item, generics, trait_refs, methods),
- ast::ItemMod(ref m) => self.process_mod(item, m),
+ ast::ItemMod(ref m) => {
+ self.process_mod(item);
+ self.nest(item.id, |v| visit::walk_mod(v, m));
+ }
ast::ItemTy(ref ty, ref ty_params) => {
- let qualname = format!("::{}", self.analysis.ty_cx.map.path_to_string(item.id));
+ let qualname = format!("::{}", self.tcx.map.path_to_string(item.id));
let value = ty_to_string(&**ty);
let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Type);
self.fmt.typedef_str(item.span,
sub_span,
item.id,
- &qualname[..],
- &value[..]);
+ &qualname,
+ &value);
self.visit_ty(&**ty);
self.process_generic_params(ty_params, item.span, &qualname, item.id);
}
fn visit_generics(&mut self, generics: &ast::Generics) {
- for param in &*generics.ty_params {
- for bound in &*param.bounds {
+ for param in generics.ty_params.iter() {
+ for bound in param.bounds.iter() {
if let ast::TraitTyParamBound(ref trait_ref, _) = *bound {
self.process_trait_ref(&trait_ref.trait_ref);
}
ast::ExprStruct(ref path, ref fields, ref base) =>
self.process_struct_lit(ex, path, fields, base),
ast::ExprMethodCall(_, _, ref args) => self.process_method_call(ex, args),
- ast::ExprField(ref sub_ex, ident) => {
+ ast::ExprField(ref sub_ex, _) => {
if generated_code(sub_ex.span) {
return
}
- self.visit_expr(&**sub_ex);
- let ty = &ty::expr_ty_adjusted(&self.analysis.ty_cx, &**sub_ex).sty;
- match *ty {
- ty::ty_struct(def_id, _) => {
- let fields = ty::lookup_struct_fields(&self.analysis.ty_cx, def_id);
- for f in &fields {
- if f.name == ident.node.name {
- let sub_span = self.span.span_for_last_ident(ex.span);
- self.fmt.ref_str(recorder::VarRef,
- ex.span,
- sub_span,
- f.id,
- self.cur_scope);
- break;
- }
- }
- }
- _ => self.sess.span_bug(ex.span,
- &format!("Expected struct type, found {:?}", ty)),
+ self.visit_expr(&sub_ex);
+
+ if let Some(field_data) = self.save_ctxt.get_expr_data(ex) {
+ down_cast_data!(field_data, VariableRefData, self, ex.span);
+ self.fmt.ref_str(recorder::VarRef,
+ ex.span,
+ Some(field_data.span),
+ field_data.ref_id,
+ field_data.scope);
}
},
ast::ExprTupField(ref sub_ex, idx) => {
self.visit_expr(&**sub_ex);
- let ty = &ty::expr_ty_adjusted(&self.analysis.ty_cx, &**sub_ex).sty;
+ let ty = &ty::expr_ty_adjusted(self.tcx, &**sub_ex).sty;
match *ty {
- ty::ty_struct(def_id, _) => {
- let fields = ty::lookup_struct_fields(&self.analysis.ty_cx, def_id);
+ ty::TyStruct(def_id, _) => {
+ let fields = ty::lookup_struct_fields(self.tcx, def_id);
for (i, f) in fields.iter().enumerate() {
if i == idx.node {
let sub_span = self.span.sub_span_after_token(ex.span, token::Dot);
}
}
}
- ty::ty_tup(_) => {}
+ ty::TyTuple(_) => {}
_ => self.sess.span_bug(ex.span,
&format!("Expected struct or tuple \
type, found {:?}", ty)),
return
}
- let mut id = String::from_str("$");
+ let mut id = String::from("$");
id.push_str(&ex.id.to_string());
- self.process_formals(&decl.inputs, &id[..]);
+ self.process_formals(&decl.inputs, &id);
// walk arg and return types
for arg in &decl.inputs {
let mut paths_to_process = vec![];
// process collected paths
for &(id, ref p, immut, ref_kind) in &collector.collected_paths {
- let def_map = self.analysis.ty_cx.def_map.borrow();
+ let def_map = self.tcx.def_map.borrow();
if !def_map.contains_key(&id) {
self.sess.span_bug(p.span,
&format!("def_map has no key for {} in visit_arm",
Some(p.span),
id,
&path_to_string(p),
- &value[..],
+ &value,
"")
}
def::DefVariant(..) | def::DefTy(..) | def::DefStruct(..) => {
} else {
"<mutable>".to_string()
};
- let types = self.analysis.ty_cx.node_types();
- let typ = ppaux::ty_to_string(&self.analysis.ty_cx, *types.get(&id).unwrap());
+ let types = self.tcx.node_types();
+ let typ = types.get(&id).unwrap().to_string();
// Get the span only for the name of the variable (I hope the path
// is only ever a variable name, but who knows?).
let sub_span = self.span.span_for_last_ident(p.span);
sub_span,
id,
&path_to_string(p),
- &value[..],
- &typ[..]);
+ &value,
+ &typ);
}
// Just walk the initialiser and type (don't want to walk the pattern again).
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use session::Session;
use middle::ty;
+use middle::def;
use std::env;
use std::fs::{self, File};
use syntax::visit::{self, Visitor};
use syntax::print::pprust::ty_to_string;
-
use self::span_utils::SpanUtils;
+
mod span_utils;
mod recorder;
mod dump_csv;
pub struct SaveContext<'l, 'tcx: 'l> {
- sess: &'l Session,
- analysis: &'l ty::CrateAnalysis<'tcx>,
+ tcx: &'l ty::ctxt<'tcx>,
span_utils: SpanUtils<'l>,
}
/// Data for any entity in the Rust language. The actual data contained varied
/// with the kind of entity being queried. See the nested structs for details.
+#[derive(Debug)]
pub enum Data {
/// Data for all kinds of functions and methods.
FunctionData(FunctionData),
- /// Data for local and global variables (consts and statics).
+ /// Data for local and global variables (consts and statics), and fields.
VariableData(VariableData),
+ /// Data for modules.
+ ModData(ModData),
+ /// Data for Enums.
+ EnumData(EnumData),
+ /// Data for impls.
+ ImplData(ImplData),
+
+ /// Data for the use of some variable (e.g., the use of a local variable, which
+ /// will refere to that variables declaration).
+ VariableRefData(VariableRefData),
+ /// Data for a reference to a type or trait.
+ TypeRefData(TypeRefData),
}
/// Data for all kinds of functions and methods.
+#[derive(Debug)]
pub struct FunctionData {
pub id: NodeId,
pub name: String,
}
/// Data for local and global variables (consts and statics).
+#[derive(Debug)]
pub struct VariableData {
pub id: NodeId,
pub name: String,
pub type_value: String,
}
+/// Data for modules.
+#[derive(Debug)]
+pub struct ModData {
+ pub id: NodeId,
+ pub name: String,
+ pub qualname: String,
+ pub span: Span,
+ pub scope: NodeId,
+ pub filename: String,
+}
+
+/// Data for enum declarations.
+#[derive(Debug)]
+pub struct EnumData {
+ pub id: NodeId,
+ pub value: String,
+ pub qualname: String,
+ pub span: Span,
+ pub scope: NodeId,
+}
+
+#[derive(Debug)]
+pub struct ImplData {
+ pub id: NodeId,
+ pub span: Span,
+ pub scope: NodeId,
+ // FIXME: I'm not really sure inline data is the best way to do this. Seems
+ // OK in this case, but generalising leads to returning chunks of AST, which
+ // feels wrong.
+ pub trait_ref: Option<TypeRefData>,
+ pub self_ref: Option<TypeRefData>,
+}
+
+/// Data for the use of some item (e.g., the use of a local variable, which
+/// will refere to that variables declaration (by ref_id)).
+#[derive(Debug)]
+pub struct VariableRefData {
+ pub name: String,
+ pub span: Span,
+ pub scope: NodeId,
+ pub ref_id: DefId,
+}
+
+/// Data for a reference to a type or trait.
+#[derive(Debug)]
+pub struct TypeRefData {
+ pub span: Span,
+ pub scope: NodeId,
+ pub ref_id: DefId,
+}
+
+
impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
- pub fn new(sess: &'l Session,
- analysis: &'l ty::CrateAnalysis<'tcx>,
+ pub fn new(tcx: &'l ty::ctxt<'tcx>,
span_utils: SpanUtils<'l>)
-> SaveContext<'l, 'tcx> {
SaveContext {
- sess: sess,
- analysis: analysis,
+ tcx: tcx,
span_utils: span_utils,
}
}
pub fn get_external_crates(&self) -> Vec<CrateData> {
let mut result = Vec::new();
- self.sess.cstore.iter_crate_data(|n, cmd| {
+ self.tcx.sess.cstore.iter_crate_data(|n, cmd| {
result.push(CrateData { name: cmd.name.clone(), number: n });
});
pub fn get_item_data(&self, item: &ast::Item) -> Data {
match item.node {
- ast::Item_::ItemFn(..) => {
- let name = self.analysis.ty_cx.map.path_to_string(item.id);
+ ast::ItemFn(..) => {
+ let name = self.tcx.map.path_to_string(item.id);
let qualname = format!("::{}", name);
let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Fn);
qualname: qualname,
declaration: None,
span: sub_span.unwrap(),
- scope: self.analysis.ty_cx.map.get_parent(item.id),
+ scope: self.tcx.map.get_parent(item.id),
})
}
ast::ItemStatic(ref typ, mt, ref expr) => {
- let qualname = format!("::{}", self.analysis.ty_cx.map.path_to_string(item.id));
+ let qualname = format!("::{}", self.tcx.map.path_to_string(item.id));
// If the variable is immutable, save the initialising expression.
let (value, keyword) = match mt {
- ast::MutMutable => (String::from_str("<mutable>"), keywords::Mut),
+ ast::MutMutable => (String::from("<mutable>"), keywords::Mut),
ast::MutImmutable => (self.span_utils.snippet(expr.span), keywords::Static),
};
name: get_ident(item.ident).to_string(),
qualname: qualname,
span: sub_span.unwrap(),
- scope: self.analysis.ty_cx.map.get_parent(item.id),
+ scope: self.tcx.map.get_parent(item.id),
value: value,
type_value: ty_to_string(&typ),
})
}
ast::ItemConst(ref typ, ref expr) => {
- let qualname = format!("::{}", self.analysis.ty_cx.map.path_to_string(item.id));
+ let qualname = format!("::{}", self.tcx.map.path_to_string(item.id));
let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Const);
Data::VariableData(VariableData {
name: get_ident(item.ident).to_string(),
qualname: qualname,
span: sub_span.unwrap(),
- scope: self.analysis.ty_cx.map.get_parent(item.id),
+ scope: self.tcx.map.get_parent(item.id),
value: self.span_utils.snippet(expr.span),
type_value: ty_to_string(&typ),
})
}
+ ast::ItemMod(ref m) => {
+ let qualname = format!("::{}", self.tcx.map.path_to_string(item.id));
+
+ let cm = self.tcx.sess.codemap();
+ let filename = cm.span_to_filename(m.inner);
+
+ let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Mod);
+
+ Data::ModData(ModData {
+ id: item.id,
+ name: get_ident(item.ident).to_string(),
+ qualname: qualname,
+ span: sub_span.unwrap(),
+ scope: self.tcx.map.get_parent(item.id),
+ filename: filename,
+ })
+ },
+ ast::ItemEnum(..) => {
+ let enum_name = format!("::{}", self.tcx.map.path_to_string(item.id));
+ let val = self.span_utils.snippet(item.span);
+ let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Enum);
+
+ Data::EnumData(EnumData {
+ id: item.id,
+ value: val,
+ span: sub_span.unwrap(),
+ qualname: enum_name,
+ scope: self.tcx.map.get_parent(item.id),
+ })
+ },
+ ast::ItemImpl(_, _, _, ref trait_ref, ref typ, _) => {
+ let mut type_data = None;
+ let sub_span;
+
+ let parent = self.tcx.map.get_parent(item.id);
+
+ match typ.node {
+ // Common case impl for a struct or something basic.
+ ast::TyPath(None, ref path) => {
+ sub_span = self.span_utils.sub_span_for_type_name(path.span).unwrap();
+ type_data = self.lookup_ref_id(typ.id).map(|id| TypeRefData {
+ span: sub_span,
+ scope: parent,
+ ref_id: id,
+ });
+ },
+ _ => {
+ // Less useful case, impl for a compound type.
+ let span = typ.span;
+ sub_span = self.span_utils.sub_span_for_type_name(span).unwrap_or(span);
+ }
+ }
+
+ let trait_data =
+ trait_ref.as_ref().and_then(|tr| self.get_trait_ref_data(tr, parent));
+
+ Data::ImplData(ImplData {
+ id: item.id,
+ span: sub_span,
+ scope: parent,
+ trait_ref: trait_data,
+ self_ref: type_data,
+ })
+ }
_ => {
// FIXME
unimplemented!();
}
}
+ // FIXME: we ought to be able to get the parent id ourselves, but we can't
+ // for now.
+ pub fn get_field_data(&self, field: &ast::StructField, parent: NodeId) -> Option<Data> {
+ match field.node.kind {
+ ast::NamedField(ident, _) => {
+ let name = get_ident(ident);
+ let qualname = format!("::{}::{}",
+ self.tcx.map.path_to_string(parent),
+ name);
+ let typ = self.tcx.node_types().get(&field.node.id).unwrap()
+ .to_string();
+ let sub_span = self.span_utils.sub_span_before_token(field.span, token::Colon);
+ Some(Data::VariableData(VariableData {
+ id: field.node.id,
+ name: get_ident(ident).to_string(),
+ qualname: qualname,
+ span: sub_span.unwrap(),
+ scope: parent,
+ value: "".to_owned(),
+ type_value: typ,
+ }))
+ },
+ _ => None,
+ }
+ }
+
+ // FIXME: we ought to be able to get the parent id ourselves, but we can't
+ // for now.
+ pub fn get_trait_ref_data(&self,
+ trait_ref: &ast::TraitRef,
+ parent: NodeId)
+ -> Option<TypeRefData> {
+ self.lookup_ref_id(trait_ref.ref_id).map(|def_id| {
+ let span = trait_ref.path.span;
+ let sub_span = self.span_utils.sub_span_for_type_name(span).unwrap_or(span);
+ TypeRefData {
+ span: sub_span,
+ scope: parent,
+ ref_id: def_id,
+ }
+ })
+ }
+
+ pub fn get_expr_data(&self, expr: &ast::Expr) -> Option<Data> {
+ match expr.node {
+ ast::ExprField(ref sub_ex, ident) => {
+ let ty = &ty::expr_ty_adjusted(self.tcx, &sub_ex).sty;
+ match *ty {
+ ty::TyStruct(def_id, _) => {
+ let fields = ty::lookup_struct_fields(self.tcx, def_id);
+ for f in &fields {
+ if f.name == ident.node.name {
+ let sub_span = self.span_utils.span_for_last_ident(expr.span);
+ return Some(Data::VariableRefData(VariableRefData {
+ name: get_ident(ident.node).to_string(),
+ span: sub_span.unwrap(),
+ scope: self.tcx.map.get_parent(expr.id),
+ ref_id: f.id,
+ }));
+ }
+ }
+
+ self.tcx.sess.span_bug(expr.span,
+ &format!("Couldn't find field {} on {:?}",
+ &get_ident(ident.node), ty))
+ }
+ _ => {
+ debug!("Expected struct type, found {:?}", ty);
+ None
+ }
+ }
+ }
+ ast::ExprStruct(ref path, _, _) => {
+ let ty = &ty::expr_ty_adjusted(&self.tcx, expr).sty;
+ match *ty {
+ ty::TyStruct(def_id, _) => {
+ let sub_span = self.span_utils.span_for_last_ident(path.span);
+ Some(Data::TypeRefData(TypeRefData {
+ span: sub_span.unwrap(),
+ scope: self.tcx.map.get_parent(expr.id),
+ ref_id: def_id,
+ }))
+ }
+ _ => {
+ // FIXME ty could legitimately be a TyEnum, but then we will fail
+ // later if we try to look up the fields.
+ debug!("expected TyStruct, found {:?}", ty);
+ None
+ }
+ }
+ }
+ _ => {
+ // FIXME
+ unimplemented!();
+ }
+ }
+ }
+
+ pub fn get_field_ref_data(&self,
+ field_ref: &ast::Field,
+ struct_id: DefId,
+ parent: NodeId)
+ -> VariableRefData {
+ let fields = ty::lookup_struct_fields(&self.tcx, struct_id);
+ let field_name = get_ident(field_ref.ident.node).to_string();
+ for f in &fields {
+ if f.name == field_ref.ident.node.name {
+ // We don't really need a sub-span here, but no harm done
+ let sub_span = self.span_utils.span_for_last_ident(field_ref.ident.span);
+ return VariableRefData {
+ name: field_name,
+ span: sub_span.unwrap(),
+ scope: parent,
+ ref_id: f.id,
+ };
+ }
+ }
+
+ self.tcx.sess.span_bug(field_ref.span,
+ &format!("Couldn't find field {}", field_name));
+ }
+
pub fn get_data_for_id(&self, _id: &NodeId) -> Data {
// FIXME
unimplemented!();
}
+
+ fn lookup_ref_id(&self, ref_id: NodeId) -> Option<DefId> {
+ if !self.tcx.def_map.borrow().contains_key(&ref_id) {
+ self.tcx.sess.bug(&format!("def_map has no key for {} in lookup_type_ref",
+ ref_id));
+ }
+ let def = self.tcx.def_map.borrow().get(&ref_id).unwrap().full_def();
+ match def {
+ def::DefPrimTy(_) => None,
+ _ => Some(def.def_id()),
+ }
+ }
+
}
// An AST visitor for collecting paths from patterns.
self.collected_paths.push((p.id,
path.clone(),
ast::MutMutable,
- recorder::StructRef));
+ recorder::TypeRef));
}
ast::PatEnum(ref path, _) |
ast::PatQPath(_, ref path) => {
}
#[allow(deprecated)]
-pub fn process_crate(sess: &Session,
- krate: &ast::Crate,
+pub fn process_crate(tcx: &ty::ctxt,
analysis: &ty::CrateAnalysis,
odir: Option<&Path>) {
+ let krate = tcx.map.krate();
if generated_code(krate.span) {
return;
}
Some(name) => name.to_string(),
None => {
info!("Could not find crate name, using 'unknown_crate'");
- String::from_str("unknown_crate")
+ String::from("unknown_crate")
},
};
},
};
- match fs::create_dir_all(&root_path) {
- Err(e) => sess.err(&format!("Could not create directory {}: {}",
- root_path.display(), e)),
- _ => (),
+ if let Err(e) = fs::create_dir_all(&root_path) {
+ tcx.sess.err(&format!("Could not create directory {}: {}",
+ root_path.display(), e));
}
{
Ok(f) => box f,
Err(e) => {
let disp = root_path.display();
- sess.fatal(&format!("Could not open {}: {}", disp, e));
+ tcx.sess.fatal(&format!("Could not open {}: {}", disp, e));
}
};
root_path.pop();
- let mut visitor = dump_csv::DumpCsvVisitor::new(sess, analysis, output_file);
+ let mut visitor = dump_csv::DumpCsvVisitor::new(tcx, analysis, output_file);
- visitor.dump_crate_info(&cratename[..], krate);
+ visitor.dump_crate_info(&cratename, krate);
visit::walk_crate(&mut visitor, krate);
}
ModRef,
VarRef,
TypeRef,
- StructRef,
FnRef,
}
TypeRef => ("type_ref",
vec!("refid","refidcrate","qualname","scopeid"),
true, true),
- StructRef => ("struct_ref",
- vec!("refid","refidcrate","qualname","scopeid"),
- true, true),
FnRef => ("fn_ref", vec!("refid","refidcrate","qualname","scopeid"), true, true)
}
}
});
let pairs = fields.iter().zip(values);
- let strs = pairs.map(|(f, v)| format!(",{},\"{}\"", f, escape(String::from_str(v))));
+ let strs = pairs.map(|(f, v)| format!(",{},\"{}\"", f, escape(String::from(v))));
Some(strs.fold(String::new(), |mut s, ss| {
s.push_str(&ss[..]);
s
None => return,
};
- let mut result = String::from_str(label);
+ let mut result = String::from(label);
result.push_str(&values_str[..]);
result.push_str("\n");
self.recorder.record(&result[..]);
// the local case they can be overridden in one block and there is no nice way
// to refer to such a scope in english, so we just hack it by appending the
// variable def's node id
- let mut qualname = String::from_str(name);
+ let mut qualname = String::from(name);
qualname.push_str("$");
qualname.push_str(&id.to_string());
self.check_and_record(Variable,
fn_name: &str,
name: &str,
typ: &str) {
- let mut qualname = String::from_str(fn_name);
+ let mut qualname = String::from(fn_name);
qualname.push_str("::");
qualname.push_str(name);
self.check_and_record(Variable,
// the codemap as a new filemap. This is mostly OK, but means we should
// not iterate over the codemap. Also, any spans over the new filemap
// are incompatible with spans over other filemaps.
- let filemap = self.sess.codemap().new_filemap(String::from_str("<anon-dxr>"),
+ let filemap = self.sess.codemap().new_filemap(String::from("<anon-dxr>"),
self.snippet(span));
let s = self.sess;
lexer::StringReader::new(s.diagnostic(), filemap)
use session::config::{NoDebugInfo, FullDebugInfo};
use util::common::indenter;
use util::nodemap::FnvHashMap;
-use util::ppaux::{Repr, vec_map_to_string};
+use util::ppaux;
use std;
use std::cmp::Ordering;
+use std::fmt;
use std::rc::Rc;
use syntax::ast;
use syntax::ast::{DUMMY_NODE_ID, NodeId};
impl<'a> ConstantExpr<'a> {
fn eq(self, other: ConstantExpr<'a>, tcx: &ty::ctxt) -> bool {
- match const_eval::compare_lit_exprs(tcx, self.0, other.0, None) {
+ match const_eval::compare_lit_exprs(tcx, self.0, other.0, None,
+ |id| {ty::node_id_item_substs(tcx, id).substs}) {
Some(result) => result == Ordering::Equal,
None => panic!("compare_list_exprs: type mismatch"),
}
match *self {
ConstantValue(ConstantExpr(lit_expr), _) => {
let lit_ty = ty::node_id_to_type(bcx.tcx(), lit_expr.id);
- let (llval, _) = consts::const_expr(ccx, &*lit_expr, bcx.fcx.param_substs);
+ let (llval, _) = consts::const_expr(ccx, &*lit_expr, bcx.fcx.param_substs, None);
let lit_datum = immediate_rvalue(llval, lit_ty);
let lit_datum = unpack_datum!(bcx, lit_datum.to_appropriate_datum(bcx));
SingleResult(Result::new(bcx, lit_datum.val))
}
ConstantRange(ConstantExpr(ref l1), ConstantExpr(ref l2), _) => {
- let (l1, _) = consts::const_expr(ccx, &**l1, bcx.fcx.param_substs);
- let (l2, _) = consts::const_expr(ccx, &**l2, bcx.fcx.param_substs);
+ let (l1, _) = consts::const_expr(ccx, &**l1, bcx.fcx.param_substs, None);
+ let (l2, _) = consts::const_expr(ccx, &**l2, bcx.fcx.param_substs, None);
RangeResult(Result::new(bcx, l1), Result::new(bcx, l2))
}
Variant(disr_val, ref repr, _, _) => {
pat_renaming_map: Option<&'a FnvHashMap<(NodeId, Span), NodeId>>
}
-impl<'a, 'p, 'blk, 'tcx> Repr<'tcx> for Match<'a, 'p, 'blk, 'tcx> {
- fn repr(&self, tcx: &ty::ctxt) -> String {
- if tcx.sess.verbose() {
+impl<'a, 'p, 'blk, 'tcx> fmt::Debug for Match<'a, 'p, 'blk, 'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ if ppaux::verbose() {
// for many programs, this just take too long to serialize
- self.pats.repr(tcx)
+ write!(f, "{:?}", self.pats)
} else {
- format!("{} pats", self.pats.len())
+ write!(f, "{} pats", self.pats.len())
}
}
}
col: usize,
val: ValueRef)
-> Vec<Match<'a, 'p, 'blk, 'tcx>> {
- debug!("expand_nested_bindings(bcx={}, m={}, col={}, val={})",
+ debug!("expand_nested_bindings(bcx={}, m={:?}, col={}, val={})",
bcx.to_str(),
- m.repr(bcx.tcx()),
+ m,
col,
bcx.val_to_string(val));
let _indenter = indenter();
-> Vec<Match<'a, 'p, 'blk, 'tcx>> where
F: FnMut(&[&'p ast::Pat]) -> Option<Vec<&'p ast::Pat>>,
{
- debug!("enter_match(bcx={}, m={}, col={}, val={})",
+ debug!("enter_match(bcx={}, m={:?}, col={}, val={})",
bcx.to_str(),
- m.repr(bcx.tcx()),
+ m,
col,
bcx.val_to_string(val));
let _indenter = indenter();
col: usize,
val: ValueRef)
-> Vec<Match<'a, 'p, 'blk, 'tcx>> {
- debug!("enter_default(bcx={}, m={}, col={}, val={})",
+ debug!("enter_default(bcx={}, m={:?}, col={}, val={})",
bcx.to_str(),
- m.repr(bcx.tcx()),
+ m,
col,
bcx.val_to_string(val));
let _indenter = indenter();
variant_size: usize,
val: ValueRef)
-> Vec<Match<'a, 'p, 'blk, 'tcx>> {
- debug!("enter_opt(bcx={}, m={}, opt={:?}, col={}, val={})",
+ debug!("enter_opt(bcx={}, m={:?}, opt={:?}, col={}, val={})",
bcx.to_str(),
- m.repr(bcx.tcx()),
+ m,
*opt,
col,
bcx.val_to_string(val));
-> Result<'blk, 'tcx> {
let did = langcall(cx,
None,
- &format!("comparison of `{}`",
- cx.ty_to_string(rhs_t)),
+ &format!("comparison of `{}`", rhs_t),
StrEqFnLangItem);
- let t = ty::mk_str_slice(cx.tcx(), cx.tcx().mk_region(ty::ReStatic), ast::MutImmutable);
- // The comparison function gets the slices by value, so we have to make copies here. Even
- // if the function doesn't write through the pointer, things like lifetime intrinsics
- // require that we do this properly
- let lhs_arg = alloc_ty(cx, t, "lhs");
- let rhs_arg = alloc_ty(cx, t, "rhs");
- memcpy_ty(cx, lhs_arg, lhs, t);
- memcpy_ty(cx, rhs_arg, rhs, t);
- let res = callee::trans_lang_call(cx, did, &[lhs_arg, rhs_arg], None, debug_loc);
- call_lifetime_end(res.bcx, lhs_arg);
- call_lifetime_end(res.bcx, rhs_arg);
-
- res
+ let lhs_data = Load(cx, expr::get_dataptr(cx, lhs));
+ let lhs_len = Load(cx, expr::get_len(cx, lhs));
+ let rhs_data = Load(cx, expr::get_dataptr(cx, rhs));
+ let rhs_len = Load(cx, expr::get_len(cx, rhs));
+ callee::trans_lang_call(cx, did, &[lhs_data, lhs_len, rhs_data, rhs_len], None, debug_loc)
}
let _icx = push_ctxt("compare_values");
}
match rhs_t.sty {
- ty::ty_rptr(_, mt) => match mt.ty.sty {
- ty::ty_str => compare_str(cx, lhs, rhs, rhs_t, debug_loc),
- ty::ty_vec(ty, _) => match ty.sty {
- ty::ty_uint(ast::TyU8) => {
+ ty::TyRef(_, mt) => match mt.ty.sty {
+ ty::TyStr => compare_str(cx, lhs, rhs, rhs_t, debug_loc),
+ ty::TyArray(ty, _) | ty::TySlice(ty) => match ty.sty {
+ ty::TyUint(ast::TyU8) => {
// NOTE: cast &[u8] and &[u8; N] to &str and abuse the str_eq lang item,
// which calls memcmp().
let pat_len = val_ty(rhs).element_type().array_length();
chk: &FailureHandler,
has_genuine_default: bool)
-> Block<'blk, 'tcx> {
- debug!("compile_guard(bcx={}, guard_expr={}, m={}, vals={})",
+ debug!("compile_guard(bcx={}, guard_expr={:?}, m={:?}, vals=[{}])",
bcx.to_str(),
- bcx.expr_to_string(guard_expr),
- m.repr(bcx.tcx()),
- vec_map_to_string(vals, |v| bcx.val_to_string(*v)));
+ guard_expr,
+ m,
+ vals.iter().map(|v| bcx.val_to_string(*v)).collect::<Vec<_>>().connect(", "));
let _indenter = indenter();
let mut bcx = insert_lllocals(bcx, &data.bindings_map, None);
vals: &[ValueRef],
chk: &FailureHandler,
has_genuine_default: bool) {
- debug!("compile_submatch(bcx={}, m={}, vals={})",
+ debug!("compile_submatch(bcx={}, m={:?}, vals=[{}])",
bcx.to_str(),
- m.repr(bcx.tcx()),
- vec_map_to_string(vals, |v| bcx.val_to_string(*v)));
+ m,
+ vals.iter().map(|v| bcx.val_to_string(*v)).collect::<Vec<_>>().connect(", "));
let _indenter = indenter();
let _icx = push_ctxt("match::compile_submatch");
let mut bcx = bcx;
).collect();
match left_ty.sty {
- ty::ty_struct(def_id, substs) if !type_is_sized(bcx.tcx(), left_ty) => {
+ ty::TyStruct(def_id, substs) if !type_is_sized(bcx.tcx(), left_ty) => {
// The last field is technically unsized but
// since we can only ever match that field behind
// a reference we construct a fat ptr here.
Some(vec!(Load(bcx, val)))
} else {
match left_ty.sty {
- ty::ty_vec(_, Some(n)) => {
+ ty::TyArray(_, n) => {
let args = extract_vec_elems(bcx, left_ty, n, 0, val);
Some(args.vals)
}
};
let mut matches = Vec::new();
- for (arm_data, pats) in arm_datas.iter().zip(arm_pats.iter()) {
+ for (arm_data, pats) in arm_datas.iter().zip(&arm_pats) {
matches.extend(pats.iter().map(|p| Match {
pats: vec![&**p],
data: arm_data,
val: ValueRef,
cleanup_scope: cleanup::ScopeId)
-> Block<'blk, 'tcx> {
- debug!("bind_irrefutable_pat(bcx={}, pat={})",
+ debug!("bind_irrefutable_pat(bcx={}, pat={:?})",
bcx.to_str(),
- pat.repr(bcx.tcx()));
+ pat);
if bcx.sess().asm_comments() {
- add_comment(bcx, &format!("bind_irrefutable_pat(pat={})",
- pat.repr(bcx.tcx())));
+ add_comment(bcx, &format!("bind_irrefutable_pat(pat={:?})",
+ pat));
}
let _indenter = indenter();
.iter()
.chain(slice.iter())
.chain(after.iter())
- .zip(extracted.vals.into_iter())
+ .zip(extracted.vals)
.fold(bcx, |bcx, (inner, elem)|
bind_irrefutable_pat(bcx, &**inner, elem, cleanup_scope)
);
use trans::monomorphize;
use trans::type_::Type;
use trans::type_of;
-use util::ppaux::ty_to_string;
type Hint = attr::ReprAttr;
pub fn represent_type<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
t: Ty<'tcx>)
-> Rc<Repr<'tcx>> {
- debug!("Representing: {}", ty_to_string(cx.tcx(), t));
+ debug!("Representing: {}", t);
match cx.adt_reprs().borrow().get(&t) {
Some(repr) => return repr.clone(),
None => {}
fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
t: Ty<'tcx>) -> Repr<'tcx> {
match t.sty {
- ty::ty_tup(ref elems) => {
+ ty::TyTuple(ref elems) => {
Univariant(mk_struct(cx, &elems[..], false, t), 0)
}
- ty::ty_struct(def_id, substs) => {
+ ty::TyStruct(def_id, substs) => {
let fields = ty::lookup_struct_fields(cx.tcx(), def_id);
let mut ftys = fields.iter().map(|field| {
let fty = ty::lookup_field_type(cx.tcx(), def_id, field.id, substs);
Univariant(mk_struct(cx, &ftys[..], packed, t), dtor_to_init_u8(dtor))
}
- ty::ty_closure(def_id, substs) => {
+ ty::TyClosure(def_id, substs) => {
let typer = NormalizingClosureTyper::new(cx.tcx());
let upvars = typer.closure_upvars(def_id, substs).unwrap();
let upvar_types = upvars.iter().map(|u| u.ty).collect::<Vec<_>>();
Univariant(mk_struct(cx, &upvar_types[..], false, t), 0)
}
- ty::ty_enum(def_id, substs) => {
+ ty::TyEnum(def_id, substs) => {
let cases = get_cases(cx.tcx(), def_id, substs);
let hint = *ty::lookup_repr_hints(cx.tcx(), def_id).get(0)
.unwrap_or(&attr::ReprAny);
General(ity, fields, dtor_to_init_u8(dtor))
}
- _ => cx.sess().bug(&format!("adt::represent_type called on non-ADT type: {}",
- ty_to_string(cx.tcx(), t)))
+ _ => cx.sess().bug(&format!("adt::represent_type called on non-ADT type: {}", t))
}
}
mut path: DiscrField) -> Option<DiscrField> {
match ty.sty {
// Fat &T/&mut T/Box<T> i.e. T is [T], str, or Trait
- ty::ty_rptr(_, ty::mt { ty, .. }) | ty::ty_uniq(ty) if !type_is_sized(tcx, ty) => {
+ ty::TyRef(_, ty::mt { ty, .. }) | ty::TyBox(ty) if !type_is_sized(tcx, ty) => {
path.push(FAT_PTR_ADDR);
Some(path)
},
// Regular thin pointer: &T/&mut T/Box<T>
- ty::ty_rptr(..) | ty::ty_uniq(..) => Some(path),
+ ty::TyRef(..) | ty::TyBox(..) => Some(path),
// Functions are just pointers
- ty::ty_bare_fn(..) => Some(path),
+ ty::TyBareFn(..) => Some(path),
// Is this the NonZero lang item wrapping a pointer or integer type?
- ty::ty_struct(did, substs) if Some(did) == tcx.lang_items.non_zero() => {
+ ty::TyStruct(did, substs) if Some(did) == tcx.lang_items.non_zero() => {
let nonzero_fields = ty::lookup_struct_fields(tcx, did);
assert_eq!(nonzero_fields.len(), 1);
let nonzero_field = ty::lookup_field_type(tcx, did, nonzero_fields[0].id, substs);
match nonzero_field.sty {
- ty::ty_ptr(ty::mt { ty, .. }) if !type_is_sized(tcx, ty) => {
+ ty::TyRawPtr(ty::mt { ty, .. }) if !type_is_sized(tcx, ty) => {
path.push_all(&[0, FAT_PTR_ADDR]);
Some(path)
},
- ty::ty_ptr(..) | ty::ty_int(..) | ty::ty_uint(..) => {
+ ty::TyRawPtr(..) | ty::TyInt(..) | ty::TyUint(..) => {
path.push(0);
Some(path)
},
// Perhaps one of the fields of this struct is non-zero
// let's recurse and find out
- ty::ty_struct(def_id, substs) => {
+ ty::TyStruct(def_id, substs) => {
let fields = ty::lookup_struct_fields(tcx, def_id);
for (j, field) in fields.iter().enumerate() {
let field_ty = ty::lookup_field_type(tcx, def_id, field.id, substs);
// Perhaps one of the upvars of this struct is non-zero
// Let's recurse and find out!
- ty::ty_closure(def_id, substs) => {
+ ty::TyClosure(def_id, substs) => {
let typer = NormalizingClosureTyper::new(tcx);
let upvars = typer.closure_upvars(def_id, substs).unwrap();
let upvar_types = upvars.iter().map(|u| u.ty).collect::<Vec<_>>();
},
// Can we use one of the fields in this tuple?
- ty::ty_tup(ref tys) => {
+ ty::TyTuple(ref tys) => {
for (j, &ty) in tys.iter().enumerate() {
if let Some(mut fpath) = find_discr_field_candidate(tcx, ty, path.clone()) {
fpath.push(j);
// Is this a fixed-size array of something non-zero
// with at least one element?
- ty::ty_vec(ety, Some(d)) if d > 0 => {
+ ty::TyArray(ety, d) if d > 0 => {
if let Some(mut vpath) = find_discr_field_candidate(tcx, ety, path) {
vpath.push(0);
Some(vpath)
}
}
-
+pub fn is_discr_signed<'tcx>(r: &Repr<'tcx>) -> bool {
+ match *r {
+ CEnum(ity, _, _) => ity.is_signed(),
+ General(ity, _, _) => ity.is_signed(),
+ Univariant(..) => false,
+ RawNullablePointer { .. } => false,
+ StructWrappedNullablePointer { .. } => false,
+ }
+}
/// Obtain the actual discriminant of a value.
pub fn trans_get_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
scrutinee: ValueRef, cast_to: Option<Type>)
-> ValueRef {
- let signed;
- let val;
debug!("trans_get_discr r: {:?}", r);
- match *r {
- CEnum(ity, min, max) => {
- val = load_discr(bcx, ity, scrutinee, min, max);
- signed = ity.is_signed();
- }
+ let val = match *r {
+ CEnum(ity, min, max) => load_discr(bcx, ity, scrutinee, min, max),
General(ity, ref cases, _) => {
let ptr = GEPi(bcx, scrutinee, &[0, 0]);
- val = load_discr(bcx, ity, ptr, 0, (cases.len() - 1) as Disr);
- signed = ity.is_signed();
- }
- Univariant(..) => {
- val = C_u8(bcx.ccx(), 0);
- signed = false;
+ load_discr(bcx, ity, ptr, 0, (cases.len() - 1) as Disr)
}
+ Univariant(..) => C_u8(bcx.ccx(), 0),
RawNullablePointer { nndiscr, nnty, .. } => {
let cmp = if nndiscr == 0 { IntEQ } else { IntNE };
let llptrty = type_of::sizing_type_of(bcx.ccx(), nnty);
- val = ICmp(bcx, cmp, Load(bcx, scrutinee), C_null(llptrty), DebugLoc::None);
- signed = false;
+ ICmp(bcx, cmp, Load(bcx, scrutinee), C_null(llptrty), DebugLoc::None)
}
StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => {
- val = struct_wrapped_nullable_bitdiscr(bcx, nndiscr, discrfield, scrutinee);
- signed = false;
+ struct_wrapped_nullable_bitdiscr(bcx, nndiscr, discrfield, scrutinee)
}
- }
+ };
match cast_to {
None => val,
- Some(llty) => if signed { SExt(bcx, val, llty) } else { ZExt(bcx, val, llty) }
+ Some(llty) => if is_discr_signed(r) { SExt(bcx, val, llty) } else { ZExt(bcx, val, llty) }
}
}
}
General(ity, ref cases, _) => {
let ccx = bcx.ccx();
- let unr_cx = fcx.new_temp_block("enum-variant-iter-unr");
- Unreachable(unr_cx);
+
+ // See the comments in trans/base.rs for more information (inside
+ // iter_structural_ty), but the gist here is that if the enum's
+ // discriminant is *not* in the range that we're expecting (in which
+ // case we'll take the fall-through branch on the switch
+ // instruction) then we can't just optimize this to an Unreachable
+ // block.
+ //
+ // Currently we still have filling drop, so this means that the drop
+ // glue for enums may be called when the enum has been paved over
+ // with the "I've been dropped" value. In this case the default
+ // branch of the switch instruction will actually be taken at
+ // runtime, so the basic block isn't actually unreachable, so we
+ // need to make it do something with defined behavior. In this case
+ // we just return early from the function.
+ let ret_void_cx = fcx.new_temp_block("enum-variant-iter-ret-void");
+ RetVoid(ret_void_cx, DebugLoc::None);
let discr_val = trans_get_discr(bcx, r, value, None);
- let llswitch = Switch(bcx, discr_val, unr_cx.llbb, cases.len());
+ let llswitch = Switch(bcx, discr_val, ret_void_cx.llbb, cases.len());
let bcx_next = fcx.new_temp_block("enum-variant-iter-next");
for (discr, case) in cases.iter().enumerate() {
// offset of current value
let mut offset = 0;
let mut cfields = Vec::new();
- for (&val, &target_offset) in vals.iter().zip(target_offsets.iter()) {
+ for (&val, target_offset) in vals.iter().zip(target_offsets) {
if !st.packed {
let val_align = machine::llalign_of_min(ccx, val_ty(val));
offset = roundup(offset, val_align);
output_types.push(type_of::type_of(bcx.ccx(), out_datum.ty));
let val = out_datum.val;
if is_rw {
- ext_inputs.push(unpack_result!(bcx, {
- callee::trans_arg_datum(bcx,
- expr_ty(bcx, &**out),
- out_datum,
- cleanup::CustomScope(temp_scope),
- callee::DontAutorefArg)
- }));
+ bcx = callee::trans_arg_datum(bcx,
+ expr_ty(bcx, &**out),
+ out_datum,
+ cleanup::CustomScope(temp_scope),
+ callee::DontAutorefArg,
+ &mut ext_inputs);
ext_constraints.push(i.to_string());
}
val
}).collect::<Vec<_>>();
// Now the input operands
- let mut inputs = ia.inputs.iter().map(|&(ref c, ref input)| {
+ let mut inputs = Vec::new();
+ for &(ref c, ref input) in &ia.inputs {
constraints.push((*c).clone());
let in_datum = unpack_datum!(bcx, expr::trans(bcx, &**input));
- unpack_result!(bcx, {
- callee::trans_arg_datum(bcx,
+ bcx = callee::trans_arg_datum(bcx,
expr_ty(bcx, &**input),
in_datum,
cleanup::CustomScope(temp_scope),
- callee::DontAutorefArg)
- })
- }).collect::<Vec<_>>();
+ callee::DontAutorefArg,
+ &mut inputs);
+ }
inputs.push_all(&ext_inputs[..]);
// no failure occurred preparing operands, no need to cleanup
let all_constraints= constraints.iter()
.map(|s| s.to_string())
- .chain(ext_constraints.into_iter())
+ .chain(ext_constraints)
.chain(clobbers)
.chain(arch_clobbers.iter()
.map(|s| s.to_string()))
use libc::{c_uint, c_ulonglong};
use llvm::{self, ValueRef, AttrHelper};
use middle::ty::{self, ClosureTyper};
+use session::config::NoDebugInfo;
use syntax::abi;
use syntax::ast;
pub use syntax::attr::InlineAttr;
use syntax::attr::*;
inline(llfn, find_inline_attr(Some(ccx.sess().diagnostic()), attrs));
+ // FIXME: #11906: Omitting frame pointers breaks retrieving the value of a
+ // parameter.
+ let no_fp_elim = (ccx.sess().opts.debuginfo != NoDebugInfo) ||
+ !ccx.sess().target.target.options.eliminate_frame_pointer;
+ if no_fp_elim {
+ unsafe {
+ let attr = "no-frame-pointer-elim\0".as_ptr() as *const _;
+ let val = "true\0".as_ptr() as *const _;
+ llvm::LLVMAddFunctionAttrStringValue(llfn,
+ llvm::FunctionIndex as c_uint,
+ attr, val);
+ }
+ }
+
for attr in attrs {
if attr.check_name("no_stack_check") {
split_stack(llfn, false);
let function_type;
let (fn_sig, abi, env_ty) = match fn_type.sty {
- ty::ty_bare_fn(_, ref f) => (&f.sig, f.abi, None),
- ty::ty_closure(closure_did, substs) => {
+ ty::TyBareFn(_, ref f) => (&f.sig, f.abi, None),
+ ty::TyClosure(closure_did, substs) => {
let typer = common::NormalizingClosureTyper::new(ccx.tcx());
function_type = typer.closure_type(closure_did, substs);
let self_type = base::self_type_for_closure(ccx, closure_did, fn_type);
// These have an odd calling convention, so we need to manually
// unpack the input ty's
let input_tys = match fn_type.sty {
- ty::ty_closure(..) => {
+ ty::TyClosure(..) => {
assert!(abi == abi::RustCall);
match fn_sig.inputs[0].sty {
- ty::ty_tup(ref inputs) => {
+ ty::TyTuple(ref inputs) => {
let mut full_inputs = vec![env_ty.expect("Missing closure environment")];
full_inputs.push_all(inputs);
full_inputs
_ => ccx.sess().bug("expected tuple'd inputs")
}
},
- ty::ty_bare_fn(..) if abi == abi::RustCall => {
+ ty::TyBareFn(..) if abi == abi::RustCall => {
let mut inputs = vec![fn_sig.inputs[0]];
match fn_sig.inputs[1].sty {
- ty::ty_tup(ref t_in) => {
+ ty::TyTuple(ref t_in) => {
inputs.push_all(&t_in[..]);
inputs
}
};
// Index 0 is the return value of the llvm func, so we start at 1
- let mut first_arg_offset = 1;
+ let mut idx = 1;
if let ty::FnConverging(ret_ty) = ret_ty {
// A function pointer is called without the declaration
// available, so we have to apply any attributes with ABI
.arg(1, llvm::DereferenceableAttribute(llret_sz));
// Add one more since there's an outptr
- first_arg_offset += 1;
+ idx += 1;
} else {
// The `noalias` attribute on the return value is useful to a
// function ptr caller.
match ret_ty.sty {
// `Box` pointer return values never alias because ownership
// is transferred
- ty::ty_uniq(it) if common::type_is_sized(ccx.tcx(), it) => {
+ ty::TyBox(it) if common::type_is_sized(ccx.tcx(), it) => {
attrs.ret(llvm::Attribute::NoAlias);
}
_ => {}
// We can also mark the return value as `dereferenceable` in certain cases
match ret_ty.sty {
// These are not really pointers but pairs, (pointer, len)
- ty::ty_rptr(_, ty::mt { ty: inner, .. })
- | ty::ty_uniq(inner) if common::type_is_sized(ccx.tcx(), inner) => {
+ ty::TyRef(_, ty::mt { ty: inner, .. })
+ | ty::TyBox(inner) if common::type_is_sized(ccx.tcx(), inner) => {
let llret_sz = machine::llsize_of_real(ccx, type_of::type_of(ccx, inner));
attrs.ret(llvm::DereferenceableAttribute(llret_sz));
}
_ => {}
}
- if let ty::ty_bool = ret_ty.sty {
+ if let ty::TyBool = ret_ty.sty {
attrs.ret(llvm::Attribute::ZExt);
}
}
}
- for (idx, &t) in input_tys.iter().enumerate().map(|(i, v)| (i + first_arg_offset, v)) {
+ for &t in input_tys.iter() {
match t.sty {
- // this needs to be first to prevent fat pointers from falling through
- _ if !common::type_is_immediate(ccx, t) => {
+ _ if type_of::arg_is_indirect(ccx, t) => {
let llarg_sz = machine::llsize_of_real(ccx, type_of::type_of(ccx, t));
// For non-immediate arguments the callee gets its own copy of
.arg(idx, llvm::DereferenceableAttribute(llarg_sz));
}
- ty::ty_bool => {
+ ty::TyBool => {
attrs.arg(idx, llvm::Attribute::ZExt);
}
// `Box` pointer parameters never alias because ownership is transferred
- ty::ty_uniq(inner) => {
- let llsz = machine::llsize_of_real(ccx, type_of::type_of(ccx, inner));
-
- attrs.arg(idx, llvm::Attribute::NoAlias)
- .arg(idx, llvm::DereferenceableAttribute(llsz));
+ ty::TyBox(inner) => {
+ attrs.arg(idx, llvm::Attribute::NoAlias);
+
+ if common::type_is_sized(ccx.tcx(), inner) {
+ let llsz = machine::llsize_of_real(ccx, type_of::type_of(ccx, inner));
+ attrs.arg(idx, llvm::DereferenceableAttribute(llsz));
+ } else {
+ attrs.arg(idx, llvm::NonNullAttribute);
+ if ty::type_is_trait(inner) {
+ attrs.arg(idx + 1, llvm::NonNullAttribute);
+ }
+ }
}
- // `&mut` pointer parameters never alias other parameters, or mutable global data
- //
- // `&T` where `T` contains no `UnsafeCell<U>` is immutable, and can be marked as both
- // `readonly` and `noalias`, as LLVM's definition of `noalias` is based solely on
- // memory dependencies rather than pointer equality
- ty::ty_rptr(b, mt) if mt.mutbl == ast::MutMutable ||
- !ty::type_contents(ccx.tcx(), mt.ty).interior_unsafe() => {
+ ty::TyRef(b, mt) => {
+ // `&mut` pointer parameters never alias other parameters, or mutable global data
+ //
+ // `&T` where `T` contains no `UnsafeCell<U>` is immutable, and can be marked as
+ // both `readonly` and `noalias`, as LLVM's definition of `noalias` is based solely
+ // on memory dependencies rather than pointer equality
+ let interior_unsafe = ty::type_contents(ccx.tcx(), mt.ty).interior_unsafe();
- let llsz = machine::llsize_of_real(ccx, type_of::type_of(ccx, mt.ty));
- attrs.arg(idx, llvm::Attribute::NoAlias)
- .arg(idx, llvm::DereferenceableAttribute(llsz));
+ if mt.mutbl == ast::MutMutable || !interior_unsafe {
+ attrs.arg(idx, llvm::Attribute::NoAlias);
+ }
- if mt.mutbl == ast::MutImmutable {
+ if mt.mutbl == ast::MutImmutable && !interior_unsafe {
attrs.arg(idx, llvm::Attribute::ReadOnly);
}
+ // & pointer parameters are also never null and for sized types we also know
+ // exactly how many bytes we can dereference
+ if common::type_is_sized(ccx.tcx(), mt.ty) {
+ let llsz = machine::llsize_of_real(ccx, type_of::type_of(ccx, mt.ty));
+ attrs.arg(idx, llvm::DereferenceableAttribute(llsz));
+ } else {
+ attrs.arg(idx, llvm::NonNullAttribute);
+ if ty::type_is_trait(mt.ty) {
+ attrs.arg(idx + 1, llvm::NonNullAttribute);
+ }
+ }
+
+ // When a reference in an argument has no named lifetime, it's
+ // impossible for that reference to escape this function
+ // (returned or stored beyond the call by a closure).
if let ReLateBound(_, BrAnon(_)) = *b {
attrs.arg(idx, llvm::Attribute::NoCapture);
}
}
- // When a reference in an argument has no named lifetime, it's impossible for that
- // reference to escape this function (returned or stored beyond the call by a closure).
- ty::ty_rptr(&ReLateBound(_, BrAnon(_)), mt) => {
- let llsz = machine::llsize_of_real(ccx, type_of::type_of(ccx, mt.ty));
- attrs.arg(idx, llvm::Attribute::NoCapture)
- .arg(idx, llvm::DereferenceableAttribute(llsz));
- }
-
- // & pointer parameters are also never null and we know exactly how
- // many bytes we can dereference
- ty::ty_rptr(_, mt) => {
- let llsz = machine::llsize_of_real(ccx, type_of::type_of(ccx, mt.ty));
- attrs.arg(idx, llvm::DereferenceableAttribute(llsz));
- }
_ => ()
}
+
+ if common::type_is_fat_ptr(ccx.tcx(), t) {
+ idx += 2;
+ } else {
+ idx += 1;
+ }
}
attrs
use middle::weak_lang_items;
use middle::subst::Substs;
use middle::ty::{self, Ty, ClosureTyper, type_is_simd, simd_size};
+use rustc::ast_map;
use session::config::{self, NoDebugInfo};
use session::Session;
use trans::_match;
use trans::type_of::*;
use trans::value::Value;
use util::common::indenter;
-use util::ppaux::{Repr, ty_to_string};
use util::sha2::Sha256;
use util::nodemap::NodeMap;
use syntax::parse::token::InternedString;
use syntax::visit::Visitor;
use syntax::visit;
-use syntax::{ast, ast_util, ast_map};
+use syntax::{ast, ast_util};
thread_local! {
static TASK_LOCAL_INSN_KEY: RefCell<Option<Vec<&'static str>>> = {
// don't do this then linker errors can be generated where the linker
// complains that one object files has a thread local version of the
// symbol and another one doesn't.
- for attr in &*ty::get_attrs(ccx.tcx(), did) {
+ for attr in ty::get_attrs(ccx.tcx(), did).iter() {
if attr.check_name("thread_local") {
llvm::set_thread_local(c, true);
}
}
+ if ccx.use_dll_storage_attrs() {
+ llvm::SetDLLStorageClass(c, llvm::DLLImportStorageClass);
+ }
ccx.externs().borrow_mut().insert(name.to_string(), c);
return c;
}
match bcx.tcx().lang_items.require(it) {
Ok(id) => id,
Err(s) => {
- bcx.sess().fatal(&format!("allocation of `{}` {}",
- bcx.ty_to_string(info_ty),
- s));
+ bcx.sess().fatal(&format!("allocation of `{}` {}", info_ty, s));
}
}
}
debug_loc: DebugLoc)
-> ValueRef {
match t.sty {
- ty::ty_tup(ref tys) if tys.is_empty() => {
+ ty::TyTuple(ref tys) if tys.is_empty() => {
// We don't need to do actual comparisons for nil.
// () == () holds but () < () does not.
match op {
_ => bcx.sess().bug("compare_scalar_types: must be a comparison operator")
}
}
- ty::ty_bare_fn(..) | ty::ty_bool | ty::ty_uint(_) | ty::ty_char => {
+ ty::TyBareFn(..) | ty::TyBool | ty::TyUint(_) | ty::TyChar => {
ICmp(bcx, bin_op_to_icmp_predicate(bcx.ccx(), op, false), lhs, rhs, debug_loc)
}
- ty::ty_ptr(mt) if common::type_is_sized(bcx.tcx(), mt.ty) => {
+ ty::TyRawPtr(mt) if common::type_is_sized(bcx.tcx(), mt.ty) => {
ICmp(bcx, bin_op_to_icmp_predicate(bcx.ccx(), op, false), lhs, rhs, debug_loc)
}
- ty::ty_int(_) => {
+ ty::TyInt(_) => {
ICmp(bcx, bin_op_to_icmp_predicate(bcx.ccx(), op, true), lhs, rhs, debug_loc)
}
- ty::ty_float(_) => {
+ ty::TyFloat(_) => {
FCmp(bcx, bin_op_to_fcmp_predicate(bcx.ccx(), op), lhs, rhs, debug_loc)
}
// Should never get here, because t is scalar.
debug_loc: DebugLoc)
-> ValueRef {
let signed = match t.sty {
- ty::ty_float(_) => {
+ ty::TyFloat(_) => {
// The comparison operators for floating point vectors are challenging.
// LLVM outputs a `< size x i1 >`, but if we perform a sign extension
// then bitcast to a floating point vector, the result will be `-NaN`
bcx.sess().bug("compare_simd_types: comparison operators \
not supported for floating point SIMD types")
},
- ty::ty_uint(_) => false,
- ty::ty_int(_) => true,
+ ty::TyUint(_) => false,
+ ty::TyInt(_) => true,
_ => bcx.sess().bug("compare_simd_types: invalid SIMD type"),
};
let mut cx = cx;
match t.sty {
- ty::ty_struct(..) => {
+ ty::TyStruct(..) => {
let repr = adt::represent_type(cx.ccx(), t);
expr::with_field_tys(cx.tcx(), t, None, |discr, field_tys| {
for (i, field_ty) in field_tys.iter().enumerate() {
}
})
}
- ty::ty_closure(def_id, substs) => {
+ ty::TyClosure(def_id, substs) => {
let repr = adt::represent_type(cx.ccx(), t);
let typer = common::NormalizingClosureTyper::new(cx.tcx());
let upvars = typer.closure_upvars(def_id, substs).unwrap();
cx = f(cx, llupvar, upvar.ty);
}
}
- ty::ty_vec(_, Some(n)) => {
+ ty::TyArray(_, n) => {
let (base, len) = tvec::get_fixed_base_and_len(cx, data_ptr, n);
let unit_ty = ty::sequence_element_type(cx.tcx(), t);
cx = tvec::iter_vec_raw(cx, base, unit_ty, len, f);
}
- ty::ty_vec(_, None) | ty::ty_str => {
+ ty::TySlice(_) | ty::TyStr => {
let unit_ty = ty::sequence_element_type(cx.tcx(), t);
cx = tvec::iter_vec_raw(cx, data_ptr, unit_ty, info.unwrap(), f);
}
- ty::ty_tup(ref args) => {
+ ty::TyTuple(ref args) => {
let repr = adt::represent_type(cx.ccx(), t);
for (i, arg) in args.iter().enumerate() {
let llfld_a = adt::trans_field_ptr(cx, &*repr, data_ptr, 0, i);
cx = f(cx, llfld_a, *arg);
}
}
- ty::ty_enum(tid, substs) => {
+ ty::TyEnum(tid, substs) => {
let fcx = cx.fcx;
let ccx = fcx.ccx;
}
(_match::Switch, Some(lldiscrim_a)) => {
cx = f(cx, lldiscrim_a, cx.tcx().types.isize);
- let unr_cx = fcx.new_temp_block("enum-iter-unr");
- Unreachable(unr_cx);
- let llswitch = Switch(cx, lldiscrim_a, unr_cx.llbb,
+
+ // Create a fall-through basic block for the "else" case of
+ // the switch instruction we're about to generate. Note that
+ // we do **not** use an Unreachable instruction here, even
+ // though most of the time this basic block will never be hit.
+ //
+ // When an enum is dropped it's contents are currently
+ // overwritten to DTOR_DONE, which means the discriminant
+ // could have changed value to something not within the actual
+ // range of the discriminant. Currently this function is only
+ // used for drop glue so in this case we just return quickly
+ // from the outer function, and any other use case will only
+ // call this for an already-valid enum in which case the `ret
+ // void` will never be hit.
+ let ret_void_cx = fcx.new_temp_block("enum-iter-ret-void");
+ RetVoid(ret_void_cx, DebugLoc::None);
+ let llswitch = Switch(cx, lldiscrim_a, ret_void_cx.llbb,
n_variants);
let next_cx = fcx.new_temp_block("enum-iter-next");
}
}
_ => {
- cx.sess().unimpl(&format!("type in iter_structural_ty: {}",
- ty_to_string(cx.tcx(), t)))
+ cx.sess().unimpl(&format!("type in iter_structural_ty: {}", t))
}
}
return cx;
pub fn llty_and_min_for_signed_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
val_t: Ty<'tcx>) -> (Type, u64) {
match val_t.sty {
- ty::ty_int(t) => {
+ ty::TyInt(t) => {
let llty = Type::int_from_ty(cx.ccx(), t);
let min = match t {
ast::TyIs if llty == Type::i32(cx.ccx()) => i32::MIN as u64,
let debug_loc = call_info.debug_loc();
let (is_zero, is_signed) = match rhs_t.sty {
- ty::ty_int(t) => {
+ ty::TyInt(t) => {
let zero = C_integral(Type::int_from_ty(cx.ccx(), t), 0, false);
(ICmp(cx, llvm::IntEQ, rhs, zero, debug_loc), true)
}
- ty::ty_uint(t) => {
+ ty::TyUint(t) => {
let zero = C_integral(Type::uint_from_ty(cx.ccx(), t), 0, false);
(ICmp(cx, llvm::IntEQ, rhs, zero, debug_loc), false)
}
- ty::ty_struct(_, _) if type_is_simd(cx.tcx(), rhs_t) => {
+ ty::TyStruct(_, _) if type_is_simd(cx.tcx(), rhs_t) => {
let mut res = C_bool(cx.ccx(), false);
for i in 0 .. simd_size(cx.tcx(), rhs_t) {
res = Or(cx, res,
(res, false)
}
_ => {
- cx.sess().bug(&format!("fail-if-zero on unexpected type: {}",
- ty_to_string(cx.tcx(), rhs_t)));
+ cx.sess().bug(&format!("fail-if-zero on unexpected type: {}", rhs_t));
}
};
let bcx = with_cond(cx, is_zero, |bcx| {
did: ast::DefId, t: Ty<'tcx>) -> ValueRef {
let name = csearch::get_symbol(&ccx.sess().cstore, did);
match t.sty {
- ty::ty_bare_fn(_, ref fn_ty) => {
+ ty::TyBareFn(_, ref fn_ty) => {
match ccx.sess().target.target.adjust_abi(fn_ty.abi) {
Rust | RustCall => {
get_extern_rust_fn(ccx, t, &name[..], did)
ccx.sess().bug("unexpected intrinsic in trans_external_path")
}
_ => {
- let llfn = foreign::register_foreign_item_fn(ccx, fn_ty.abi, t, &name[..]);
+ let llfn = foreign::register_foreign_item_fn(ccx, fn_ty.abi,
+ t, &name);
let attrs = csearch::get_item_attrs(&ccx.sess().cstore, did);
attributes::from_fn_attrs(ccx, &attrs, llfn);
llfn
}
pub fn need_invoke(bcx: Block) -> bool {
- if bcx.sess().no_landing_pads() {
+ // FIXME(#25869) currently unwinding is not implemented for MSVC and our
+ // normal unwinding infrastructure ends up just causing linker
+ // errors with the current LLVM implementation, so landing
+ // pads are disabled entirely for MSVC targets
+ if bcx.sess().no_landing_pads() ||
+ bcx.sess().target.target.options.is_like_msvc {
return false;
}
if !global.is_null() && llvm::LLVMIsGlobalConstant(global) == llvm::True {
let val = llvm::LLVMGetInitializer(global);
if !val.is_null() {
- return from_arg_ty(cx, val, t);
+ return to_arg_ty(cx, val, t);
}
}
}
llvm::LLVMSetAlignment(val, align);
}
- from_arg_ty(cx, val, t)
+ to_arg_ty(cx, val, t)
}
/// Helper for storing values in memory. Does the necessary conversion if the in-memory type
return;
}
- let store = Store(cx, to_arg_ty(cx, v, t), to_arg_ty_ptr(cx, dst, t));
+ let store = Store(cx, from_arg_ty(cx, v, t), to_arg_ty_ptr(cx, dst, t));
unsafe {
llvm::LLVMSetAlignment(store, type_of::align_of(cx.ccx(), t));
}
}
-pub fn to_arg_ty(bcx: Block, val: ValueRef, ty: Ty) -> ValueRef {
+pub fn from_arg_ty(bcx: Block, val: ValueRef, ty: Ty) -> ValueRef {
if ty::type_is_bool(ty) {
ZExt(bcx, val, Type::i8(bcx.ccx()))
} else {
}
}
-pub fn from_arg_ty(bcx: Block, val: ValueRef, ty: Ty) -> ValueRef {
+pub fn to_arg_ty(bcx: Block, val: ValueRef, ty: Ty) -> ValueRef {
if ty::type_is_bool(ty) {
Trunc(bcx, val, Type::i1(bcx.ccx()))
} else {
{
let _icx = push_ctxt("with_cond");
- if bcx.unreachable.get() ||
- (common::is_const(val) && common::const_to_uint(val) == 0) {
+ if bcx.unreachable.get() || common::const_to_opt_uint(val) == Some(0) {
return bcx;
}
let blk = match tcx.map.find(id) {
Some(ast_map::NodeItem(i)) => {
match i.node {
- ast::ItemFn(_, _, _, _, ref blk) => {
+ ast::ItemFn(_, _, _, _, _, ref blk) => {
blk
}
_ => tcx.sess.bug("unexpected item variant in has_nested_returns")
// return slot alloca. This can cause errors related to clean-up due to
// the clobbering of the existing value in the return slot.
fn has_nested_returns(tcx: &ty::ctxt, cfg: &cfg::CFG, blk_id: ast::NodeId) -> bool {
- for n in cfg.graph.depth_traverse(cfg.entry) {
+ for index in cfg.graph.depth_traverse(cfg.entry) {
+ let n = cfg.graph.node_data(index);
match tcx.map.find(n.id()) {
Some(ast_map::NodeExpr(ex)) => {
if let ast::ExprRet(Some(ref ret_expr)) = ex.node {
-> FunctionContext<'a, 'tcx> {
common::validate_substs(param_substs);
- debug!("new_fn_ctxt(path={}, id={}, param_substs={})",
+ debug!("new_fn_ctxt(path={}, id={}, param_substs={:?})",
if id == !0 {
"".to_string()
} else {
ccx.tcx().map.path_to_string(id).to_string()
},
- id, param_substs.repr(ccx.tcx()));
+ id, param_substs);
let uses_outptr = match output_type {
ty::FnConverging(output_type) => {
// create_datums_for_fn_args: creates rvalue datums for each of the
// incoming function arguments. These will later be stored into
// appropriate lvalue datums.
-pub fn create_datums_for_fn_args<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>,
+pub fn create_datums_for_fn_args<'a, 'tcx>(bcx: Block<'a, 'tcx>,
arg_tys: &[Ty<'tcx>])
-> Vec<RvalueDatum<'tcx>> {
let _icx = push_ctxt("create_datums_for_fn_args");
+ let fcx = bcx.fcx;
// Return an array wrapping the ValueRefs that we get from `get_param` for
// each argument into datums.
- arg_tys.iter().enumerate().map(|(i, &arg_ty)| {
- let llarg = get_param(fcx.llfn, fcx.arg_pos(i) as c_uint);
- datum::Datum::new(llarg, arg_ty, arg_kind(fcx, arg_ty))
+ let mut i = fcx.arg_offset() as c_uint;
+ arg_tys.iter().map(|&arg_ty| {
+ if common::type_is_fat_ptr(bcx.tcx(), arg_ty) {
+ let llty = type_of::type_of(bcx.ccx(), arg_ty);
+ let data = get_param(fcx.llfn, i);
+ let extra = get_param(fcx.llfn, i + 1);
+ let fat_ptr = expr::make_fat_ptr(bcx, llty, data, extra);
+ i += 2;
+ datum::Datum::new(fat_ptr, arg_ty, datum::Rvalue { mode: datum::ByValue })
+ } else {
+ let llarg = get_param(fcx.llfn, i);
+ i += 1;
+ datum::Datum::new(llarg, arg_ty, arg_kind(fcx, arg_ty))
+ }
}).collect()
}
arg_tys: &[Ty<'tcx>])
-> Vec<RvalueDatum<'tcx>> {
let mut result = Vec::new();
+ let mut idx = bcx.fcx.arg_offset() as c_uint;
for (i, &arg_ty) in arg_tys.iter().enumerate() {
if i < arg_tys.len() - 1 {
// Regular argument.
- let llarg = get_param(bcx.fcx.llfn, bcx.fcx.arg_pos(i) as c_uint);
- result.push(datum::Datum::new(llarg, arg_ty, arg_kind(bcx.fcx,
- arg_ty)));
+ result.push(if common::type_is_fat_ptr(bcx.tcx(), arg_ty) {
+ let llty = type_of::type_of(bcx.ccx(), arg_ty);
+ let data = get_param(bcx.fcx.llfn, idx);
+ let extra = get_param(bcx.fcx.llfn, idx + 1);
+ idx += 2;
+ let fat_ptr = expr::make_fat_ptr(bcx, llty, data, extra);
+ datum::Datum::new(fat_ptr, arg_ty, datum::Rvalue { mode: datum::ByValue })
+ } else {
+ let val = get_param(bcx.fcx.llfn, idx);
+ idx += 1;
+ datum::Datum::new(val, arg_ty, arg_kind(bcx.fcx, arg_ty))
+ });
+
continue
}
// This is the last argument. Tuple it.
match arg_ty.sty {
- ty::ty_tup(ref tupled_arg_tys) => {
+ ty::TyTuple(ref tupled_arg_tys) => {
let tuple_args_scope_id = cleanup::CustomScope(arg_scope);
let tuple =
unpack_datum!(bcx,
llval| {
for (j, &tupled_arg_ty) in
tupled_arg_tys.iter().enumerate() {
- let llarg =
- get_param(bcx.fcx.llfn,
- bcx.fcx.arg_pos(i + j) as c_uint);
let lldest = GEPi(bcx, llval, &[0, j]);
- let datum = datum::Datum::new(
- llarg,
- tupled_arg_ty,
- arg_kind(bcx.fcx, tupled_arg_ty));
- bcx = datum.store_to(bcx, lldest);
+ if common::type_is_fat_ptr(bcx.tcx(), tupled_arg_ty) {
+ let data = get_param(bcx.fcx.llfn, idx);
+ let extra = get_param(bcx.fcx.llfn, idx + 1);
+ Store(bcx, data, expr::get_dataptr(bcx, lldest));
+ Store(bcx, extra, expr::get_len(bcx, lldest));
+ idx += 2;
+ } else {
+ let datum = datum::Datum::new(
+ get_param(bcx.fcx.llfn, idx),
+ tupled_arg_ty,
+ arg_kind(bcx.fcx, tupled_arg_ty));
+ idx += 1;
+ bcx = datum.store_to(bcx, lldest);
+ };
}
bcx
}));
let _icx = push_ctxt("trans_closure");
attributes::emit_uwtable(llfndecl, true);
- debug!("trans_closure(..., param_substs={})",
- param_substs.repr(ccx.tcx()));
+ debug!("trans_closure(..., param_substs={:?})",
+ param_substs);
let has_env = match closure_env {
closure::ClosureEnv::Closure(_) => true,
}
};
for monomorphized_arg_type in &monomorphized_arg_types {
- debug!("trans_closure: monomorphized_arg_type: {}",
- ty_to_string(ccx.tcx(), *monomorphized_arg_type));
+ debug!("trans_closure: monomorphized_arg_type: {:?}",
+ monomorphized_arg_type);
}
debug!("trans_closure: function lltype: {}",
bcx.fcx.ccx.tn().val_to_string(bcx.fcx.llfn));
}
_ => {
let arg_tys = untuple_arguments_if_necessary(ccx, &monomorphized_arg_types, abi);
- create_datums_for_fn_args(&fcx, &arg_tys)
+ create_datums_for_fn_args(bcx, &arg_tys)
}
};
id: ast::NodeId,
attrs: &[ast::Attribute]) {
let _s = StatRecorder::new(ccx, ccx.tcx().map.path_to_string(id).to_string());
- debug!("trans_fn(param_substs={})", param_substs.repr(ccx.tcx()));
+ debug!("trans_fn(param_substs={:?})", param_substs);
let _icx = push_ctxt("trans_fn");
let fn_ty = ty::node_id_to_type(ccx.tcx(), id);
let output_type = ty::erase_late_bound_regions(ccx.tcx(), &ty::ty_fn_ret(fn_ty));
-> Result<'blk, 'tcx> {
let ccx = bcx.fcx.ccx;
- let tcx = ccx.tcx();
let result_ty = match ctor_ty.sty {
- ty::ty_bare_fn(_, ref bft) => {
+ ty::TyBareFn(_, ref bft) => {
ty::erase_late_bound_regions(bcx.tcx(), &bft.sig.output()).unwrap()
}
_ => ccx.sess().bug(
&format!("trans_enum_variant_constructor: \
unexpected ctor return type {}",
- ctor_ty.repr(tcx)))
+ ctor_ty))
};
// Get location to store the result. If the user does not care about
if !type_is_zero_size(ccx, result_ty) {
alloc_ty(bcx, result_ty, "constructor_result")
} else {
- C_undef(type_of::type_of(ccx, result_ty))
+ C_undef(type_of::type_of(ccx, result_ty).ptr_to())
}
}
};
let ctor_ty = monomorphize::apply_param_substs(ccx.tcx(), param_substs, &ctor_ty);
let result_ty = match ctor_ty.sty {
- ty::ty_bare_fn(_, ref bft) => {
+ ty::TyBareFn(_, ref bft) => {
ty::erase_late_bound_regions(ccx.tcx(), &bft.sig.output())
}
_ => ccx.sess().bug(
&format!("trans_enum_variant_or_tuple_like_struct: \
unexpected ctor return type {}",
- ty_to_string(ccx.tcx(), ctor_ty)))
+ ctor_ty))
};
let (arena, fcx): (TypedArena<_>, FunctionContext);
ty::erase_late_bound_regions(
ccx.tcx(), &ty::ty_fn_args(ctor_ty));
- let arg_datums = create_datums_for_fn_args(&fcx, &arg_tys[..]);
+ let arg_datums = create_datums_for_fn_args(bcx, &arg_tys[..]);
if !type_is_zero_size(fcx.ccx, result_ty.unwrap()) {
let dest = fcx.get_ret_slot(bcx, result_ty, "eret_slot");
match id {
Some(id) if ccx.reachable().contains(&id) => {
llvm::SetLinkage(llval, llvm::ExternalLinkage);
+ if ccx.use_dll_storage_attrs() {
+ llvm::SetDLLStorageClass(llval, llvm::DLLExportStorageClass);
+ }
},
_ => {
// `id` does not refer to an item in `ccx.reachable`.
if ccx.sess().opts.cg.codegen_units > 1 {
llvm::SetLinkage(llval, llvm::ExternalLinkage);
+ if ccx.use_dll_storage_attrs() {
+ llvm::SetDLLStorageClass(llval, llvm::DLLExportStorageClass);
+ }
} else {
llvm::SetLinkage(llval, llvm::InternalLinkage);
}
let from_external = ccx.external_srcs().borrow().contains_key(&item.id);
match item.node {
- ast::ItemFn(ref decl, _fn_style, abi, ref generics, ref body) => {
+ ast::ItemFn(ref decl, _, _, abi, ref generics, ref body) => {
if !generics.is_type_parameterized() {
let trans_everywhere = attr::requests_inline(&item.attrs);
// Ignore `trans_everywhere` for cross-crate inlined items
let g = consts::trans_static(ccx, m, item.id);
update_linkage(ccx, g, Some(item.id), OriginalTranslation);
-
- // Do static_assert checking. It can't really be done much earlier
- // because we need to get the value of the bool out of LLVM
- if attr::contains_name(&item.attrs, "static_assert") {
- if !ty::type_is_bool(ty::expr_ty(ccx.tcx(), expr)) {
- ccx.sess().span_fatal(expr.span,
- "can only have static_assert on a static \
- with type `bool`");
- }
- if m == ast::MutMutable {
- ccx.sess().span_fatal(expr.span,
- "cannot have static_assert on a mutable \
- static");
- }
-
- let v = ccx.static_values().borrow().get(&item.id).unwrap().clone();
- unsafe {
- if !(llvm::LLVMConstIntGetZExtValue(v) != 0) {
- ccx.sess().span_fatal(expr.span, "static assertion failed");
- }
- }
- }
},
ast::ItemForeignMod(ref foreign_mod) => {
foreign::trans_foreign_mod(ccx, foreign_mod);
if ccx.tcx().lang_items.stack_exhausted() == Some(def) {
attributes::split_stack(llfn, false);
llvm::SetLinkage(llfn, llvm::ExternalLinkage);
+ if ccx.use_dll_storage_attrs() {
+ llvm::SetDLLStorageClass(llfn, llvm::DLLExportStorageClass);
+ }
}
if ccx.tcx().lang_items.eh_personality() == Some(def) {
llvm::SetLinkage(llfn, llvm::ExternalLinkage);
+ if ccx.use_dll_storage_attrs() {
+ llvm::SetDLLStorageClass(llfn, llvm::DLLExportStorageClass);
+ }
}
}
node_id: ast::NodeId,
node_type: Ty<'tcx>)
-> ValueRef {
- if let ty::ty_bare_fn(_, ref f) = node_type.sty {
+ if let ty::TyBareFn(_, ref f) = node_type.sty {
if f.abi != Rust && f.abi != RustCall {
ccx.sess().span_bug(sp, &format!("only the `{}` or `{}` calling conventions are valid \
for this function; `{}` was specified",
// FIXME: #16581: Marking a symbol in the executable with `dllexport`
// linkage forces MinGW's linker to output a `.reloc` section for ASLR
if ccx.sess().target.target.options.is_like_windows {
- unsafe { llvm::LLVMRustSetDLLExportStorageClass(llfn) }
+ llvm::SetDLLStorageClass(llfn, llvm::DLLExportStorageClass);
}
let llbb = unsafe {
// We need the translated value here, because for enums the
// LLVM type is not fully determined by the Rust type.
let empty_substs = ccx.tcx().mk_substs(Substs::trans_empty());
- let (v, ty) = consts::const_expr(ccx, &**expr, empty_substs);
+ let (v, ty) = consts::const_expr(ccx, &**expr, empty_substs, None);
ccx.static_values().borrow_mut().insert(id, v);
unsafe {
// boolean SSA values are i1, but they have to be stored in i8 slots,
}
}
- ast::ItemFn(_, _, abi, _, _) => {
+ ast::ItemFn(_, _, _, abi, _, _) => {
let sym = sym();
let llfn = if abi == Rust {
register_fn(ccx, i.span, sym, i.id, ty)
let sym = exported_name(ccx, id, mty, &attrs);
- if let ty::ty_bare_fn(_, ref f) = mty.sty {
+ if let ty::TyBareFn(_, ref f) = mty.sty {
let llfn = if f.abi == Rust || f.abi == RustCall {
register_fn(ccx, span, sym, id, mty)
} else {
}
}
-pub fn crate_ctxt_to_encode_parms<'a, 'tcx>(cx: &'a SharedCrateContext<'tcx>,
+pub fn crate_ctxt_to_encode_parms<'a, 'tcx>(cx: &'a SharedCrateContext<'a, 'tcx>,
ie: encoder::EncodeInlinedItem<'a>)
-> encoder::EncodeParams<'a, 'tcx> {
encoder::EncodeParams {
};
unsafe {
llvm::LLVMSetInitializer(llglobal, llconst);
- let name = loader::meta_section_name(cx.sess().target.target.options.is_like_osx);
+ let name = loader::meta_section_name(&cx.sess().target.target);
let name = CString::new(name).unwrap();
llvm::LLVMSetSection(llglobal, name.as_ptr())
}
if !declared.contains(&name) &&
!reachable.contains(str::from_utf8(&name).unwrap()) {
llvm::SetLinkage(val, llvm::InternalLinkage);
+ llvm::SetDLLStorageClass(val, llvm::DefaultStorageClass);
}
}
}
}
}
-pub fn trans_crate<'tcx>(analysis: ty::CrateAnalysis<'tcx>)
- -> (ty::ctxt<'tcx>, CrateTranslation) {
- let ty::CrateAnalysis { ty_cx: tcx, export_map, reachable, name, .. } = analysis;
+pub fn trans_crate(tcx: &ty::ctxt, analysis: ty::CrateAnalysis) -> CrateTranslation {
+ let ty::CrateAnalysis { export_map, reachable, name, .. } = analysis;
let krate = tcx.map.krate();
let check_overflow = if let Some(v) = tcx.sess.opts.debugging_opts.force_overflow_checks {
// Before we touch LLVM, make sure that multithreading is enabled.
unsafe {
- use std::sync::{Once, ONCE_INIT};
- static INIT: Once = ONCE_INIT;
+ use std::sync::Once;
+ static INIT: Once = Once::new();
static mut POISONED: bool = false;
INIT.call_once(|| {
if llvm::LLVMStartMultithreaded() != 1 {
stats.fn_stats.borrow_mut().sort_by(|&(_, insns_a), &(_, insns_b)| {
insns_b.cmp(&insns_a)
});
- for tuple in &*stats.fn_stats.borrow() {
+ for tuple in stats.fn_stats.borrow().iter() {
match *tuple {
(ref name, insns) => {
println!("{} insns, {}", insns, *name);
}
}
if shared_ccx.sess().count_llvm_insns() {
- for (k, v) in &*shared_ccx.stats().llvm_insns.borrow() {
+ for (k, v) in shared_ccx.stats().llvm_insns.borrow().iter() {
println!("{:7} {}", *v, *k);
}
}
let formats = shared_ccx.tcx().dependency_formats.borrow().clone();
let no_builtins = attr::contains_name(&krate.attrs, "no_builtins");
- let translation = CrateTranslation {
+ CrateTranslation {
modules: modules,
metadata_module: metadata_module,
link: link_meta,
reachable: reachable,
crate_formats: formats,
no_builtins: no_builtins,
- };
-
- (shared_ccx.take_tcx(), translation)
+ }
}
B(cx).not(v)
}
-/* Memory */
-pub fn Malloc(cx: Block, ty: Type, debug_loc: DebugLoc) -> ValueRef {
- unsafe {
- if cx.unreachable.get() {
- return llvm::LLVMGetUndef(Type::i8p(cx.ccx()).to_ref());
- }
- debug_loc.apply(cx.fcx);
- B(cx).malloc(ty)
- }
-}
-
-pub fn ArrayMalloc(cx: Block,
- ty: Type,
- val: ValueRef,
- debug_loc: DebugLoc) -> ValueRef {
- unsafe {
- if cx.unreachable.get() {
- return llvm::LLVMGetUndef(Type::i8p(cx.ccx()).to_ref());
- }
- debug_loc.apply(cx.fcx);
- B(cx).array_malloc(ty, val)
- }
-}
-
pub fn Alloca(cx: Block, ty: Type, name: &str) -> ValueRef {
unsafe {
if cx.unreachable.get() { return llvm::LLVMGetUndef(ty.ptr_to().to_ref()); }
b.alloca(ty, name)
}
-pub fn ArrayAlloca(cx: Block, ty: Type, val: ValueRef) -> ValueRef {
- unsafe {
- if cx.unreachable.get() { return llvm::LLVMGetUndef(ty.ptr_to().to_ref()); }
- let b = cx.fcx.ccx.builder();
- b.position_before(cx.fcx.alloca_insert_pt.get().unwrap());
- DebugLoc::None.apply(cx.fcx);
- b.array_alloca(ty, val)
- }
-}
-
pub fn Free(cx: Block, pointer_val: ValueRef) {
if cx.unreachable.get() { return; }
B(cx).free(pointer_val)
// Pass 2: concat strings for each elt, skipping
// forwards over any cycles by advancing to rightmost
// occurrence of each element in path.
- let mut s = String::from_str(".");
+ let mut s = String::from(".");
i = 0;
while i < len {
i = mm[v[i]];
}
}
- /* Memory */
- pub fn malloc(&self, ty: Type) -> ValueRef {
- self.count_insn("malloc");
- unsafe {
- llvm::LLVMBuildMalloc(self.llbuilder, ty.to_ref(), noname())
- }
- }
-
- pub fn array_malloc(&self, ty: Type, val: ValueRef) -> ValueRef {
- self.count_insn("arraymalloc");
- unsafe {
- llvm::LLVMBuildArrayMalloc(self.llbuilder, ty.to_ref(), val, noname())
- }
- }
-
pub fn alloca(&self, ty: Type, name: &str) -> ValueRef {
self.count_insn("alloca");
unsafe {
}
}
- pub fn array_alloca(&self, ty: Type, val: ValueRef) -> ValueRef {
- self.count_insn("arrayalloca");
- unsafe {
- llvm::LLVMBuildArrayAlloca(self.llbuilder, ty.to_ref(), val, noname())
- }
- }
-
pub fn free(&self, ptr: ValueRef) {
self.count_insn("free");
unsafe {
// we care about.
if ixs.len() < 16 {
let mut small_vec = [ C_i32(self.ccx, 0); 16 ];
- for (small_vec_e, &ix) in small_vec.iter_mut().zip(ixs.iter()) {
+ for (small_vec_e, &ix) in small_vec.iter_mut().zip(ixs) {
*small_vec_e = C_i32(self.ccx, ix as i32);
}
self.inbounds_gep(base, &small_vec[..ixs.len()])
use arena::TypedArena;
use back::link;
use session;
-use llvm::ValueRef;
-use llvm::get_param;
-use llvm;
+use llvm::{self, ValueRef, get_params};
use metadata::csearch;
use middle::def;
use middle::subst;
use trans::type_of;
use middle::ty::{self, Ty};
use middle::ty::MethodCall;
-use util::ppaux::Repr;
-use util::ppaux::ty_to_string;
+use rustc::ast_map;
use syntax::abi as synabi;
use syntax::ast;
-use syntax::ast_map;
use syntax::ptr::P;
#[derive(Copy, Clone)]
fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr)
-> Callee<'blk, 'tcx> {
let _icx = push_ctxt("trans_callee");
- debug!("callee::trans(expr={})", expr.repr(bcx.tcx()));
+ debug!("callee::trans(expr={:?})", expr);
// pick out special kinds of expressions that can be called:
match expr.node {
-> Callee<'blk, 'tcx> {
let DatumBlock { bcx, datum, .. } = expr::trans(bcx, expr);
match datum.ty.sty {
- ty::ty_bare_fn(..) => {
+ ty::TyBareFn(..) => {
let llval = datum.to_llscalarish(bcx);
return Callee {
bcx: bcx,
_ => {
bcx.tcx().sess.span_bug(
expr.span,
- &format!("type of callee is neither bare-fn nor closure: \
- {}",
- bcx.ty_to_string(datum.ty)));
+ &format!("type of callee is neither bare-fn nor closure: {}",
+ datum.ty));
}
}
}
def: def::Def,
ref_expr: &ast::Expr)
-> Callee<'blk, 'tcx> {
- debug!("trans_def(def={}, ref_expr={})", def.repr(bcx.tcx()), ref_expr.repr(bcx.tcx()));
+ debug!("trans_def(def={:?}, ref_expr={:?})", def, ref_expr);
let expr_ty = common::node_id_type(bcx, ref_expr.id);
match def {
def::DefFn(did, _) if {
}
}
def::DefFn(did, _) if match expr_ty.sty {
- ty::ty_bare_fn(_, ref f) => f.abi == synabi::RustIntrinsic,
+ ty::TyBareFn(_, ref f) => f.abi == synabi::RustIntrinsic,
_ => false
} => {
let substs = common::node_id_substs(bcx.ccx(),
let _icx = push_ctxt("trans_fn_ref");
let substs = common::node_id_substs(ccx, node, param_substs);
- debug!("trans_fn_ref(def_id={}, node={:?}, substs={})",
- def_id.repr(ccx.tcx()),
+ debug!("trans_fn_ref(def_id={:?}, node={:?}, substs={:?})",
+ def_id,
node,
- substs.repr(ccx.tcx()));
+ substs);
trans_fn_ref_with_substs(ccx, def_id, node, param_substs, substs)
}
None => { }
}
- debug!("trans_fn_pointer_shim(bare_fn_ty={})",
- bare_fn_ty.repr(tcx));
+ debug!("trans_fn_pointer_shim(bare_fn_ty={:?})",
+ bare_fn_ty);
// Construct the "tuply" version of `bare_fn_ty`. It takes two arguments: `self`,
// which is the fn pointer, and `args`, which is the arguments tuple.
let (opt_def_id, sig) =
match bare_fn_ty.sty {
- ty::ty_bare_fn(opt_def_id,
+ ty::TyBareFn(opt_def_id,
&ty::BareFnTy { unsafety: ast::Unsafety::Normal,
abi: synabi::Rust,
ref sig }) => {
_ => {
tcx.sess.bug(&format!("trans_fn_pointer_shim invoked on invalid type: {}",
- bare_fn_ty.repr(tcx)));
+ bare_fn_ty));
}
};
let sig = ty::erase_late_bound_regions(tcx, sig);
output: sig.output,
variadic: false
})}));
- debug!("tuple_fn_ty: {}", tuple_fn_ty.repr(tcx));
+ debug!("tuple_fn_ty: {:?}", tuple_fn_ty);
//
let function_name = link::mangle_internal_name_by_type_and_seq(ccx, bare_fn_ty,
&block_arena);
let mut bcx = init_function(&fcx, false, sig.output);
+ let llargs = get_params(fcx.llfn);
+
+ let self_idx = fcx.arg_offset();
// the first argument (`self`) will be ptr to the the fn pointer
let llfnpointer = if is_by_ref {
- Load(bcx, get_param(fcx.llfn, fcx.arg_pos(0) as u32))
+ Load(bcx, llargs[self_idx])
} else {
- get_param(fcx.llfn, fcx.arg_pos(0) as u32)
+ llargs[self_idx]
};
- // the remaining arguments will be the untupled values
- let llargs: Vec<_> =
- sig.inputs.iter()
- .enumerate()
- .map(|(i, _)| get_param(fcx.llfn, fcx.arg_pos(i+1) as u32))
- .collect();
assert!(!fcx.needs_ret_allocas);
let dest = fcx.llretslotptr.get().map(|_|
DebugLoc::None,
bare_fn_ty,
|bcx, _| Callee { bcx: bcx, data: Fn(llfnpointer) },
- ArgVals(&llargs[..]),
+ ArgVals(&llargs[(self_idx + 1)..]),
dest).bcx;
finish_fn(&fcx, bcx, sig.output, DebugLoc::None);
let _icx = push_ctxt("trans_fn_ref_with_substs");
let tcx = ccx.tcx();
- debug!("trans_fn_ref_with_substs(def_id={}, node={:?}, \
- param_substs={}, substs={})",
- def_id.repr(tcx),
+ debug!("trans_fn_ref_with_substs(def_id={:?}, node={:?}, \
+ param_substs={:?}, substs={:?})",
+ def_id,
node,
- param_substs.repr(tcx),
- substs.repr(tcx));
+ param_substs,
+ substs);
assert!(substs.types.all(|t| !ty::type_needs_infer(*t)));
assert!(substs.types.all(|t| !ty::type_has_escaping_regions(*t)));
let new_substs = tcx.mk_substs(first_subst.subst(tcx, &substs));
debug!("trans_fn_with_vtables - default method: \
- substs = {}, trait_subst = {}, \
- first_subst = {}, new_subst = {}",
- substs.repr(tcx), trait_ref.substs.repr(tcx),
- first_subst.repr(tcx), new_substs.repr(tcx));
+ substs = {:?}, trait_subst = {:?}, \
+ first_subst = {:?}, new_subst = {:?}",
+ substs, trait_ref.substs,
+ first_subst, new_substs);
(true, source_id, new_substs)
}
false
};
+ debug!("trans_fn_ref_with_substs({:?}) must_monomorphise: {}",
+ def_id, must_monomorphise);
+
// Create a monomorphic version of generic functions
if must_monomorphise {
// Should be either intra-crate or inlined.
dest: expr::Dest)
-> Block<'blk, 'tcx> {
let _icx = push_ctxt("trans_method_call");
- debug!("trans_method_call(call_expr={})", call_expr.repr(bcx.tcx()));
+ debug!("trans_method_call(call_expr={:?})", call_expr);
let method_call = MethodCall::expr(call_expr.id);
let method_ty = match bcx.tcx().method_map.borrow().get(&method_call) {
Some(method) => match method.origin {
ty::MethodTraitObject(_) => match method.ty.sty {
- ty::ty_bare_fn(_, ref fty) => {
+ ty::TyBareFn(_, ref fty) => {
ty::mk_bare_fn(bcx.tcx(), None, meth::opaque_method_ty(bcx.tcx(), fty))
}
_ => method.ty
let mut bcx = callee.bcx;
let (abi, ret_ty) = match callee_ty.sty {
- ty::ty_bare_fn(_, ref f) => {
+ ty::TyBareFn(_, ref f) => {
let output = ty::erase_late_bound_regions(bcx.tcx(), &f.sig.output());
(f.abi, output)
}
let mut llargs = Vec::new();
let arg_tys = match args {
- ArgExprs(a) => a.iter().map(|x| common::expr_ty(bcx, &**x)).collect(),
+ ArgExprs(a) => a.iter().map(|x| common::expr_ty_adjusted(bcx, &**x)).collect(),
_ => panic!("expected arg exprs.")
};
bcx = trans_args(bcx,
// Translate the `self` argument first.
if !ignore_self {
let arg_datum = unpack_datum!(bcx, expr::trans(bcx, &*arg_exprs[0]));
- llargs.push(unpack_result!(bcx, {
- trans_arg_datum(bcx,
- args[0],
- arg_datum,
- arg_cleanup_scope,
- DontAutorefArg)
- }))
+ bcx = trans_arg_datum(bcx,
+ args[0],
+ arg_datum,
+ arg_cleanup_scope,
+ DontAutorefArg,
+ llargs);
}
// Now untuple the rest of the arguments.
let tuple_type = common::node_id_type(bcx, tuple_expr.id);
match tuple_type.sty {
- ty::ty_tup(ref field_types) => {
+ ty::TyTuple(ref field_types) => {
let tuple_datum = unpack_datum!(bcx,
expr::trans(bcx, &**tuple_expr));
let tuple_lvalue_datum =
tuple_expr.id));
let repr = adt::represent_type(bcx.ccx(), tuple_type);
let repr_ptr = &*repr;
- llargs.extend(field_types.iter().enumerate().map(|(i, field_type)| {
+ for (i, field_type) in field_types.iter().enumerate() {
let arg_datum = tuple_lvalue_datum.get_element(
bcx,
field_type,
|srcval| {
adt::trans_field_ptr(bcx, repr_ptr, srcval, 0, i)
}).to_expr_datum();
- unpack_result!(bcx, trans_arg_datum(
- bcx,
- field_type,
- arg_datum,
- arg_cleanup_scope,
- DontAutorefArg)
- )
- }));
+ bcx = trans_arg_datum(bcx,
+ field_type,
+ arg_datum,
+ arg_cleanup_scope,
+ DontAutorefArg,
+ llargs);
+ }
}
_ => {
bcx.sess().span_bug(tuple_expr.span,
let arg_tys = ty::erase_late_bound_regions(bcx.tcx(), &ty::ty_fn_args(fn_ty));
if !ignore_self {
let arg_datum = unpack_datum!(bcx, expr::trans(bcx, arg_exprs[0]));
- llargs.push(unpack_result!(bcx, {
- trans_arg_datum(bcx,
- arg_tys[0],
- arg_datum,
- arg_cleanup_scope,
- DontAutorefArg)
- }))
+ bcx = trans_arg_datum(bcx,
+ arg_tys[0],
+ arg_datum,
+ arg_cleanup_scope,
+ DontAutorefArg,
+ llargs);
}
// Now untuple the rest of the arguments.
let tuple_type = arg_tys[1];
match tuple_type.sty {
- ty::ty_tup(ref field_types) => {
+ ty::TyTuple(ref field_types) => {
for (i, &field_type) in field_types.iter().enumerate() {
let arg_datum =
unpack_datum!(bcx, expr::trans(bcx, arg_exprs[i + 1]));
- llargs.push(unpack_result!(bcx, {
- trans_arg_datum(bcx,
- field_type,
- arg_datum,
- arg_cleanup_scope,
- DontAutorefArg)
- }))
+ bcx = trans_arg_datum(bcx,
+ field_type,
+ arg_datum,
+ arg_cleanup_scope,
+ DontAutorefArg,
+ llargs);
}
}
_ => {
};
let arg_datum = unpack_datum!(bcx, expr::trans(bcx, &**arg_expr));
- llargs.push(unpack_result!(bcx, {
- trans_arg_datum(bcx, arg_ty, arg_datum,
- arg_cleanup_scope,
- DontAutorefArg)
- }));
+ bcx = trans_arg_datum(bcx, arg_ty, arg_datum,
+ arg_cleanup_scope,
+ DontAutorefArg,
+ llargs);
}
}
ArgOverloadedCall(arg_exprs) => {
ArgOverloadedOp(lhs, rhs, autoref) => {
assert!(!variadic);
- llargs.push(unpack_result!(bcx, {
- trans_arg_datum(bcx, arg_tys[0], lhs,
- arg_cleanup_scope,
- DontAutorefArg)
- }));
+ bcx = trans_arg_datum(bcx, arg_tys[0], lhs,
+ arg_cleanup_scope,
+ DontAutorefArg,
+ llargs);
assert_eq!(arg_tys.len(), 1 + rhs.len());
for (rhs, rhs_id) in rhs {
- llargs.push(unpack_result!(bcx, {
- trans_arg_datum(bcx, arg_tys[1], rhs,
- arg_cleanup_scope,
- if autoref { DoAutorefArg(rhs_id) } else { DontAutorefArg })
- }));
+ bcx = trans_arg_datum(bcx, arg_tys[1], rhs,
+ arg_cleanup_scope,
+ if autoref { DoAutorefArg(rhs_id) } else { DontAutorefArg },
+ llargs);
}
}
ArgVals(vs) => {
formal_arg_ty: Ty<'tcx>,
arg_datum: Datum<'tcx, Expr>,
arg_cleanup_scope: cleanup::ScopeId,
- autoref_arg: AutorefArg)
- -> Result<'blk, 'tcx> {
+ autoref_arg: AutorefArg,
+ llargs: &mut Vec<ValueRef>)
+ -> Block<'blk, 'tcx> {
let _icx = push_ctxt("trans_arg_datum");
let mut bcx = bcx;
let ccx = bcx.ccx();
- debug!("trans_arg_datum({})",
- formal_arg_ty.repr(bcx.tcx()));
+ debug!("trans_arg_datum({:?})",
+ formal_arg_ty);
let arg_datum_ty = arg_datum.ty;
bcx, arg_datum.to_lvalue_datum(bcx, "arg", arg_id));
val = arg_datum.val;
}
+ DontAutorefArg if common::type_is_fat_ptr(bcx.tcx(), arg_datum_ty) &&
+ !bcx.fcx.type_needs_drop(arg_datum_ty) => {
+ val = arg_datum.val
+ }
DontAutorefArg => {
// Make this an rvalue, since we are going to be
// passing ownership.
}
}
- if formal_arg_ty != arg_datum_ty {
+ if type_of::arg_is_indirect(ccx, formal_arg_ty) && formal_arg_ty != arg_datum_ty {
// this could happen due to e.g. subtyping
let llformal_arg_ty = type_of::type_of_explicit_arg(ccx, formal_arg_ty);
debug!("casting actual type ({}) to match formal ({})",
bcx.val_to_string(val), bcx.llty_str(llformal_arg_ty));
- debug!("Rust types: {}; {}", ty_to_string(bcx.tcx(), arg_datum_ty),
- ty_to_string(bcx.tcx(), formal_arg_ty));
+ debug!("Rust types: {:?}; {:?}", arg_datum_ty,
+ formal_arg_ty);
val = PointerCast(bcx, val, llformal_arg_ty);
}
debug!("--- trans_arg_datum passing {}", bcx.val_to_string(val));
- Result::new(bcx, val)
+
+ if common::type_is_fat_ptr(bcx.tcx(), formal_arg_ty) {
+ llargs.push(Load(bcx, expr::get_dataptr(bcx, val)));
+ llargs.push(Load(bcx, expr::get_len(bcx, val)));
+ } else {
+ llargs.push(val);
+ }
+
+ bcx
}
use middle::ty::{self, Ty};
use std::fmt;
use syntax::ast;
-use util::ppaux::Repr;
pub struct CleanupScope<'blk, 'tcx: 'blk> {
// The id of this cleanup scope. If the id is None,
skip_dtor: false,
};
- debug!("schedule_drop_mem({:?}, val={}, ty={}) fill_on_drop={} skip_dtor={}",
+ debug!("schedule_drop_mem({:?}, val={}, ty={:?}) fill_on_drop={} skip_dtor={}",
cleanup_scope,
self.ccx.tn().val_to_string(val),
- ty.repr(self.ccx.tcx()),
+ ty,
drop.fill_on_drop,
drop.skip_dtor);
skip_dtor: false,
};
- debug!("schedule_drop_and_fill_mem({:?}, val={}, ty={}, fill_on_drop={}, skip_dtor={})",
+ debug!("schedule_drop_and_fill_mem({:?}, val={}, ty={:?}, fill_on_drop={}, skip_dtor={})",
cleanup_scope,
self.ccx.tn().val_to_string(val),
- ty.repr(self.ccx.tcx()),
+ ty,
drop.fill_on_drop,
drop.skip_dtor);
skip_dtor: true,
};
- debug!("schedule_drop_adt_contents({:?}, val={}, ty={}) fill_on_drop={} skip_dtor={}",
+ debug!("schedule_drop_adt_contents({:?}, val={}, ty={:?}) fill_on_drop={} skip_dtor={}",
cleanup_scope,
self.ccx.tn().val_to_string(val),
- ty.repr(self.ccx.tcx()),
+ ty,
drop.fill_on_drop,
drop.skip_dtor);
debug!("schedule_drop_immediate({:?}, val={}, ty={:?}) fill_on_drop={} skip_dtor={}",
cleanup_scope,
self.ccx.tn().val_to_string(val),
- ty.repr(self.ccx.tcx()),
+ ty,
drop.fill_on_drop,
drop.skip_dtor);
use arena::TypedArena;
use back::link::{self, mangle_internal_name_by_path_and_seq};
-use llvm::{ValueRef, get_param};
+use llvm::{ValueRef, get_params};
use middle::mem_categorization::Typer;
use trans::adt;
use trans::attributes;
use middle::ty::{self, ClosureTyper};
use middle::subst::Substs;
use session::config::FullDebugInfo;
-use util::ppaux::Repr;
use syntax::abi::RustCall;
use syntax::ast;
// duplicate declarations
let function_type = erase_regions(ccx.tcx(), &function_type);
let params = match function_type.sty {
- ty::ty_closure(_, substs) => &substs.types,
+ ty::TyClosure(_, substs) => &substs.types,
_ => unreachable!()
};
let mono_id = MonoId {
match ccx.closure_vals().borrow().get(&mono_id) {
Some(&llfn) => {
- debug!("get_or_create_declaration_if_closure(): found closure");
+ debug!("get_or_create_declaration_if_closure(): found closure {:?}: {:?}",
+ mono_id, ccx.tn().val_to_string(llfn));
return Some(Datum::new(llfn, function_type, Rvalue::new(ByValue)))
}
None => {}
attributes::inline(llfn, attributes::InlineAttr::Hint);
debug!("get_or_create_declaration_if_closure(): inserting new \
- closure {:?} (type {})",
+ closure {:?} (type {}): {:?}",
mono_id,
- ccx.tn().type_to_string(val_ty(llfn)));
+ ccx.tn().type_to_string(val_ty(llfn)),
+ ccx.tn().val_to_string(llfn));
ccx.closure_vals().borrow_mut().insert(mono_id, llfn);
Some(Datum::new(llfn, function_type, Rvalue::new(ByValue)))
Dest::Ignore(ccx) => ccx
};
let tcx = ccx.tcx();
- let _icx = push_ctxt("closure::trans_closure");
+ let _icx = push_ctxt("closure::trans_closure_expr");
- debug!("trans_closure()");
+ debug!("trans_closure_expr()");
let closure_id = ast_util::local_def(id);
let llfn = get_or_create_declaration_if_closure(
&[],
sig.output,
function_type.abi,
- ClosureEnv::Closure(&freevars[..]));
+ ClosureEnv::Closure(&freevars));
// Don't hoist this to the top of the function. It's perfectly legitimate
// to have a zero-size closure (in which case dest will be `Ignore`) and
let (mut bcx, dest_addr) = match dest {
Dest::SaveIn(bcx, p) => (bcx, p),
Dest::Ignore(_) => {
- debug!("trans_closure() ignoring result");
+ debug!("trans_closure_expr() ignoring result");
return None;
}
};
llreffn: ValueRef)
-> ValueRef
{
- debug!("trans_fn_once_adapter_shim(closure_def_id={}, substs={}, llreffn={})",
- closure_def_id.repr(ccx.tcx()),
- substs.repr(ccx.tcx()),
+ debug!("trans_fn_once_adapter_shim(closure_def_id={:?}, substs={:?}, llreffn={})",
+ closure_def_id,
+ substs,
ccx.tn().val_to_string(llreffn));
let tcx = ccx.tcx();
abi: abi,
sig: sig.clone() });
let llref_fn_ty = ty::mk_bare_fn(tcx, None, llref_bare_fn_ty);
- debug!("trans_fn_once_adapter_shim: llref_fn_ty={}",
- llref_fn_ty.repr(tcx));
+ debug!("trans_fn_once_adapter_shim: llref_fn_ty={:?}",
+ llref_fn_ty);
// Make a version of the closure type with the same arguments, but
// with argument #0 being by value.
&block_arena);
let mut bcx = init_function(&fcx, false, sig.output);
+ let llargs = get_params(fcx.llfn);
+
// the first argument (`self`) will be the (by value) closure env.
let self_scope = fcx.push_custom_cleanup_scope();
let self_scope_id = CustomScope(self_scope);
let rvalue_mode = datum::appropriate_rvalue_mode(ccx, closure_ty);
- let llself = get_param(lloncefn, fcx.arg_pos(0) as u32);
+ let self_idx = fcx.arg_offset();
+ let llself = llargs[self_idx];
let env_datum = Datum::new(llself, closure_ty, Rvalue::new(rvalue_mode));
let env_datum = unpack_datum!(bcx,
env_datum.to_lvalue_datum_in_scope(bcx, "self",
debug!("trans_fn_once_adapter_shim: env_datum={}",
bcx.val_to_string(env_datum.val));
- // the remaining arguments will be packed up in a tuple.
- let input_tys = match sig.inputs[1].sty {
- ty::ty_tup(ref tys) => &**tys,
- _ => bcx.sess().bug(&format!("trans_fn_once_adapter_shim: not rust-call! \
- closure_def_id={}",
- closure_def_id.repr(tcx)))
- };
- let llargs: Vec<_> =
- input_tys.iter()
- .enumerate()
- .map(|(i, _)| get_param(lloncefn, fcx.arg_pos(i+1) as u32))
- .collect();
-
let dest =
fcx.llretslotptr.get().map(
|_| expr::SaveIn(fcx.get_ret_slot(bcx, sig.output, "ret_slot")));
DebugLoc::None,
llref_fn_ty,
|bcx, _| Callee { bcx: bcx, data: callee_data },
- ArgVals(&llargs),
+ ArgVals(&llargs[(self_idx + 1)..]),
dest).bcx;
fcx.pop_custom_cleanup_scope(self_scope);
use middle::ty::{self, HasProjectionTypes, Ty};
use middle::ty_fold;
use middle::ty_fold::{TypeFolder, TypeFoldable};
-use util::ppaux::Repr;
+use rustc::ast_map::{PathElem, PathName};
use util::nodemap::{FnvHashMap, NodeMap};
use arena::TypedArena;
use std::result::Result as StdResult;
use std::vec::Vec;
use syntax::ast;
-use syntax::ast_map::{PathElem, PathName};
use syntax::codemap::{DUMMY_SP, Span};
use syntax::parse::token::InternedString;
use syntax::parse::token;
/// subtyping, but they are anonymized and normalized as well). This
/// is a stronger, caching version of `ty_fold::erase_regions`.
pub fn erase_regions<'tcx,T>(cx: &ty::ctxt<'tcx>, value: &T) -> T
- where T : TypeFoldable<'tcx> + Repr<'tcx>
+ where T : TypeFoldable<'tcx>
{
let value1 = value.fold_with(&mut RegionEraser(cx));
- debug!("erase_regions({}) = {}",
- value.repr(cx), value1.repr(cx));
+ debug!("erase_regions({:?}) = {:?}",
+ value, value1);
return value1;
struct RegionEraser<'a, 'tcx: 'a>(&'a ty::ctxt<'tcx>);
return t_norm;
}
+ fn fold_existential_bounds(&mut self, s: &ty::ExistentialBounds<'tcx>)
+ -> ty::ExistentialBounds<'tcx> {
+ let mut s = ty_fold::super_fold_existential_bounds(self, s);
+
+ // this annoying flag messes up trans normalization
+ s.region_bound_will_change = false;
+
+ s
+ }
+
fn fold_binder<T>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T>
- where T : TypeFoldable<'tcx> + Repr<'tcx>
+ where T : TypeFoldable<'tcx>
{
let u = ty::anonymize_late_bound_regions(self.tcx(), t);
ty_fold::super_fold_binder(self, &u)
}
}
-// Is the type's representation size known at compile time?
+/// Is the type's representation size known at compile time?
pub fn type_is_sized<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
- let param_env = ty::empty_parameter_environment(tcx);
- // FIXME(#4287) This can cause errors due to polymorphic recursion,
- // a better span should be provided, if available.
- let err_count = tcx.sess.err_count();
- let is_sized = ty::type_is_sized(¶m_env, DUMMY_SP, ty);
- // Those errors aren't fatal, but an incorrect result can later
- // trip over asserts in both rustc's trans and LLVM.
- if err_count < tcx.sess.err_count() {
- tcx.sess.abort_if_errors();
- }
- is_sized
+ ty::type_is_sized(None, tcx, DUMMY_SP, ty)
}
pub fn type_is_fat_ptr<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
match ty.sty {
- ty::ty_ptr(ty::mt{ty, ..}) |
- ty::ty_rptr(_, ty::mt{ty, ..}) |
- ty::ty_uniq(ty) => {
+ ty::TyRawPtr(ty::mt{ty, ..}) |
+ ty::TyRef(_, ty::mt{ty, ..}) |
+ ty::TyBox(ty) => {
!type_is_sized(cx, ty)
}
_ => {
let mut needs_unwind_cleanup = false;
ty::maybe_walk_ty(ty, |ty| {
needs_unwind_cleanup |= match ty.sty {
- ty::ty_bool | ty::ty_int(_) | ty::ty_uint(_) |
- ty::ty_float(_) | ty::ty_tup(_) | ty::ty_ptr(_) => false,
+ ty::TyBool | ty::TyInt(_) | ty::TyUint(_) |
+ ty::TyFloat(_) | ty::TyTuple(_) | ty::TyRawPtr(_) => false,
- ty::ty_enum(did, substs) =>
+ ty::TyEnum(did, substs) =>
ty::enum_variants(tcx, did).iter().any(|v|
v.args.iter().any(|&aty| {
let t = aty.subst(tcx, substs);
// destructor (e.g. zero its memory on move).
let contents = ty::type_contents(cx, ty);
- debug!("type_needs_drop ty={} contents={:?}", ty.repr(cx), contents);
+ debug!("type_needs_drop ty={:?} contents={:?}", ty, contents);
contents.needs_drop(cx)
}
fn type_is_newtype_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool {
match ty.sty {
- ty::ty_struct(def_id, substs) => {
+ ty::TyStruct(def_id, substs) => {
let fields = ty::lookup_struct_fields(ccx.tcx(), def_id);
fields.len() == 1 && {
let ty = ty::lookup_field_type(ccx.tcx(), def_id, fields[0].id, substs);
return false;
}
match ty.sty {
- ty::ty_struct(..) | ty::ty_enum(..) | ty::ty_tup(..) | ty::ty_vec(_, Some(_)) |
- ty::ty_closure(..) => {
+ ty::TyStruct(..) | ty::TyEnum(..) | ty::TyTuple(..) | ty::TyArray(_, _) |
+ ty::TyClosure(..) => {
let llty = sizing_type_of(ccx, ty);
llsize_of_alloc(ccx, llty) <= llsize_of_alloc(ccx, ccx.int_type())
}
}
impl<'a, 'tcx> FunctionContext<'a, 'tcx> {
- pub fn arg_pos(&self, arg: usize) -> usize {
- let arg = self.env_arg_pos() + arg;
- if self.llenv.is_some() {
- arg + 1
- } else {
- arg
- }
+ pub fn arg_offset(&self) -> usize {
+ self.env_arg_pos() + if self.llenv.is_some() { 1 } else { 0 }
}
pub fn env_arg_pos(&self) -> usize {
}
pub fn monomorphize<T>(&self, value: &T) -> T
- where T : TypeFoldable<'tcx> + Repr<'tcx> + HasProjectionTypes + Clone
+ where T : TypeFoldable<'tcx> + HasProjectionTypes
{
monomorphize::apply_param_substs(self.ccx.tcx(),
self.param_substs,
self.tcx().map.node_to_string(id).to_string()
}
- pub fn expr_to_string(&self, e: &ast::Expr) -> String {
- e.repr(self.tcx())
- }
-
pub fn def(&self, nid: ast::NodeId) -> def::Def {
match self.tcx().def_map.borrow().get(&nid) {
Some(v) => v.full_def(),
self.ccx().tn().type_to_string(ty)
}
- pub fn ty_to_string(&self, t: Ty<'tcx>) -> String {
- t.repr(self.tcx())
- }
-
pub fn to_str(&self) -> String {
format!("[block {:p}]", self)
}
pub fn monomorphize<T>(&self, value: &T) -> T
- where T : TypeFoldable<'tcx> + Repr<'tcx> + HasProjectionTypes + Clone
+ where T : TypeFoldable<'tcx> + HasProjectionTypes
{
monomorphize::apply_param_substs(self.tcx(),
self.fcx.param_substs,
}
}
-pub fn is_const(v: ValueRef) -> bool {
- unsafe {
- llvm::LLVMIsConstant(v) == True
- }
-}
-
pub fn const_to_int(v: ValueRef) -> i64 {
unsafe {
llvm::LLVMConstIntGetSExtValue(v)
// First check the cache.
match ccx.trait_cache().borrow().get(&trait_ref) {
Some(vtable) => {
- info!("Cache hit: {}", trait_ref.repr(ccx.tcx()));
+ info!("Cache hit: {:?}", trait_ref);
return (*vtable).clone();
}
None => { }
}
- debug!("trans fulfill_obligation: trait_ref={}", trait_ref.repr(ccx.tcx()));
+ debug!("trans fulfill_obligation: trait_ref={:?} def_id={:?}",
+ trait_ref, trait_ref.def_id());
ty::populate_implementations_for_trait_if_necessary(tcx, trait_ref.def_id());
let infcx = infer::new_infer_ctxt(tcx);
// leading to an ambiguous result. So report this as an
// overflow bug, since I believe this is the only case
// where ambiguity can result.
- debug!("Encountered ambiguity selecting `{}` during trans, \
+ debug!("Encountered ambiguity selecting `{:?}` during trans, \
presuming due to overflow",
- trait_ref.repr(tcx));
+ trait_ref);
ccx.sess().span_fatal(
span,
"reached the recursion limit during monomorphization");
Err(e) => {
tcx.sess.span_bug(
span,
- &format!("Encountered error `{}` selecting `{}` during trans",
- e.repr(tcx),
- trait_ref.repr(tcx)))
+ &format!("Encountered error `{:?}` selecting `{:?}` during trans",
+ e,
+ trait_ref))
}
};
// Currently, we use a fulfillment context to completely resolve
// all nested obligations. This is because they can inform the
// inference of the impl's type parameters.
- let mut fulfill_cx = traits::FulfillmentContext::new();
- let vtable = selection.map_move_nested(|predicate| {
+ let mut fulfill_cx = traits::FulfillmentContext::new(true);
+ let vtable = selection.map(|predicate| {
fulfill_cx.register_predicate_obligation(&infcx, predicate);
});
let vtable = drain_fulfillment_cx_or_panic(span, &infcx, &mut fulfill_cx, &vtable);
- info!("Cache miss: {}", trait_ref.repr(ccx.tcx()));
+ info!("Cache miss: {:?}", trait_ref);
ccx.trait_cache().borrow_mut().insert(trait_ref,
vtable.clone());
predicates: Vec<ty::Predicate<'tcx>>)
-> bool
{
- debug!("normalize_and_test_predicates(predicates={})",
- predicates.repr(ccx.tcx()));
+ debug!("normalize_and_test_predicates(predicates={:?})",
+ predicates);
let tcx = ccx.tcx();
let infcx = infer::new_infer_ctxt(tcx);
let typer = NormalizingClosureTyper::new(tcx);
let mut selcx = traits::SelectionContext::new(&infcx, &typer);
- let mut fulfill_cx = traits::FulfillmentContext::new();
+ let mut fulfill_cx = traits::FulfillmentContext::new(false);
let cause = traits::ObligationCause::dummy();
let traits::Normalized { value: predicates, obligations } =
traits::normalize(&mut selcx, cause.clone(), &predicates);
fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
result: &T)
-> T
- where T : TypeFoldable<'tcx> + Repr<'tcx>
+ where T : TypeFoldable<'tcx>
{
match drain_fulfillment_cx(infcx, fulfill_cx, result) {
Ok(v) => v,
Err(errors) => {
infcx.tcx.sess.span_bug(
span,
- &format!("Encountered errors `{}` fulfilling during trans",
- errors.repr(infcx.tcx)));
+ &format!("Encountered errors `{:?}` fulfilling during trans",
+ errors));
}
}
}
fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
result: &T)
-> StdResult<T,Vec<traits::FulfillmentError<'tcx>>>
- where T : TypeFoldable<'tcx> + Repr<'tcx>
+ where T : TypeFoldable<'tcx>
{
- debug!("drain_fulfillment_cx(result={})",
- result.repr(infcx.tcx));
+ debug!("drain_fulfillment_cx(result={:?})",
+ result);
// In principle, we only need to do this so long as `result`
// contains unbound type parameters. It could be a slight
if substs.types.any(|t| ty::type_needs_infer(*t)) {
tcx.sess.bug(&format!("type parameters for node {:?} include inference types: {:?}",
- node, substs.repr(tcx)));
+ node, substs));
}
monomorphize::apply_param_substs(tcx,
use llvm;
use llvm::{ConstFCmp, ConstICmp, SetLinkage, SetUnnamedAddr};
use llvm::{InternalLinkage, ValueRef, Bool, True};
-use middle::{check_const, const_eval, def};
+use middle::{check_const, def};
+use middle::const_eval::{self, ConstVal};
use middle::const_eval::{const_int_checked_neg, const_uint_checked_neg};
use middle::const_eval::{const_int_checked_add, const_uint_checked_add};
use middle::const_eval::{const_int_checked_sub, const_uint_checked_sub};
use trans::monomorphize;
use trans::type_::Type;
use trans::type_of;
+use middle::cast::{CastTy,IntTy};
use middle::subst::Substs;
use middle::ty::{self, Ty};
-use util::ppaux::{Repr, ty_to_string};
+use util::nodemap::NodeMap;
use std::iter::repeat;
use libc::c_uint;
use syntax::parse::token;
use syntax::ptr::P;
+pub type FnArgMap<'a> = Option<&'a NodeMap<ValueRef>>;
+
pub fn const_lit(cx: &CrateContext, e: &ast::Expr, lit: &ast::Lit)
-> ValueRef {
let _icx = push_ctxt("trans_lit");
ast::LitInt(i, ast::UnsuffixedIntLit(_)) => {
let lit_int_ty = ty::node_id_to_type(cx.tcx(), e.id);
match lit_int_ty.sty {
- ty::ty_int(t) => {
+ ty::TyInt(t) => {
C_integral(Type::int_from_ty(cx, t), i as u64, true)
}
- ty::ty_uint(t) => {
+ ty::TyUint(t) => {
C_integral(Type::uint_from_ty(cx, t), i as u64, false)
}
_ => cx.sess().span_bug(lit.span,
- &format!("integer literal has type {} (expected int \
+ &format!("integer literal has type {:?} (expected int \
or usize)",
- ty_to_string(cx.tcx(), lit_int_ty)))
+ lit_int_ty))
}
}
ast::LitFloat(ref fs, t) => {
ast::LitFloatUnsuffixed(ref fs) => {
let lit_float_ty = ty::node_id_to_type(cx.tcx(), e.id);
match lit_float_ty.sty {
- ty::ty_float(t) => {
+ ty::TyFloat(t) => {
C_floating(&fs, Type::float_from_ty(cx, t))
}
_ => {
}
}
None => {
- cx.sess().bug(&format!("unexpected dereferenceable type {}",
- ty_to_string(cx.tcx(), ty)))
+ cx.sess().bug(&format!("unexpected dereferenceable type {:?}",
+ ty))
+ }
+ }
+}
+
+fn const_fn_call<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+ node: ExprOrMethodCall,
+ def_id: ast::DefId,
+ arg_vals: &[ValueRef],
+ param_substs: &'tcx Substs<'tcx>) -> ValueRef {
+ let fn_like = const_eval::lookup_const_fn_by_id(ccx.tcx(), def_id);
+ let fn_like = fn_like.expect("lookup_const_fn_by_id failed in const_fn_call");
+
+ let args = &fn_like.decl().inputs;
+ assert_eq!(args.len(), arg_vals.len());
+
+ let arg_ids = args.iter().map(|arg| arg.pat.id);
+ let fn_args = arg_ids.zip(arg_vals.iter().cloned()).collect();
+
+ let substs = ccx.tcx().mk_substs(node_id_substs(ccx, node, param_substs));
+ match fn_like.body().expr {
+ Some(ref expr) => {
+ const_expr(ccx, &**expr, substs, Some(&fn_args)).0
}
+ None => C_nil(ccx)
}
}
qualif: check_const::ConstQualif,
param_substs: &'tcx Substs<'tcx>)
-> ValueRef {
+ debug!("get_const_expr_as_global: {:?}", expr.id);
// Special-case constants to cache a common global for all uses.
match expr.node {
ast::ExprPath(..) => {
match def {
def::DefConst(def_id) | def::DefAssociatedConst(def_id, _) => {
if !ccx.tcx().adjustments.borrow().contains_key(&expr.id) {
+ debug!("get_const_expr_as_global ({:?}): found const {:?}",
+ expr.id, def_id);
return get_const_val(ccx, def_id, expr);
}
}
// references, even when only the latter are correct.
let ty = monomorphize::apply_param_substs(ccx.tcx(), param_substs,
&ty::expr_ty(ccx.tcx(), expr));
- const_expr_unadjusted(ccx, expr, ty, param_substs)
+ const_expr_unadjusted(ccx, expr, ty, param_substs, None)
} else {
- const_expr(ccx, expr, param_substs).0
+ const_expr(ccx, expr, param_substs, None).0
};
// boolean SSA values are i1, but they have to be stored in i8 slots,
pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
e: &ast::Expr,
- param_substs: &'tcx Substs<'tcx>)
+ param_substs: &'tcx Substs<'tcx>,
+ fn_args: FnArgMap)
-> (ValueRef, Ty<'tcx>) {
let ety = monomorphize::apply_param_substs(cx.tcx(), param_substs,
&ty::expr_ty(cx.tcx(), e));
- let llconst = const_expr_unadjusted(cx, e, ety, param_substs);
+ let llconst = const_expr_unadjusted(cx, e, ety, param_substs, fn_args);
let mut llconst = llconst;
let mut ety_adjusted = monomorphize::apply_param_substs(cx.tcx(), param_substs,
&ty::expr_ty_adjusted(cx.tcx(), e));
let info = expr::unsized_info(cx, pointee_ty, unsized_ty,
old_info, param_substs);
- let prev_const = cx.const_unsized().borrow_mut()
- .insert(base, llconst);
- assert!(prev_const.is_none() || prev_const == Some(llconst));
+ if old_info.is_none() {
+ let prev_const = cx.const_unsized().borrow_mut()
+ .insert(base, llconst);
+ assert!(prev_const.is_none() || prev_const == Some(llconst));
+ }
assert_eq!(abi::FAT_PTR_ADDR, 0);
assert_eq!(abi::FAT_PTR_EXTRA, 1);
llconst = C_struct(cx, &[base, info], false);
llvm::LLVMDumpValue(llconst);
llvm::LLVMDumpValue(C_undef(llty));
}
- cx.sess().bug(&format!("const {} of type {} has size {} instead of {}",
- e.repr(cx.tcx()), ty_to_string(cx.tcx(), ety_adjusted),
+ cx.sess().bug(&format!("const {:?} of type {:?} has size {} instead of {}",
+ e, ety_adjusted,
csize, tsize));
}
(llconst, ety_adjusted)
if let ast::ExprLit(_) = inner_e.node { return; }
let result = match t.sty {
- ty::ty_int(int_type) => {
+ ty::TyInt(int_type) => {
let input = match const_to_opt_int(te) {
Some(v) => v,
None => return,
const_int_checked_neg(
input, e, Some(const_eval::IntTy::from(cx.tcx(), int_type)))
}
- ty::ty_uint(uint_type) => {
+ ty::TyUint(uint_type) => {
let input = match const_to_opt_uint(te) {
Some(v) => v,
None => return,
let b = if let ast::ExprBinary(b, _, _) = e.node { b } else { return };
let result = match t.sty {
- ty::ty_int(int_type) => {
+ ty::TyInt(int_type) => {
let (lhs, rhs) = match (const_to_opt_int(te1),
const_to_opt_int(te2)) {
(Some(v1), Some(v2)) => (v1, v2),
_ => return,
}
}
- ty::ty_uint(uint_type) => {
+ ty::TyUint(uint_type) => {
let (lhs, rhs) = match (const_to_opt_uint(te1),
const_to_opt_uint(te2)) {
(Some(v1), Some(v2)) => (v1, v2),
fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
e: &ast::Expr,
ety: Ty<'tcx>,
- param_substs: &'tcx Substs<'tcx>)
+ param_substs: &'tcx Substs<'tcx>,
+ fn_args: FnArgMap)
-> ValueRef
{
- debug!("const_expr_unadjusted(e={}, ety={}, param_substs={})",
- e.repr(cx.tcx()),
- ety.repr(cx.tcx()),
- param_substs.repr(cx.tcx()));
-
- let map_list = |exprs: &[P<ast::Expr>]| {
- exprs.iter().map(|e| const_expr(cx, &**e, param_substs).0)
- .fold(Vec::new(), |mut l, val| { l.push(val); l })
+ debug!("const_expr_unadjusted(e={:?}, ety={:?}, param_substs={:?})",
+ e,
+ ety,
+ param_substs);
+
+ let map_list = |exprs: &[P<ast::Expr>]| -> Vec<ValueRef> {
+ exprs.iter()
+ .map(|e| const_expr(cx, &**e, param_substs, fn_args).0)
+ .collect()
};
unsafe {
let _icx = push_ctxt("const_expr");
ast::ExprBinary(b, ref e1, ref e2) => {
/* Neither type is bottom, and we expect them to be unified
* already, so the following is safe. */
- let (te1, ty) = const_expr(cx, &**e1, param_substs);
- debug!("const_expr_unadjusted: te1={}, ty={}",
+ let (te1, ty) = const_expr(cx, &**e1, param_substs, fn_args);
+ debug!("const_expr_unadjusted: te1={}, ty={:?}",
cx.tn().val_to_string(te1),
- ty.repr(cx.tcx()));
+ ty);
let is_simd = ty::type_is_simd(cx.tcx(), ty);
let intype = if is_simd {
ty::simd_type(cx.tcx(), ty)
let is_float = ty::type_is_fp(intype);
let signed = ty::type_is_signed(intype);
- let (te2, _) = const_expr(cx, &**e2, param_substs);
+ let (te2, _) = const_expr(cx, &**e2, param_substs, fn_args);
check_binary_expr_validity(cx, e, ty, te1, te2);
}
},
ast::ExprUnary(u, ref inner_e) => {
- let (te, ty) = const_expr(cx, &**inner_e, param_substs);
+ let (te, ty) = const_expr(cx, &**inner_e, param_substs, fn_args);
check_unary_expr_validity(cx, e, ty, te);
}
}
ast::ExprField(ref base, field) => {
- let (bv, bt) = const_expr(cx, &**base, param_substs);
+ let (bv, bt) = const_expr(cx, &**base, param_substs, fn_args);
let brepr = adt::represent_type(cx, bt);
expr::with_field_tys(cx.tcx(), bt, None, |discr, field_tys| {
let ix = ty::field_idx_strict(cx.tcx(), field.node.name, field_tys);
})
}
ast::ExprTupField(ref base, idx) => {
- let (bv, bt) = const_expr(cx, &**base, param_substs);
+ let (bv, bt) = const_expr(cx, &**base, param_substs, fn_args);
let brepr = adt::represent_type(cx, bt);
expr::with_field_tys(cx.tcx(), bt, None, |discr, _| {
adt::const_get_field(cx, &*brepr, bv, discr, idx.node)
}
ast::ExprIndex(ref base, ref index) => {
- let (bv, bt) = const_expr(cx, &**base, param_substs);
+ let (bv, bt) = const_expr(cx, &**base, param_substs, fn_args);
let iv = match const_eval::eval_const_expr_partial(cx.tcx(), &**index, None) {
- Ok(const_eval::const_int(i)) => i as u64,
- Ok(const_eval::const_uint(u)) => u,
+ Ok(ConstVal::Int(i)) => i as u64,
+ Ok(ConstVal::Uint(u)) => u,
_ => cx.sess().span_bug(index.span,
"index is not an integer-constant expression")
};
let (arr, len) = match bt.sty {
- ty::ty_vec(_, Some(u)) => (bv, C_uint(cx, u)),
- ty::ty_vec(_, None) | ty::ty_str => {
+ ty::TyArray(_, u) => (bv, C_uint(cx, u)),
+ ty::TySlice(_) | ty::TyStr => {
let e1 = const_get_elt(cx, bv, &[0]);
(const_deref_ptr(cx, e1), const_get_elt(cx, bv, &[1]))
}
- ty::ty_rptr(_, mt) => match mt.ty.sty {
- ty::ty_vec(_, Some(u)) => {
+ ty::TyRef(_, mt) => match mt.ty.sty {
+ ty::TyArray(_, u) => {
(const_deref_ptr(cx, bv), C_uint(cx, u))
},
_ => cx.sess().span_bug(base.span,
&format!("index-expr base must be a vector \
- or string type, found {}",
- ty_to_string(cx.tcx(), bt)))
+ or string type, found {:?}",
+ bt))
},
_ => cx.sess().span_bug(base.span,
&format!("index-expr base must be a vector \
- or string type, found {}",
- ty_to_string(cx.tcx(), bt)))
+ or string type, found {:?}",
+ bt))
};
let len = llvm::LLVMConstIntGetZExtValue(len) as u64;
let len = match bt.sty {
- ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => match ty.sty {
- ty::ty_str => {
+ ty::TyBox(ty) | ty::TyRef(_, ty::mt{ty, ..}) => match ty.sty {
+ ty::TyStr => {
assert!(len > 0);
len - 1
}
}
}
ast::ExprCast(ref base, _) => {
- let llty = type_of::type_of(cx, ety);
- let (v, basety) = const_expr(cx, &**base, param_substs);
- if expr::cast_is_noop(basety, ety) {
+ let t_cast = ety;
+ let llty = type_of::type_of(cx, t_cast);
+ let (v, t_expr) = const_expr(cx, &**base, param_substs, fn_args);
+ debug!("trans_const_cast({:?} as {:?})", t_expr, t_cast);
+ if expr::cast_is_noop(cx.tcx(), base, t_expr, t_cast) {
return v;
}
- match (expr::cast_type_kind(cx.tcx(), basety),
- expr::cast_type_kind(cx.tcx(), ety)) {
-
- (expr::cast_integral, expr::cast_integral) => {
- let s = ty::type_is_signed(basety) as Bool;
+ if type_is_fat_ptr(cx.tcx(), t_expr) {
+ // Fat pointer casts.
+ let t_cast_inner = ty::deref(t_cast, true).expect("cast to non-pointer").ty;
+ let ptr_ty = type_of::in_memory_type_of(cx, t_cast_inner).ptr_to();
+ let addr = ptrcast(const_get_elt(cx, v, &[abi::FAT_PTR_ADDR as u32]),
+ ptr_ty);
+ if type_is_fat_ptr(cx.tcx(), t_cast) {
+ let info = const_get_elt(cx, v, &[abi::FAT_PTR_EXTRA as u32]);
+ return C_struct(cx, &[addr, info], false)
+ } else {
+ return addr;
+ }
+ }
+ match (CastTy::from_ty(cx.tcx(), t_expr).expect("bad input type for cast"),
+ CastTy::from_ty(cx.tcx(), t_cast).expect("bad output type for cast")) {
+ (CastTy::Int(IntTy::CEnum), CastTy::Int(_)) => {
+ let repr = adt::represent_type(cx, t_expr);
+ let discr = adt::const_get_discrim(cx, &*repr, v);
+ let iv = C_integral(cx.int_type(), discr, false);
+ let s = adt::is_discr_signed(&*repr) as Bool;
+ llvm::LLVMConstIntCast(iv, llty.to_ref(), s)
+ }
+ (CastTy::Int(_), CastTy::Int(_)) => {
+ let s = ty::type_is_signed(t_expr) as Bool;
llvm::LLVMConstIntCast(v, llty.to_ref(), s)
}
- (expr::cast_integral, expr::cast_float) => {
- if ty::type_is_signed(basety) {
+ (CastTy::Int(_), CastTy::Float) => {
+ if ty::type_is_signed(t_expr) {
llvm::LLVMConstSIToFP(v, llty.to_ref())
} else {
llvm::LLVMConstUIToFP(v, llty.to_ref())
}
}
- (expr::cast_float, expr::cast_float) => {
+ (CastTy::Float, CastTy::Float) => {
llvm::LLVMConstFPCast(v, llty.to_ref())
}
- (expr::cast_float, expr::cast_integral) => {
- if ty::type_is_signed(ety) { llvm::LLVMConstFPToSI(v, llty.to_ref()) }
- else { llvm::LLVMConstFPToUI(v, llty.to_ref()) }
+ (CastTy::Float, CastTy::Int(IntTy::I)) => {
+ llvm::LLVMConstFPToSI(v, llty.to_ref())
}
- (expr::cast_enum, expr::cast_integral) => {
- let repr = adt::represent_type(cx, basety);
- let discr = adt::const_get_discrim(cx, &*repr, v);
- let iv = C_integral(cx.int_type(), discr, false);
- let ety_cast = expr::cast_type_kind(cx.tcx(), ety);
- match ety_cast {
- expr::cast_integral => {
- let s = ty::type_is_signed(ety) as Bool;
- llvm::LLVMConstIntCast(iv, llty.to_ref(), s)
- }
- _ => cx.sess().bug("enum cast destination is not \
- integral")
- }
+ (CastTy::Float, CastTy::Int(_)) => {
+ llvm::LLVMConstFPToUI(v, llty.to_ref())
}
- (expr::cast_pointer, expr::cast_pointer) => {
+ (CastTy::Ptr(_), CastTy::Ptr(_)) | (CastTy::FnPtr, CastTy::Ptr(_))
+ | (CastTy::RPtr(_), CastTy::Ptr(_)) => {
ptrcast(v, llty)
}
- (expr::cast_integral, expr::cast_pointer) => {
+ (CastTy::FnPtr, CastTy::FnPtr) => ptrcast(v, llty), // isn't this a coercion?
+ (CastTy::Int(_), CastTy::Ptr(_)) => {
llvm::LLVMConstIntToPtr(v, llty.to_ref())
}
- (expr::cast_pointer, expr::cast_integral) => {
+ (CastTy::Ptr(_), CastTy::Int(_)) | (CastTy::FnPtr, CastTy::Int(_)) => {
llvm::LLVMConstPtrToInt(v, llty.to_ref())
}
_ => {
} else {
// If this isn't the address of a static, then keep going through
// normal constant evaluation.
- let (v, _) = const_expr(cx, &**sub, param_substs);
+ let (v, _) = const_expr(cx, &**sub, param_substs, fn_args);
addr_of(cx, v, "ref")
}
}
ast::ExprAddrOf(ast::MutMutable, ref sub) => {
- let (v, _) = const_expr(cx, &**sub, param_substs);
+ let (v, _) = const_expr(cx, &**sub, param_substs, fn_args);
addr_of_mut(cx, v, "ref_mut_slice")
}
ast::ExprTup(ref es) => {
let repr = adt::represent_type(cx, ety);
let base_val = match *base_opt {
- Some(ref base) => Some(const_expr(cx, &**base, param_substs)),
+ Some(ref base) => Some(const_expr(cx, &**base, param_substs, fn_args)),
None => None
};
let cs = field_tys.iter().enumerate()
.map(|(ix, &field_ty)| {
match fs.iter().find(|f| field_ty.name == f.ident.node.name) {
- Some(ref f) => const_expr(cx, &*f.expr, param_substs).0,
+ Some(ref f) => const_expr(cx, &*f.expr, param_substs, fn_args).0,
None => {
match base_val {
Some((bv, _)) => {
ast::ExprVec(ref es) => {
let unit_ty = ty::sequence_element_type(cx.tcx(), ety);
let llunitty = type_of::type_of(cx, unit_ty);
- let vs = es.iter().map(|e| const_expr(cx, &**e, param_substs).0)
+ let vs = es.iter().map(|e| const_expr(cx, &**e, param_substs, fn_args).0)
.collect::<Vec<_>>();
// If the vector contains enums, an LLVM array won't work.
if vs.iter().any(|vi| val_ty(*vi) != llunitty) {
let unit_ty = ty::sequence_element_type(cx.tcx(), ety);
let llunitty = type_of::type_of(cx, unit_ty);
let n = ty::eval_repeat_count(cx.tcx(), count);
- let unit_val = const_expr(cx, &**elem, param_substs).0;
+ let unit_val = const_expr(cx, &**elem, param_substs, fn_args).0;
let vs: Vec<_> = repeat(unit_val).take(n).collect();
if val_ty(unit_val) != llunitty {
C_struct(cx, &vs[..], false)
ast::ExprPath(..) => {
let def = cx.tcx().def_map.borrow().get(&e.id).unwrap().full_def();
match def {
+ def::DefLocal(id) => {
+ if let Some(val) = fn_args.and_then(|args| args.get(&id).cloned()) {
+ val
+ } else {
+ cx.sess().span_bug(e.span, "const fn argument not found")
+ }
+ }
def::DefFn(..) | def::DefMethod(..) => {
expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val
}
}
}
def::DefStruct(_) => {
- if let ty::ty_bare_fn(..) = ety.sty {
+ if let ty::TyBareFn(..) = ety.sty {
// Tuple struct.
expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val
} else {
}
}
ast::ExprCall(ref callee, ref args) => {
- let opt_def = cx.tcx().def_map.borrow().get(&callee.id).map(|d| d.full_def());
- let arg_vals = map_list(&args[..]);
- match opt_def {
- Some(def::DefStruct(_)) => {
+ let mut callee = &**callee;
+ loop {
+ callee = match callee.node {
+ ast::ExprParen(ref inner) => &**inner,
+ ast::ExprBlock(ref block) => match block.expr {
+ Some(ref tail) => &**tail,
+ None => break
+ },
+ _ => break
+ };
+ }
+ let def = cx.tcx().def_map.borrow()[&callee.id].full_def();
+ let arg_vals = map_list(args);
+ match def {
+ def::DefFn(did, _) | def::DefMethod(did, _) => {
+ const_fn_call(cx, ExprId(callee.id), did, &arg_vals, param_substs)
+ }
+ def::DefStruct(_) => {
if ty::type_is_simd(cx.tcx(), ety) {
C_vector(&arg_vals[..])
} else {
adt::trans_const(cx, &*repr, 0, &arg_vals[..])
}
}
- Some(def::DefVariant(enum_did, variant_did, _)) => {
+ def::DefVariant(enum_did, variant_did, _) => {
let repr = adt::represent_type(cx, ety);
let vinfo = ty::enum_variant_with_id(cx.tcx(),
enum_did,
vinfo.disr_val,
&arg_vals[..])
}
- _ => cx.sess().span_bug(e.span, "expected a struct or variant def")
+ _ => cx.sess().span_bug(e.span, "expected a struct, variant, or const fn def")
}
}
- ast::ExprParen(ref e) => const_expr(cx, &**e, param_substs).0,
+ ast::ExprMethodCall(_, _, ref args) => {
+ let arg_vals = map_list(args);
+ let method_call = ty::MethodCall::expr(e.id);
+ let method_did = match cx.tcx().method_map.borrow()[&method_call].origin {
+ ty::MethodStatic(did) => did,
+ _ => cx.sess().span_bug(e.span, "expected a const method def")
+ };
+ const_fn_call(cx, MethodCallKey(method_call),
+ method_did, &arg_vals, param_substs)
+ }
+ ast::ExprParen(ref e) => const_expr(cx, &**e, param_substs, fn_args).0,
ast::ExprBlock(ref block) => {
match block.expr {
- Some(ref expr) => const_expr(cx, &**expr, param_substs).0,
+ Some(ref expr) => const_expr(cx, &**expr, param_substs, fn_args).0,
None => C_nil(cx)
}
}
ast::ExprClosure(_, ref decl, ref body) => {
closure::trans_closure_expr(closure::Dest::Ignore(cx),
- &**decl, &**body, e.id,
+ decl,
+ body,
+ e.id,
param_substs);
C_null(type_of::type_of(cx, ety))
}
use middle::ty::{self, Ty};
use session::config::NoDebugInfo;
use session::Session;
-use util::ppaux::Repr;
use util::sha2::Sha256;
use util::nodemap::{NodeMap, NodeSet, DefIdMap, FnvHashMap, FnvHashSet};
/// per crate. The data here is shared between all compilation units of the
/// crate, so it must not contain references to any LLVM data structures
/// (aside from metadata-related ones).
-pub struct SharedCrateContext<'tcx> {
+pub struct SharedCrateContext<'a, 'tcx: 'a> {
local_ccxs: Vec<LocalCrateContext<'tcx>>,
metadata_llmod: ModuleRef,
item_symbols: RefCell<NodeMap<String>>,
link_meta: LinkMeta,
symbol_hasher: RefCell<Sha256>,
- tcx: ty::ctxt<'tcx>,
+ tcx: &'a ty::ctxt<'tcx>,
stats: Stats,
check_overflow: bool,
check_drop_flag_for_sanity: bool,
- available_monomorphizations: RefCell<FnvHashSet<String>>,
available_drop_glues: RefCell<FnvHashMap<DropGlueKind<'tcx>, String>>,
+ use_dll_storage_attrs: bool,
}
/// The local portion of a `CrateContext`. There is one `LocalCrateContext`
/// Cache instances of monomorphized functions
monomorphized: RefCell<FnvHashMap<MonoId<'tcx>, ValueRef>>,
monomorphizing: RefCell<DefIdMap<usize>>,
+ available_monomorphizations: RefCell<FnvHashSet<String>>,
/// Cache generated vtables
vtables: RefCell<FnvHashMap<ty::PolyTraitRef<'tcx>, ValueRef>>,
/// Cache of constant strings,
}
pub struct CrateContext<'a, 'tcx: 'a> {
- shared: &'a SharedCrateContext<'tcx>,
+ shared: &'a SharedCrateContext<'a, 'tcx>,
local: &'a LocalCrateContext<'tcx>,
/// The index of `local` in `shared.local_ccxs`. This is used in
/// `maybe_iter(true)` to identify the original `LocalCrateContext`.
}
pub struct CrateContextIterator<'a, 'tcx: 'a> {
- shared: &'a SharedCrateContext<'tcx>,
+ shared: &'a SharedCrateContext<'a, 'tcx>,
index: usize,
}
/// The iterator produced by `CrateContext::maybe_iter`.
pub struct CrateContextMaybeIterator<'a, 'tcx: 'a> {
- shared: &'a SharedCrateContext<'tcx>,
+ shared: &'a SharedCrateContext<'a, 'tcx>,
index: usize,
single: bool,
origin: usize,
(llcx, llmod)
}
-impl<'tcx> SharedCrateContext<'tcx> {
+impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
pub fn new(crate_name: &str,
local_count: usize,
- tcx: ty::ctxt<'tcx>,
+ tcx: &'b ty::ctxt<'tcx>,
export_map: ExportMap,
symbol_hasher: Sha256,
link_meta: LinkMeta,
reachable: NodeSet,
check_overflow: bool,
check_drop_flag_for_sanity: bool)
- -> SharedCrateContext<'tcx> {
+ -> SharedCrateContext<'b, 'tcx> {
let (metadata_llcx, metadata_llmod) = unsafe {
create_context_and_module(&tcx.sess, "metadata")
};
+ // An interesting part of Windows which MSVC forces our hand on (and
+ // apparently MinGW didn't) is the usage of `dllimport` and `dllexport`
+ // attributes in LLVM IR as well as native dependencies (in C these
+ // correspond to `__declspec(dllimport)`).
+ //
+ // Whenever a dynamic library is built by MSVC it must have its public
+ // interface specified by functions tagged with `dllexport` or otherwise
+ // they're not available to be linked against. This poses a few problems
+ // for the compiler, some of which are somewhat fundamental, but we use
+ // the `use_dll_storage_attrs` variable below to attach the `dllexport`
+ // attribute to all LLVM functions that are reachable (e.g. they're
+ // already tagged with external linkage). This is suboptimal for a few
+ // reasons:
+ //
+ // * If an object file will never be included in a dynamic library,
+ // there's no need to attach the dllexport attribute. Most object
+ // files in Rust are not destined to become part of a dll as binaries
+ // are statically linked by default.
+ // * If the compiler is emitting both an rlib and a dylib, the same
+ // source object file is currently used but with MSVC this may be less
+ // feasible. The compiler may be able to get around this, but it may
+ // involve some invasive changes to deal with this.
+ //
+ // The flipside of this situation is that whenever you link to a dll and
+ // you import a function from it, the import should be tagged with
+ // `dllimport`. At this time, however, the compiler does not emit
+ // `dllimport` for any declarations other than constants (where it is
+ // required), which is again suboptimal for even more reasons!
+ //
+ // * Calling a function imported from another dll without using
+ // `dllimport` causes the linker/compiler to have extra overhead (one
+ // `jmp` instruction on x86) when calling the function.
+ // * The same object file may be used in different circumstances, so a
+ // function may be imported from a dll if the object is linked into a
+ // dll, but it may be just linked against if linked into an rlib.
+ // * The compiler has no knowledge about whether native functions should
+ // be tagged dllimport or not.
+ //
+ // For now the compiler takes the perf hit (I do not have any numbers to
+ // this effect) by marking very little as `dllimport` and praying the
+ // linker will take care of everything. Fixing this problem will likely
+ // require adding a few attributes to Rust itself (feature gated at the
+ // start) and then strongly recommending static linkage on MSVC!
+ let use_dll_storage_attrs = tcx.sess.target.target.options.is_like_msvc;
+
let mut shared_ccx = SharedCrateContext {
local_ccxs: Vec::with_capacity(local_count),
metadata_llmod: metadata_llmod,
},
check_overflow: check_overflow,
check_drop_flag_for_sanity: check_drop_flag_for_sanity,
- available_monomorphizations: RefCell::new(FnvHashSet()),
available_drop_glues: RefCell::new(FnvHashMap()),
+ use_dll_storage_attrs: use_dll_storage_attrs,
};
for i in 0..local_count {
}
pub fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> {
- &self.tcx
- }
-
- pub fn take_tcx(self) -> ty::ctxt<'tcx> {
self.tcx
}
pub fn stats<'a>(&'a self) -> &'a Stats {
&self.stats
}
+
+ pub fn use_dll_storage_attrs(&self) -> bool {
+ self.use_dll_storage_attrs
+ }
}
impl<'tcx> LocalCrateContext<'tcx> {
- fn new(shared: &SharedCrateContext<'tcx>,
+ fn new<'a>(shared: &SharedCrateContext<'a, 'tcx>,
name: &str)
-> LocalCrateContext<'tcx> {
unsafe {
external_srcs: RefCell::new(NodeMap()),
monomorphized: RefCell::new(FnvHashMap()),
monomorphizing: RefCell::new(DefIdMap()),
+ available_monomorphizations: RefCell::new(FnvHashSet()),
vtables: RefCell::new(FnvHashMap()),
const_cstr_cache: RefCell::new(FnvHashMap()),
const_unsized: RefCell::new(FnvHashMap()),
/// This is used in the `LocalCrateContext` constructor to allow calling
/// functions that expect a complete `CrateContext`, even before the local
/// portion is fully initialized and attached to the `SharedCrateContext`.
- fn dummy_ccx<'a>(&'a self, shared: &'a SharedCrateContext<'tcx>)
+ fn dummy_ccx<'a>(&'a self, shared: &'a SharedCrateContext<'a, 'tcx>)
-> CrateContext<'a, 'tcx> {
CrateContext {
shared: shared,
}
impl<'b, 'tcx> CrateContext<'b, 'tcx> {
- pub fn shared(&self) -> &'b SharedCrateContext<'tcx> {
+ pub fn shared(&self) -> &'b SharedCrateContext<'b, 'tcx> {
self.shared
}
pub fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> {
- &self.shared.tcx
+ self.shared.tcx
}
pub fn sess<'a>(&'a self) -> &'a Session {
}
pub fn available_monomorphizations<'a>(&'a self) -> &'a RefCell<FnvHashSet<String>> {
- &self.shared.available_monomorphizations
+ &self.local.available_monomorphizations
}
pub fn available_drop_glues(&self) -> &RefCell<FnvHashMap<DropGlueKind<'tcx>, String>> {
pub fn report_overbig_object(&self, obj: Ty<'tcx>) -> ! {
self.sess().fatal(
- &format!("the type `{}` is too big for the current architecture",
- obj.repr(self.tcx())))
+ &format!("the type `{:?}` is too big for the current architecture",
+ obj))
}
pub fn check_overflow(&self) -> bool {
// values.
self.shared.check_drop_flag_for_sanity
}
+
+ pub fn use_dll_storage_attrs(&self) -> bool {
+ self.shared.use_dll_storage_attrs()
+ }
}
/// Declare any llvm intrinsics that you might need
ifn!("llvm.trunc.f32", fn(t_f32) -> t_f32);
ifn!("llvm.trunc.f64", fn(t_f64) -> t_f64);
+ ifn!("llvm.copysign.f32", fn(t_f32, t_f32) -> t_f32);
+ ifn!("llvm.copysign.f64", fn(t_f64, t_f64) -> t_f64);
+ ifn!("llvm.round.f32", fn(t_f32) -> t_f32);
+ ifn!("llvm.round.f64", fn(t_f64) -> t_f64);
+
ifn!("llvm.rint.f32", fn(t_f32) -> t_f32);
ifn!("llvm.rint.f64", fn(t_f64) -> t_f64);
ifn!("llvm.nearbyint.f32", fn(t_f32) -> t_f32);
ifn!("llvm.lifetime.end", fn(t_i64, i8p) -> void);
ifn!("llvm.expect.i1", fn(i1, i1) -> i1);
- ifn!("llvm.assume", fn(i1) -> void);
// Some intrinsics were introduced in later versions of LLVM, but they have
- // fallbacks in libc or libm and such. Currently, all of these intrinsics
- // were introduced in LLVM 3.4, so we case on that.
+ // fallbacks in libc or libm and such.
macro_rules! compatible_ifn {
- ($name:expr, $cname:ident ($($arg:expr),*) -> $ret:expr) => (
- ifn!($name, fn($($arg),*) -> $ret);
+ ($name:expr, noop($cname:ident ($($arg:expr),*) -> void), $llvm_version:expr) => (
+ if unsafe { llvm::LLVMVersionMinor() >= $llvm_version } {
+ // The `if key == $name` is already in ifn!
+ ifn!($name, fn($($arg),*) -> void);
+ } else if *key == $name {
+ let f = declare::declare_cfn(ccx, stringify!($cname),
+ Type::func(&[$($arg),*], &void),
+ ty::mk_nil(ccx.tcx()));
+ llvm::SetLinkage(f, llvm::InternalLinkage);
+
+ let bld = ccx.builder();
+ let llbb = unsafe {
+ llvm::LLVMAppendBasicBlockInContext(ccx.llcx(), f,
+ "entry-block\0".as_ptr() as *const _)
+ };
+
+ bld.position_at_end(llbb);
+ bld.ret_void();
+
+ ccx.intrinsics().borrow_mut().insert($name, f.clone());
+ return Some(f);
+ }
+ );
+ ($name:expr, $cname:ident ($($arg:expr),*) -> $ret:expr, $llvm_version:expr) => (
+ if unsafe { llvm::LLVMVersionMinor() >= $llvm_version } {
+ // The `if key == $name` is already in ifn!
+ ifn!($name, fn($($arg),*) -> $ret);
+ } else if *key == $name {
+ let f = declare::declare_cfn(ccx, stringify!($cname),
+ Type::func(&[$($arg),*], &$ret),
+ ty::mk_nil(ccx.tcx()));
+ ccx.intrinsics().borrow_mut().insert($name, f.clone());
+ return Some(f);
+ }
)
}
- compatible_ifn!("llvm.copysign.f32", copysignf(t_f32, t_f32) -> t_f32);
- compatible_ifn!("llvm.copysign.f64", copysign(t_f64, t_f64) -> t_f64);
- compatible_ifn!("llvm.round.f32", roundf(t_f32) -> t_f32);
- compatible_ifn!("llvm.round.f64", round(t_f64) -> t_f64);
-
+ compatible_ifn!("llvm.assume", noop(llvmcompat_assume(i1) -> void), 6);
if ccx.sess().opts.debuginfo != NoDebugInfo {
ifn!("llvm.dbg.declare", fn(Type::metadata(ccx), Type::metadata(ccx)) -> void);
use trans::expr;
use trans;
use middle::ty;
-use util::ppaux::Repr;
use syntax::ast;
use syntax::ast_util;
use syntax::parse::token::InternedString;
use syntax::parse::token;
-use syntax::visit::Visitor;
pub fn trans_stmt<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
s: &ast::Stmt)
-> Block<'blk, 'tcx> {
let _icx = push_ctxt("trans_stmt");
let fcx = cx.fcx;
- debug!("trans_stmt({})", s.repr(cx.tcx()));
+ debug!("trans_stmt({:?})", s);
if cx.unreachable.get() {
return cx;
}
if cx.sess().asm_comments() {
- add_span_comment(cx, s.span, &s.repr(cx.tcx()));
+ add_span_comment(cx, s.span, &format!("{:?}", s));
}
let mut bcx = cx;
els: Option<&ast::Expr>,
dest: expr::Dest)
-> Block<'blk, 'tcx> {
- debug!("trans_if(bcx={}, if_id={}, cond={}, thn={}, dest={})",
- bcx.to_str(), if_id, bcx.expr_to_string(cond), thn.id,
+ debug!("trans_if(bcx={}, if_id={}, cond={:?}, thn={}, dest={})",
+ bcx.to_str(), if_id, cond, thn.id,
dest.to_string(bcx.ccx()));
let _icx = push_ctxt("trans_if");
let cond_val = unpack_result!(bcx, expr::trans(bcx, cond).to_llbool());
// Drop branches that are known to be impossible
- if is_const(cond_val) && !is_undef(cond_val) {
- if const_to_uint(cond_val) == 1 {
- match els {
- Some(elexpr) => {
- let mut trans = TransItemVisitor { ccx: bcx.fcx.ccx };
- trans.visit_expr(&*elexpr);
- }
- None => {}
- }
+ if let Some(cv) = const_to_opt_uint(cond_val) {
+ if cv == 1 {
// if true { .. } [else { .. }]
bcx = trans_block(bcx, &*thn, dest);
trans::debuginfo::clear_source_location(bcx.fcx);
} else {
- let mut trans = TransItemVisitor { ccx: bcx.fcx.ccx } ;
- trans.visit_block(&*thn);
-
- match els {
- // if false { .. } else { .. }
- Some(elexpr) => {
- bcx = expr::trans_into(bcx, &*elexpr, dest);
- trans::debuginfo::clear_source_location(bcx.fcx);
- }
-
- // if false { .. }
- None => { }
+ if let Some(elexpr) = els {
+ bcx = expr::trans_into(bcx, &*elexpr, dest);
+ trans::debuginfo::clear_source_location(bcx.fcx);
}
}
//! `&foo()` or `match foo() { ref x => ... }`, where the user is
//! implicitly requesting a temporary.
//!
-//! Somewhat surprisingly, not all lvalue expressions yield lvalue datums
-//! when trans'd. Ultimately the reason for this is to micro-optimize
-//! the resulting LLVM. For example, consider the following code:
-//!
-//! fn foo() -> Box<int> { ... }
-//! let x = *foo();
-//!
-//! The expression `*foo()` is an lvalue, but if you invoke `expr::trans`,
-//! it will return an rvalue datum. See `deref_once` in expr.rs for
-//! more details.
-//!
//! ### Rvalues in detail
//!
//! Rvalues datums are values with no cleanup scheduled. One must be
use trans::tvec;
use trans::type_of;
use middle::ty::{self, Ty};
-use util::ppaux::ty_to_string;
use std::fmt;
use syntax::ast;
#[allow(dead_code)] // useful for debugging
pub fn to_string<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> String {
- format!("Datum({}, {}, {:?})",
+ format!("Datum({}, {:?}, {:?})",
ccx.tn().val_to_string(self.val),
- ty_to_string(ccx.tcx(), self.ty),
+ self.ty,
self.kind)
}
for &codemap::Spanned {
node: ast::FieldPat { pat: ref sub_pat, .. },
..
- } in field_pats.iter() {
+ } in field_pats {
walk_pattern(cx, &**sub_pat, scope_stack, scope_map);
}
}
use metadata::csearch;
use middle::pat_util;
use middle::subst::{self, Substs};
+use rustc::ast_map;
use trans::{type_of, adt, machine, monomorphize};
use trans::common::{self, CrateContext, FunctionContext, NormalizingClosureTyper, Block};
use trans::_match::{BindingInfo, TrByCopy, TrByMove, TrByRef};
use middle::ty::{self, Ty, ClosureTyper};
use session::config::{self, FullDebugInfo};
use util::nodemap::FnvHashMap;
-use util::ppaux;
use util::common::path2cstr;
use libc::{c_uint, c_longlong};
use std::rc::Rc;
use syntax::util::interner::Interner;
use syntax::codemap::Span;
-use syntax::{ast, codemap, ast_util, ast_map};
+use syntax::{ast, codemap, ast_util};
use syntax::parse::token::{self, special_idents};
metadata: DIType) {
if self.type_to_metadata.insert(type_, metadata).is_some() {
cx.sess().bug(&format!("Type metadata for Ty '{}' is already in the TypeMap!",
- ppaux::ty_to_string(cx.tcx(), type_)));
+ type_));
}
}
unique_type_id.push('{');
match type_.sty {
- ty::ty_bool |
- ty::ty_char |
- ty::ty_str |
- ty::ty_int(_) |
- ty::ty_uint(_) |
- ty::ty_float(_) => {
+ ty::TyBool |
+ ty::TyChar |
+ ty::TyStr |
+ ty::TyInt(_) |
+ ty::TyUint(_) |
+ ty::TyFloat(_) => {
push_debuginfo_type_name(cx, type_, false, &mut unique_type_id);
},
- ty::ty_enum(def_id, substs) => {
+ ty::TyEnum(def_id, substs) => {
unique_type_id.push_str("enum ");
from_def_id_and_substs(self, cx, def_id, substs, &mut unique_type_id);
},
- ty::ty_struct(def_id, substs) => {
+ ty::TyStruct(def_id, substs) => {
unique_type_id.push_str("struct ");
from_def_id_and_substs(self, cx, def_id, substs, &mut unique_type_id);
},
- ty::ty_tup(ref component_types) if component_types.is_empty() => {
+ ty::TyTuple(ref component_types) if component_types.is_empty() => {
push_debuginfo_type_name(cx, type_, false, &mut unique_type_id);
},
- ty::ty_tup(ref component_types) => {
+ ty::TyTuple(ref component_types) => {
unique_type_id.push_str("tuple ");
for &component_type in component_types {
let component_type_id =
unique_type_id.push_str(&component_type_id[..]);
}
},
- ty::ty_uniq(inner_type) => {
+ ty::TyBox(inner_type) => {
unique_type_id.push_str("box ");
let inner_type_id = self.get_unique_type_id_of_type(cx, inner_type);
let inner_type_id = self.get_unique_type_id_as_string(inner_type_id);
unique_type_id.push_str(&inner_type_id[..]);
},
- ty::ty_ptr(ty::mt { ty: inner_type, mutbl } ) => {
+ ty::TyRawPtr(ty::mt { ty: inner_type, mutbl } ) => {
unique_type_id.push('*');
if mutbl == ast::MutMutable {
unique_type_id.push_str("mut");
let inner_type_id = self.get_unique_type_id_as_string(inner_type_id);
unique_type_id.push_str(&inner_type_id[..]);
},
- ty::ty_rptr(_, ty::mt { ty: inner_type, mutbl }) => {
+ ty::TyRef(_, ty::mt { ty: inner_type, mutbl }) => {
unique_type_id.push('&');
if mutbl == ast::MutMutable {
unique_type_id.push_str("mut");
let inner_type_id = self.get_unique_type_id_as_string(inner_type_id);
unique_type_id.push_str(&inner_type_id[..]);
},
- ty::ty_vec(inner_type, optional_length) => {
- match optional_length {
- Some(len) => {
- unique_type_id.push_str(&format!("[{}]", len));
- }
- None => {
- unique_type_id.push_str("[]");
- }
- };
+ ty::TyArray(inner_type, len) => {
+ unique_type_id.push_str(&format!("[{}]", len));
+
+ let inner_type_id = self.get_unique_type_id_of_type(cx, inner_type);
+ let inner_type_id = self.get_unique_type_id_as_string(inner_type_id);
+ unique_type_id.push_str(&inner_type_id[..]);
+ },
+ ty::TySlice(inner_type) => {
+ unique_type_id.push_str("[]");
let inner_type_id = self.get_unique_type_id_of_type(cx, inner_type);
let inner_type_id = self.get_unique_type_id_as_string(inner_type_id);
unique_type_id.push_str(&inner_type_id[..]);
},
- ty::ty_trait(ref trait_data) => {
+ ty::TyTrait(ref trait_data) => {
unique_type_id.push_str("trait ");
let principal =
principal.substs,
&mut unique_type_id);
},
- ty::ty_bare_fn(_, &ty::BareFnTy{ unsafety, abi, ref sig } ) => {
+ ty::TyBareFn(_, &ty::BareFnTy{ unsafety, abi, ref sig } ) => {
if unsafety == ast::Unsafety::Unsafe {
unique_type_id.push_str("unsafe ");
}
}
}
},
- ty::ty_closure(def_id, substs) => {
+ ty::TyClosure(def_id, substs) => {
let typer = NormalizingClosureTyper::new(cx.tcx());
let closure_ty = typer.closure_type(def_id, substs);
self.get_unique_type_id_of_closure_type(cx,
&mut unique_type_id);
},
_ => {
- cx.sess().bug(&format!("get_unique_type_id_of_type() - unexpected type: {}, {:?}",
- &ppaux::ty_to_string(cx.tcx(), type_),
- type_.sty))
+ cx.sess().bug(&format!("get_unique_type_id_of_type() - unexpected type: {:?}",
+ type_))
}
};
if type_map.find_metadata_for_unique_id(unique_type_id).is_none() ||
type_map.find_metadata_for_type(unfinished_type).is_none() {
cx.sess().bug(&format!("Forward declaration of potentially recursive type \
- '{}' was not found in TypeMap!",
- ppaux::ty_to_string(cx.tcx(), unfinished_type))
+ '{:?}' was not found in TypeMap!",
+ unfinished_type)
);
}
}
// return type
signature_metadata.push(match signature.output {
ty::FnConverging(ret_ty) => match ret_ty.sty {
- ty::ty_tup(ref tys) if tys.is_empty() => ptr::null_mut(),
+ ty::TyTuple(ref tys) if tys.is_empty() => ptr::null_mut(),
_ => type_metadata(cx, ret_ty, span)
},
ty::FnDiverging => diverging_type_metadata(cx)
// But it does not describe the trait's methods.
let def_id = match trait_type.sty {
- ty::ty_trait(ref data) => data.principal_def_id(),
+ ty::TyTrait(ref data) => data.principal_def_id(),
_ => {
- let pp_type_name = ppaux::ty_to_string(cx.tcx(), trait_type);
cx.sess().bug(&format!("debuginfo: Unexpected trait-object type in \
- trait_pointer_metadata(): {}",
- &pp_type_name[..]));
+ trait_pointer_metadata(): {:?}",
+ trait_type));
}
};
let sty = &t.sty;
let MetadataCreationResult { metadata, already_stored_in_typemap } = match *sty {
- ty::ty_bool |
- ty::ty_char |
- ty::ty_int(_) |
- ty::ty_uint(_) |
- ty::ty_float(_) => {
+ ty::TyBool |
+ ty::TyChar |
+ ty::TyInt(_) |
+ ty::TyUint(_) |
+ ty::TyFloat(_) => {
MetadataCreationResult::new(basic_type_metadata(cx, t), false)
}
- ty::ty_tup(ref elements) if elements.is_empty() => {
+ ty::TyTuple(ref elements) if elements.is_empty() => {
MetadataCreationResult::new(basic_type_metadata(cx, t), false)
}
- ty::ty_enum(def_id, _) => {
+ ty::TyEnum(def_id, _) => {
prepare_enum_metadata(cx, t, def_id, unique_type_id, usage_site_span).finalize(cx)
}
- ty::ty_vec(typ, len) => {
- fixed_vec_metadata(cx, unique_type_id, typ, len.map(|x| x as u64), usage_site_span)
+ ty::TyArray(typ, len) => {
+ fixed_vec_metadata(cx, unique_type_id, typ, Some(len as u64), usage_site_span)
+ }
+ ty::TySlice(typ) => {
+ fixed_vec_metadata(cx, unique_type_id, typ, None, usage_site_span)
}
- ty::ty_str => {
+ ty::TyStr => {
fixed_vec_metadata(cx, unique_type_id, cx.tcx().types.i8, None, usage_site_span)
}
- ty::ty_trait(..) => {
+ ty::TyTrait(..) => {
MetadataCreationResult::new(
trait_pointer_metadata(cx, t, None, unique_type_id),
false)
}
- ty::ty_uniq(ty) | ty::ty_ptr(ty::mt{ty, ..}) | ty::ty_rptr(_, ty::mt{ty, ..}) => {
+ ty::TyBox(ty) | ty::TyRawPtr(ty::mt{ty, ..}) | ty::TyRef(_, ty::mt{ty, ..}) => {
match ty.sty {
- ty::ty_vec(typ, None) => {
+ ty::TySlice(typ) => {
vec_slice_metadata(cx, t, typ, unique_type_id, usage_site_span)
}
- ty::ty_str => {
+ ty::TyStr => {
vec_slice_metadata(cx, t, cx.tcx().types.u8, unique_type_id, usage_site_span)
}
- ty::ty_trait(..) => {
+ ty::TyTrait(..) => {
MetadataCreationResult::new(
trait_pointer_metadata(cx, ty, Some(t), unique_type_id),
false)
}
}
}
- ty::ty_bare_fn(_, ref barefnty) => {
+ ty::TyBareFn(_, ref barefnty) => {
subroutine_type_metadata(cx, unique_type_id, &barefnty.sig, usage_site_span)
}
- ty::ty_closure(def_id, substs) => {
+ ty::TyClosure(def_id, substs) => {
let typer = NormalizingClosureTyper::new(cx.tcx());
let sig = typer.closure_type(def_id, substs).sig;
subroutine_type_metadata(cx, unique_type_id, &sig, usage_site_span)
}
- ty::ty_struct(def_id, substs) => {
+ ty::TyStruct(def_id, substs) => {
prepare_struct_metadata(cx,
t,
def_id,
unique_type_id,
usage_site_span).finalize(cx)
}
- ty::ty_tup(ref elements) => {
+ ty::TyTuple(ref elements) => {
prepare_tuple_metadata(cx,
t,
&elements[..],
the debuginfo::TypeMap but it \
was not. (Ty = {})",
&unique_type_id_str[..],
- ppaux::ty_to_string(cx.tcx(), t));
+ t);
cx.sess().span_bug(usage_site_span, &error_message[..]);
}
};
debuginfo::TypeMap. \
UniqueTypeId={}, Ty={}",
&unique_type_id_str[..],
- ppaux::ty_to_string(cx.tcx(), t));
+ t);
cx.sess().span_bug(usage_site_span, &error_message[..]);
}
}
debug!("basic_type_metadata: {:?}", t);
let (name, encoding) = match t.sty {
- ty::ty_tup(ref elements) if elements.is_empty() =>
+ ty::TyTuple(ref elements) if elements.is_empty() =>
("()".to_string(), DW_ATE_unsigned),
- ty::ty_bool => ("bool".to_string(), DW_ATE_boolean),
- ty::ty_char => ("char".to_string(), DW_ATE_unsigned_char),
- ty::ty_int(int_ty) => match int_ty {
+ ty::TyBool => ("bool".to_string(), DW_ATE_boolean),
+ ty::TyChar => ("char".to_string(), DW_ATE_unsigned_char),
+ ty::TyInt(int_ty) => match int_ty {
ast::TyIs => ("isize".to_string(), DW_ATE_signed),
ast::TyI8 => ("i8".to_string(), DW_ATE_signed),
ast::TyI16 => ("i16".to_string(), DW_ATE_signed),
ast::TyI32 => ("i32".to_string(), DW_ATE_signed),
ast::TyI64 => ("i64".to_string(), DW_ATE_signed)
},
- ty::ty_uint(uint_ty) => match uint_ty {
+ ty::TyUint(uint_ty) => match uint_ty {
ast::TyUs => ("usize".to_string(), DW_ATE_unsigned),
ast::TyU8 => ("u8".to_string(), DW_ATE_unsigned),
ast::TyU16 => ("u16".to_string(), DW_ATE_unsigned),
ast::TyU32 => ("u32".to_string(), DW_ATE_unsigned),
ast::TyU64 => ("u64".to_string(), DW_ATE_unsigned)
},
- ty::ty_float(float_ty) => match float_ty {
+ ty::TyFloat(float_ty) => match float_ty {
ast::TyF32 => ("f32".to_string(), DW_ATE_float),
ast::TyF64 => ("f64".to_string(), DW_ATE_float),
},
let mut fields = ty::struct_fields(cx.tcx(), def_id, substs);
// The `Ty` values returned by `ty::struct_fields` can still contain
- // `ty_projection` variants, so normalize those away.
+ // `TyProjection` variants, so normalize those away.
for field in &mut fields {
field.mt.ty = monomorphize::normalize_associated_type(cx.tcx(), &field.mt.ty);
}
// Build an array of (field name, field type) pairs to be captured in the factory closure.
let args: Vec<(String, Ty)> = arg_names.iter()
- .zip(struct_def.fields.iter())
+ .zip(&struct_def.fields)
.map(|(s, &t)| (s.to_string(), t))
.collect();
DIB(cx),
containing_scope,
enum_name.as_ptr(),
- UNKNOWN_FILE_METADATA,
+ file_metadata,
UNKNOWN_LINE_NUMBER,
bytes_to_bits(enum_type_size),
bytes_to_bits(enum_type_align),
use llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilderRef, DISubprogram, DIArray,
DIDescriptor, FlagPrototyped};
use middle::subst::{self, Substs};
+use rustc::ast_map;
use trans::common::{NodeIdAndSpan, CrateContext, FunctionContext, Block};
use trans;
use trans::monomorphize;
use std::ptr;
use std::rc::Rc;
use syntax::codemap::{Span, Pos};
-use syntax::{ast, codemap, ast_util, ast_map};
+use syntax::{ast, codemap, ast_util};
use syntax::parse::token::{self, special_idents};
pub mod gdb;
// Prevent bitcode readers from deleting the debug info.
let ptr = "Debug Info Version\0".as_ptr();
llvm::LLVMRustAddModuleFlag(cx.llmod(), ptr as *const _,
- llvm::LLVMRustDebugMetadataVersion);
+ llvm::LLVMRustDebugMetadataVersion());
};
}
}
match item.node {
- ast::ItemFn(ref fn_decl, _, _, ref generics, ref top_level_block) => {
+ ast::ItemFn(ref fn_decl, _, _, _, ref generics, ref top_level_block) => {
(item.ident.name, fn_decl, generics, top_level_block, item.span, true)
}
_ => {
// Get_template_parameters() will append a `<...>` clause to the function
// name if necessary.
- let mut function_name = String::from_str(&token::get_name(name));
+ let mut function_name = String::from(&*token::get_name(name));
let template_parameters = get_template_parameters(cx,
generics,
param_substs,
let param_metadata = unsafe {
llvm::LLVMDIBuilderCreateTemplateTypeParameter(
DIB(cx),
- file_metadata,
+ ptr::null_mut(),
name.as_ptr(),
actual_self_type_metadata,
- ptr::null_mut(),
+ file_metadata,
0,
0)
};
let param_metadata = unsafe {
llvm::LLVMDIBuilderCreateTemplateTypeParameter(
DIB(cx),
- file_metadata,
+ ptr::null_mut(),
name.as_ptr(),
actual_type_metadata,
- ptr::null_mut(),
+ file_metadata,
0,
0)
};
loc.line,
loc.col.to_usize()));
unsafe {
+ let debug_loc = llvm::LLVMGetCurrentDebugLocation(cx.raw_builder());
let instr = llvm::LLVMDIBuilderInsertDeclareAtEnd(
DIB(cx),
alloca,
metadata,
address_operations.as_ptr(),
address_operations.len() as c_uint,
+ debug_loc,
bcx.llbb);
llvm::LLVMSetInstDebugLocation(trans::build::B(bcx).llbuilder, instr);
use llvm;
use llvm::debuginfo::DIScope;
+use rustc::ast_map;
use trans::common::CrateContext;
use middle::ty::{self, ClosureTyper};
use std::ffi::CString;
use std::ptr;
use std::rc::{Rc, Weak};
-use syntax::{ast, ast_map};
+use syntax::ast;
use syntax::parse::token;
pub struct NamespaceTreeNode {
output.push_str(&string);
}
- let mut name = String::from_str("_ZN");
+ let mut name = String::from("_ZN");
fill_nested(self, &mut name);
name.push_str(&format!("{}", item_name.len()));
name.push_str(item_name);
use trans::common::CrateContext;
use middle::subst::{self, Substs};
use middle::ty::{self, Ty, ClosureTyper};
+
use syntax::ast;
use syntax::parse::token;
-use util::ppaux;
// Compute the name of the type as it should be stored in debuginfo. Does not do
qualified: bool,
output: &mut String) {
match t.sty {
- ty::ty_bool => output.push_str("bool"),
- ty::ty_char => output.push_str("char"),
- ty::ty_str => output.push_str("str"),
- ty::ty_int(ast::TyIs) => output.push_str("isize"),
- ty::ty_int(ast::TyI8) => output.push_str("i8"),
- ty::ty_int(ast::TyI16) => output.push_str("i16"),
- ty::ty_int(ast::TyI32) => output.push_str("i32"),
- ty::ty_int(ast::TyI64) => output.push_str("i64"),
- ty::ty_uint(ast::TyUs) => output.push_str("usize"),
- ty::ty_uint(ast::TyU8) => output.push_str("u8"),
- ty::ty_uint(ast::TyU16) => output.push_str("u16"),
- ty::ty_uint(ast::TyU32) => output.push_str("u32"),
- ty::ty_uint(ast::TyU64) => output.push_str("u64"),
- ty::ty_float(ast::TyF32) => output.push_str("f32"),
- ty::ty_float(ast::TyF64) => output.push_str("f64"),
- ty::ty_struct(def_id, substs) |
- ty::ty_enum(def_id, substs) => {
+ ty::TyBool => output.push_str("bool"),
+ ty::TyChar => output.push_str("char"),
+ ty::TyStr => output.push_str("str"),
+ ty::TyInt(ast::TyIs) => output.push_str("isize"),
+ ty::TyInt(ast::TyI8) => output.push_str("i8"),
+ ty::TyInt(ast::TyI16) => output.push_str("i16"),
+ ty::TyInt(ast::TyI32) => output.push_str("i32"),
+ ty::TyInt(ast::TyI64) => output.push_str("i64"),
+ ty::TyUint(ast::TyUs) => output.push_str("usize"),
+ ty::TyUint(ast::TyU8) => output.push_str("u8"),
+ ty::TyUint(ast::TyU16) => output.push_str("u16"),
+ ty::TyUint(ast::TyU32) => output.push_str("u32"),
+ ty::TyUint(ast::TyU64) => output.push_str("u64"),
+ ty::TyFloat(ast::TyF32) => output.push_str("f32"),
+ ty::TyFloat(ast::TyF64) => output.push_str("f64"),
+ ty::TyStruct(def_id, substs) |
+ ty::TyEnum(def_id, substs) => {
push_item_name(cx, def_id, qualified, output);
push_type_params(cx, substs, output);
},
- ty::ty_tup(ref component_types) => {
+ ty::TyTuple(ref component_types) => {
output.push('(');
for &component_type in component_types {
push_debuginfo_type_name(cx, component_type, true, output);
}
output.push(')');
},
- ty::ty_uniq(inner_type) => {
+ ty::TyBox(inner_type) => {
output.push_str("Box<");
push_debuginfo_type_name(cx, inner_type, true, output);
output.push('>');
},
- ty::ty_ptr(ty::mt { ty: inner_type, mutbl } ) => {
+ ty::TyRawPtr(ty::mt { ty: inner_type, mutbl } ) => {
output.push('*');
match mutbl {
ast::MutImmutable => output.push_str("const "),
push_debuginfo_type_name(cx, inner_type, true, output);
},
- ty::ty_rptr(_, ty::mt { ty: inner_type, mutbl }) => {
+ ty::TyRef(_, ty::mt { ty: inner_type, mutbl }) => {
output.push('&');
if mutbl == ast::MutMutable {
output.push_str("mut ");
push_debuginfo_type_name(cx, inner_type, true, output);
},
- ty::ty_vec(inner_type, optional_length) => {
+ ty::TyArray(inner_type, len) => {
+ output.push('[');
+ push_debuginfo_type_name(cx, inner_type, true, output);
+ output.push_str(&format!("; {}", len));
+ output.push(']');
+ },
+ ty::TySlice(inner_type) => {
output.push('[');
push_debuginfo_type_name(cx, inner_type, true, output);
-
- match optional_length {
- Some(len) => {
- output.push_str(&format!("; {}", len));
- }
- None => { /* nothing to do */ }
- };
-
output.push(']');
},
- ty::ty_trait(ref trait_data) => {
+ ty::TyTrait(ref trait_data) => {
let principal = ty::erase_late_bound_regions(cx.tcx(), &trait_data.principal);
push_item_name(cx, principal.def_id, false, output);
push_type_params(cx, principal.substs, output);
},
- ty::ty_bare_fn(_, &ty::BareFnTy{ unsafety, abi, ref sig } ) => {
+ ty::TyBareFn(_, &ty::BareFnTy{ unsafety, abi, ref sig } ) => {
if unsafety == ast::Unsafety::Unsafe {
output.push_str("unsafe ");
}
}
}
},
- ty::ty_closure(..) => {
+ ty::TyClosure(..) => {
output.push_str("closure");
}
- ty::ty_err |
- ty::ty_infer(_) |
- ty::ty_projection(..) |
- ty::ty_param(_) => {
+ ty::TyError |
+ ty::TyInfer(_) |
+ ty::TyProjection(..) |
+ ty::TyParam(_) => {
cx.sess().bug(&format!("debuginfo: Trying to create type name for \
- unexpected type: {}", ppaux::ty_to_string(cx.tcx(), t)));
+ unexpected type: {:?}", t));
}
}
output.push('<');
- for &type_parameter in substs.types.iter() {
+ for &type_parameter in &substs.types {
push_debuginfo_type_name(cx, type_parameter, true, output);
output.push_str(", ");
}
// except according to those terms.
//! Declare various LLVM values.
//!
-//! Prefer using functions and methods from this module rather than calling LLVM functions
-//! directly. These functions do some additional work to ensure we do the right thing given
-//! the preconceptions of trans.
+//! Prefer using functions and methods from this module rather than calling LLVM
+//! functions directly. These functions do some additional work to ensure we do
+//! the right thing given the preconceptions of trans.
//!
//! Some useful guidelines:
//!
-//! * Use declare_* family of methods if you are declaring, but are not interested in defining the
-//! ValueRef they return.
+//! * Use declare_* family of methods if you are declaring, but are not
+//! interested in defining the ValueRef they return.
//! * Use define_* family of methods when you might be defining the ValueRef.
//! * When in doubt, define.
use llvm::{self, ValueRef};
use trans::monomorphize;
use trans::type_::Type;
use trans::type_of;
-use util::ppaux::Repr;
use std::ffi::CString;
use libc::c_uint;
/// Declare a global value.
///
-/// If there’s a value with the same name already declared, the function will return its ValueRef
-/// instead.
+/// If there’s a value with the same name already declared, the function will
+/// return its ValueRef instead.
pub fn declare_global(ccx: &CrateContext, name: &str, ty: Type) -> llvm::ValueRef {
debug!("declare_global(name={:?})", name);
let namebuf = CString::new(name).unwrap_or_else(|_|{
///
/// For rust functions use `declare_rust_fn` instead.
///
-/// If there’s a value with the same name already declared, the function will update the
-/// declaration and return existing ValueRef instead.
-pub fn declare_fn(ccx: &CrateContext, name: &str, callconv: llvm::CallConv, ty: Type,
- output: ty::FnOutput) -> ValueRef {
+/// If there’s a value with the same name already declared, the function will
+/// update the declaration and return existing ValueRef instead.
+pub fn declare_fn(ccx: &CrateContext, name: &str, callconv: llvm::CallConv,
+ ty: Type, output: ty::FnOutput) -> ValueRef {
debug!("declare_fn(name={:?})", name);
let namebuf = CString::new(name).unwrap_or_else(|_|{
ccx.sess().bug(&format!("name {:?} contains an interior null byte", name))
};
llvm::SetFunctionCallConv(llfn, callconv);
- // Function addresses in Rust are never significant, allowing functions to be merged.
+ // Function addresses in Rust are never significant, allowing functions to
+ // be merged.
llvm::SetUnnamedAddr(llfn, true);
if output == ty::FnDiverging {
/// Declare a C ABI function.
///
-/// Only use this for foreign function ABIs and glue. For Rust functions use `declare_rust_fn`
-/// instead.
+/// Only use this for foreign function ABIs and glue. For Rust functions use
+/// `declare_rust_fn` instead.
///
-/// If there’s a value with the same name already declared, the function will update the
-/// declaration and return existing ValueRef instead.
-pub fn declare_cfn(ccx: &CrateContext, name: &str, fn_type: Type, output: ty::Ty) -> ValueRef {
+/// If there’s a value with the same name already declared, the function will
+/// update the declaration and return existing ValueRef instead.
+pub fn declare_cfn(ccx: &CrateContext, name: &str, fn_type: Type,
+ output: ty::Ty) -> ValueRef {
declare_fn(ccx, name, llvm::CCallConv, fn_type, ty::FnConverging(output))
}
/// Declare a Rust function.
///
-/// If there’s a value with the same name already declared, the function will update the
-/// declaration and return existing ValueRef instead.
+/// If there’s a value with the same name already declared, the function will
+/// update the declaration and return existing ValueRef instead.
pub fn declare_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
fn_type: ty::Ty<'tcx>) -> ValueRef {
- debug!("declare_rust_fn(name={:?}, fn_type={})", name, fn_type.repr(ccx.tcx()));
+ debug!("declare_rust_fn(name={:?}, fn_type={:?})", name,
+ fn_type);
let fn_type = monomorphize::normalize_associated_type(ccx.tcx(), &fn_type);
- debug!("declare_rust_fn (after normalised associated types) fn_type={}",
- fn_type.repr(ccx.tcx()));
+ debug!("declare_rust_fn (after normalised associated types) fn_type={:?}",
+ fn_type);
let function_type; // placeholder so that the memory ownership works out ok
let (sig, abi, env) = match fn_type.sty {
- ty::ty_bare_fn(_, ref f) => {
+ ty::TyBareFn(_, ref f) => {
(&f.sig, f.abi, None)
}
- ty::ty_closure(closure_did, substs) => {
+ ty::TyClosure(closure_did, substs) => {
let typer = common::NormalizingClosureTyper::new(ccx.tcx());
function_type = typer.closure_type(closure_did, substs);
let self_type = base::self_type_for_closure(ccx, closure_did, fn_type);
let llenvironment_type = type_of::type_of_explicit_arg(ccx, self_type);
- debug!("declare_rust_fn function_type={} self_type={}",
- function_type.repr(ccx.tcx()), self_type.repr(ccx.tcx()));
+ debug!("declare_rust_fn function_type={:?} self_type={:?}",
+ function_type, self_type);
(&function_type.sig, abi::RustCall, Some(llenvironment_type))
}
_ => ccx.sess().bug("expected closure or fn")
};
let sig = ty::Binder(ty::erase_late_bound_regions(ccx.tcx(), sig));
- debug!("declare_rust_fn (after region erasure) sig={}", sig.repr(ccx.tcx()));
+ debug!("declare_rust_fn (after region erasure) sig={:?}", sig);
let llfty = type_of::type_of_rust_fn(ccx, env, &sig, abi);
debug!("declare_rust_fn llfty={}", ccx.tn().type_to_string(llfty));
- // it is ok to directly access sig.0.output because we erased all late-bound-regions above
+ // it is ok to directly access sig.0.output because we erased all
+ // late-bound-regions above
let llfn = declare_fn(ccx, name, llvm::CCallConv, llfty, sig.0.output);
attributes::from_fn_type(ccx, fn_type).apply_llfn(llfn);
llfn
/// Declare a Rust function with internal linkage.
///
-/// If there’s a value with the same name already declared, the function will update the
-/// declaration and return existing ValueRef instead.
+/// If there’s a value with the same name already declared, the function will
+/// update the declaration and return existing ValueRef instead.
pub fn declare_internal_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
fn_type: ty::Ty<'tcx>) -> ValueRef {
let llfn = declare_rust_fn(ccx, name, fn_type);
/// Declare a global with an intention to define it.
///
-/// Use this function when you intend to define a global. This function will return None if the
-/// name already has a definition associated with it. In that case an error should be reported to
-/// the user, because it usually happens due to user’s fault (e.g. misuse of #[no_mangle] or
-/// #[export_name] attributes).
+/// Use this function when you intend to define a global. This function will
+/// return None if the name already has a definition associated with it. In that
+/// case an error should be reported to the user, because it usually happens due
+/// to user’s fault (e.g. misuse of #[no_mangle] or #[export_name] attributes).
pub fn define_global(ccx: &CrateContext, name: &str, ty: Type) -> Option<ValueRef> {
if get_defined_value(ccx, name).is_some() {
None
///
/// For rust functions use `define_rust_fn` instead.
///
-/// Use this function when you intend to define a function. This function will return None if the
-/// name already has a definition associated with it. In that case an error should be reported to
-/// the user, because it usually happens due to user’s fault (e.g. misuse of #[no_mangle] or
-/// #[export_name] attributes).
+/// Use this function when you intend to define a function. This function will
+/// return None if the name already has a definition associated with it. In that
+/// case an error should be reported to the user, because it usually happens due
+/// to user’s fault (e.g. misuse of #[no_mangle] or #[export_name] attributes).
pub fn define_fn(ccx: &CrateContext, name: &str, callconv: llvm::CallConv, fn_type: Type,
output: ty::FnOutput) -> Option<ValueRef> {
if get_defined_value(ccx, name).is_some() {
/// Declare a C ABI function with an intention to define it.
///
-/// Use this function when you intend to define a function. This function will return None if the
-/// name already has a definition associated with it. In that case an error should be reported to
-/// the user, because it usually happens due to user’s fault (e.g. misuse of #[no_mangle] or
-/// #[export_name] attributes).
+/// Use this function when you intend to define a function. This function will
+/// return None if the name already has a definition associated with it. In that
+/// case an error should be reported to the user, because it usually happens due
+/// to user’s fault (e.g. misuse of #[no_mangle] or #[export_name] attributes).
///
-/// Only use this for foreign function ABIs and glue. For Rust functions use `declare_rust_fn`
-/// instead.
+/// Only use this for foreign function ABIs and glue. For Rust functions use
+/// `declare_rust_fn` instead.
pub fn define_cfn(ccx: &CrateContext, name: &str, fn_type: Type,
output: ty::Ty) -> Option<ValueRef> {
if get_defined_value(ccx, name).is_some() {
/// Declare a Rust function with an intention to define it.
///
-/// Use this function when you intend to define a function. This function will return None if the
-/// name already has a definition associated with it. In that case an error should be reported to
-/// the user, because it usually happens due to user’s fault (e.g. misuse of #[no_mangle] or
-/// #[export_name] attributes).
+/// Use this function when you intend to define a function. This function will
+/// return None if the name already has a definition associated with it. In that
+/// case an error should be reported to the user, because it usually happens due
+/// to user’s fault (e.g. misuse of #[no_mangle] or #[export_name] attributes).
pub fn define_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
fn_type: ty::Ty<'tcx>) -> Option<ValueRef> {
if get_defined_value(ccx, name).is_some() {
/// Declare a Rust function with an intention to define it.
///
-/// Use this function when you intend to define a function. This function will return None if the
-/// name already has a definition associated with it. In that case an error should be reported to
-/// the user, because it usually happens due to user’s fault (e.g. misuse of #[no_mangle] or
-/// #[export_name] attributes).
+/// Use this function when you intend to define a function. This function will
+/// return None if the name already has a definition associated with it. In that
+/// case an error should be reported to the user, because it usually happens due
+/// to user’s fault (e.g. misuse of #[no_mangle] or #[export_name] attributes).
pub fn define_internal_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
fn_type: ty::Ty<'tcx>) -> Option<ValueRef> {
if get_defined_value(ccx, name).is_some() {
(llvm::LLVMIsDeclaration(val) != 0,
linkage == llvm::AvailableExternallyLinkage as c_uint)
};
- debug!("get_defined_value: found {:?} value (declaration: {}, aext_link: {})", name,
- declaration, aext_link);
+ debug!("get_defined_value: found {:?} value (declaration: {}, \
+ aext_link: {})", name, declaration, aext_link);
if !declaration || aext_link {
Some(val)
} else {
#![allow(non_camel_case_types)]
-pub use self::cast_kind::*;
pub use self::Dest::*;
use self::lazy_binop_ty::*;
use back::abi;
-use llvm::{self, ValueRef};
+use llvm::{self, ValueRef, TypeKind};
use middle::check_const;
use middle::def;
use middle::lang_items::CoerceUnsizedTraitLangItem;
use trans::monomorphize;
use trans::tvec;
use trans::type_of;
+use middle::cast::{CastKind, CastTy};
use middle::ty::{struct_fields, tup_fields};
use middle::ty::{AdjustDerefRef, AdjustReifyFnPointer, AdjustUnsafeFnPointer};
use middle::ty::{self, Ty};
use middle::ty::MethodCall;
use util::common::indenter;
-use util::ppaux::Repr;
use trans::machine::{llsize_of, llsize_of_alloc};
use trans::type_::Type;
// have different types.
let lldest = PointerCast(bcx, lldest, val_ty(global));
memcpy_ty(bcx, lldest, global, expr_ty_adjusted(bcx, expr));
+ return bcx;
}
- // Don't do anything in the Ignore case, consts don't need drop.
- return bcx;
+ // Even if we don't have a value to emit, and the expression
+ // doesn't have any side-effects, we still have to translate the
+ // body of any closures.
+ // FIXME: Find a better way of handling this case.
} else {
// The only way we're going to see a `const` at this point is if
// it prefers in-place instantiation, likely because it contains
}
}
- debug!("trans_into() expr={}", expr.repr(bcx.tcx()));
+ debug!("trans_into() expr={:?}", expr);
let cleanup_debug_loc = debuginfo::get_cleanup_debug_loc_for_ast_node(bcx.ccx(),
expr.id,
false);
bcx.fcx.push_ast_cleanup_scope(cleanup_debug_loc);
- let kind = ty::expr_kind(bcx.tcx(), expr);
+ let kind = expr_kind(bcx.tcx(), expr);
bcx = match kind {
- ty::LvalueExpr | ty::RvalueDatumExpr => {
+ ExprKind::Lvalue | ExprKind::RvalueDatum => {
trans_unadjusted(bcx, expr).store_to_dest(dest, expr.id)
}
- ty::RvalueDpsExpr => {
+ ExprKind::RvalueDps => {
trans_rvalue_dps_unadjusted(bcx, expr, dest)
}
- ty::RvalueStmtExpr => {
+ ExprKind::RvalueStmt => {
trans_rvalue_stmt_unadjusted(bcx, expr)
}
};
pub fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
expr: &ast::Expr)
-> DatumBlock<'blk, 'tcx, Expr> {
- debug!("trans(expr={})", bcx.expr_to_string(expr));
+ debug!("trans(expr={:?})", expr);
let mut bcx = bcx;
let fcx = bcx.fcx;
GEPi(bcx, fat_ptr, &[0, abi::FAT_PTR_ADDR])
}
+pub fn make_fat_ptr(bcx: Block, ty: Type, data: ValueRef, extra: ValueRef) -> ValueRef {
+ InsertValue(bcx, InsertValue(bcx, C_undef(ty), data, 0), extra, 1)
+}
pub fn copy_fat_ptr(bcx: Block, src_ptr: ValueRef, dst_ptr: ValueRef) {
Store(bcx, Load(bcx, get_dataptr(bcx, src_ptr)), get_dataptr(bcx, dst_ptr));
Store(bcx, Load(bcx, get_len(bcx, src_ptr)), get_len(bcx, dst_ptr));
-> ValueRef {
let (source, target) = ty::struct_lockstep_tails(ccx.tcx(), source, target);
match (&source.sty, &target.sty) {
- (&ty::ty_vec(_, Some(len)), &ty::ty_vec(_, None)) => C_uint(ccx, len),
- (&ty::ty_trait(_), &ty::ty_trait(_)) => {
+ (&ty::TyArray(_, len), &ty::TySlice(_)) => C_uint(ccx, len),
+ (&ty::TyTrait(_), &ty::TyTrait(_)) => {
// For now, upcasts are limited to changes in marker
// traits, and hence never actually require an actual
// change to the vtable.
old_info.expect("unsized_info: missing old info for trait upcast")
}
- (_, &ty::ty_trait(box ty::TyTrait { ref principal, .. })) => {
+ (_, &ty::TyTrait(box ty::TraitTy { ref principal, .. })) => {
// Note that we preserve binding levels here:
let substs = principal.0.substs.with_self_ty(source).erase_regions();
let substs = ccx.tcx().mk_substs(substs);
consts::ptrcast(meth::get_vtable(ccx, trait_ref, param_substs),
Type::vtable_ptr(ccx))
}
- _ => ccx.sess().bug(&format!("unsized_info: invalid unsizing {} -> {}",
- source.repr(ccx.tcx()),
- target.repr(ccx.tcx())))
+ _ => ccx.sess().bug(&format!("unsized_info: invalid unsizing {:?} -> {:?}",
+ source,
+ target))
}
}
}
Some(adj) => { adj }
};
- debug!("unadjusted datum for expr {}: {} adjustment={:?}",
- expr.repr(bcx.tcx()),
+ debug!("unadjusted datum for expr {:?}: {} adjustment={:?}",
+ expr,
datum.to_string(bcx.ccx()),
adjustment);
match adjustment {
// a different region or mutability, but we don't care here).
match datum.ty.sty {
// Don't skip a conversion from Box<T> to &T, etc.
- ty::ty_rptr(..) => {
+ ty::TyRef(..) => {
let method_call = MethodCall::autoderef(expr.id, 0);
if bcx.tcx().method_map.borrow().contains_key(&method_call) {
// Don't skip an overloaded deref.
target.to_string(bcx.ccx()));
match (&source.ty.sty, &target.ty.sty) {
- (&ty::ty_uniq(a), &ty::ty_uniq(b)) |
- (&ty::ty_rptr(_, ty::mt { ty: a, .. }), &ty::ty_rptr(_, ty::mt { ty: b, .. })) |
- (&ty::ty_rptr(_, ty::mt { ty: a, .. }), &ty::ty_ptr(ty::mt { ty: b, .. })) |
- (&ty::ty_ptr(ty::mt { ty: a, .. }), &ty::ty_ptr(ty::mt { ty: b, .. })) => {
+ (&ty::TyBox(a), &ty::TyBox(b)) |
+ (&ty::TyRef(_, ty::mt { ty: a, .. }), &ty::TyRef(_, ty::mt { ty: b, .. })) |
+ (&ty::TyRef(_, ty::mt { ty: a, .. }), &ty::TyRawPtr(ty::mt { ty: b, .. })) |
+ (&ty::TyRawPtr(ty::mt { ty: a, .. }), &ty::TyRawPtr(ty::mt { ty: b, .. })) => {
let (inner_source, inner_target) = (a, b);
let (base, old_info) = if !type_is_sized(bcx.tcx(), inner_source) {
}
// This can be extended to enums and tuples in the future.
- // (&ty::ty_enum(def_id_a, _), &ty::ty_enum(def_id_b, _)) |
- (&ty::ty_struct(def_id_a, _), &ty::ty_struct(def_id_b, _)) => {
+ // (&ty::TyEnum(def_id_a, _), &ty::TyEnum(def_id_b, _)) |
+ (&ty::TyStruct(def_id_a, _), &ty::TyStruct(def_id_b, _)) => {
assert_eq!(def_id_a, def_id_b);
// The target is already by-ref because it's to be written to.
ty::custom_coerce_unsized_kind(bcx.tcx(), impl_def_id)
}
vtable => {
- bcx.sess().span_bug(span, &format!("invalid CoerceUnsized vtable: {}",
- vtable.repr(bcx.tcx())));
+ bcx.sess().span_bug(span, &format!("invalid CoerceUnsized vtable: {:?}",
+ vtable));
}
};
};
assert!(coerce_index < src_fields.len() && src_fields.len() == target_fields.len());
- let iter = src_fields.iter().zip(target_fields.iter()).enumerate();
+ let iter = src_fields.iter().zip(target_fields).enumerate();
for (i, (src_ty, target_ty)) in iter {
let ll_source = adt::trans_field_ptr(bcx, &repr_source, source.val, 0, i);
let ll_target = adt::trans_field_ptr(bcx, &repr_target, target.val, 0, i);
}
}
}
- _ => bcx.sess().bug(&format!("coerce_unsized: invalid coercion {} -> {}",
- source.ty.repr(bcx.tcx()),
- target.ty.repr(bcx.tcx())))
+ _ => bcx.sess().bug(&format!("coerce_unsized: invalid coercion {:?} -> {:?}",
+ source.ty,
+ target.ty))
}
bcx
}
-> DatumBlock<'blk, 'tcx, Expr> {
let mut bcx = bcx;
- debug!("trans_unadjusted(expr={})", bcx.expr_to_string(expr));
+ debug!("trans_unadjusted(expr={:?})", expr);
let _indenter = indenter();
debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
- return match ty::expr_kind(bcx.tcx(), expr) {
- ty::LvalueExpr | ty::RvalueDatumExpr => {
+ return match expr_kind(bcx.tcx(), expr) {
+ ExprKind::Lvalue | ExprKind::RvalueDatum => {
let datum = unpack_datum!(bcx, {
trans_datum_unadjusted(bcx, expr)
});
DatumBlock {bcx: bcx, datum: datum}
}
- ty::RvalueStmtExpr => {
+ ExprKind::RvalueStmt => {
bcx = trans_rvalue_stmt_unadjusted(bcx, expr);
nil(bcx, expr_ty(bcx, expr))
}
- ty::RvalueDpsExpr => {
+ ExprKind::RvalueDps => {
let ty = expr_ty(bcx, expr);
if type_is_zero_size(bcx.ccx(), ty) {
bcx = trans_rvalue_dps_unadjusted(bcx, expr, Ignore);
let box_ty = expr_ty(bcx, expr);
let contents_ty = expr_ty(bcx, &**contents);
match box_ty.sty {
- ty::ty_uniq(..) => {
+ ty::TyBox(..) => {
trans_uniq_expr(bcx, expr, box_ty, &**contents, contents_ty)
}
_ => bcx.sess().span_bug(expr.span,
let info = Load(bcx, get_len(bcx, base_datum.val));
Store(bcx, info, get_len(bcx, scratch.val));
- DatumBlock::new(bcx, scratch.to_expr_datum())
-
+ // Always generate an lvalue datum, because this pointer doesn't own
+ // the data and cleanup is scheduled elsewhere.
+ DatumBlock::new(bcx, Datum::new(scratch.val, scratch.ty, LvalueExpr))
}
})
SaveIn(lldest) => closure::Dest::SaveIn(bcx, lldest),
Ignore => closure::Dest::Ignore(bcx.ccx())
};
- closure::trans_closure_expr(dest, &**decl, &**body, expr.id, bcx.fcx.param_substs)
+ closure::trans_closure_expr(dest, decl, body, expr.id, bcx.fcx.param_substs)
.unwrap_or(bcx)
}
ast::ExprCall(ref f, ref args) => {
def::DefStruct(_) => {
let ty = expr_ty(bcx, ref_expr);
match ty.sty {
- ty::ty_struct(did, _) if ty::has_dtor(bcx.tcx(), did) => {
+ ty::TyStruct(did, _) if ty::has_dtor(bcx.tcx(), did) => {
let repr = adt::represent_type(bcx.ccx(), ty);
adt::trans_set_discr(bcx, &*repr, lldest, 0);
}
}
_ => {
ccx.tcx().sess.span_bug(ref_expr.span, &format!(
- "trans_def_fn_unadjusted invoked on: {:?} for {}",
+ "trans_def_fn_unadjusted invoked on: {:?} for {:?}",
def,
- ref_expr.repr(ccx.tcx())));
+ ref_expr));
}
}
}
}
};
debug!("take_local(nid={}, v={}, ty={})",
- nid, bcx.val_to_string(datum.val), bcx.ty_to_string(datum.ty));
+ nid, bcx.val_to_string(datum.val), datum.ty);
datum
}
_ => {
F: FnOnce(ty::Disr, &[ty::field<'tcx>]) -> R,
{
match ty.sty {
- ty::ty_struct(did, substs) => {
+ ty::TyStruct(did, substs) => {
let fields = struct_fields(tcx, did, substs);
let fields = monomorphize::normalize_associated_type(tcx, &fields);
op(0, &fields[..])
}
- ty::ty_tup(ref v) => {
+ ty::TyTuple(ref v) => {
op(0, &tup_fields(&v[..]))
}
- ty::ty_enum(_, substs) => {
+ ty::TyEnum(_, substs) => {
// We want the *variant* ID here, not the enum ID.
match node_id_opt {
None => {
tcx.sess.bug(&format!(
- "cannot get field types from the enum type {} \
+ "cannot get field types from the enum type {:?} \
without a node ID",
- ty.repr(tcx)));
+ ty));
}
Some(node_id) => {
let def = tcx.def_map.borrow().get(&node_id).unwrap().full_def();
_ => {
tcx.sess.bug(&format!(
- "cannot get field types from the type {}",
- ty.repr(tcx)));
+ "cannot get field types from the type {:?}",
+ ty));
}
}
}
// Second, trans the base to the dest.
assert_eq!(discr, 0);
- match ty::expr_kind(bcx.tcx(), &*base.expr) {
- ty::RvalueDpsExpr | ty::RvalueDatumExpr if !bcx.fcx.type_needs_drop(ty) => {
+ match expr_kind(bcx.tcx(), &*base.expr) {
+ ExprKind::RvalueDps | ExprKind::RvalueDatum if !bcx.fcx.type_needs_drop(ty) => {
bcx = trans_into(bcx, &*base.expr, SaveIn(addr));
},
- ty::RvalueStmtExpr => bcx.tcx().sess.bug("unexpected expr kind for struct base expr"),
+ ExprKind::RvalueStmt => {
+ bcx.tcx().sess.bug("unexpected expr kind for struct base expr")
+ }
_ => {
let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, &*base.expr, "base"));
for &(i, t) in &base.fields {
}
// Finally, move scratch field values into actual field locations
- for (i, datum) in scratch_vals.into_iter() {
+ for (i, datum) in scratch_vals {
let dest = adt::trans_field_ptr(bcx, &*repr, addr, discr, i);
bcx = datum.store_to(bcx, dest);
}
args: &'a [P<ast::Expr>],
dest: Option<Dest>)
-> Block<'blk, 'tcx> {
+ debug!("trans_overloaded_call {}", expr.id);
let method_call = MethodCall::expr(expr.id);
let method_type = bcx.tcx()
.method_map
bcx
}
-fn int_cast(bcx: Block,
- lldsttype: Type,
- llsrctype: Type,
- llsrc: ValueRef,
- signed: bool)
- -> ValueRef {
- let _icx = push_ctxt("int_cast");
- let srcsz = llsrctype.int_width();
- let dstsz = lldsttype.int_width();
- return if dstsz == srcsz {
- BitCast(bcx, llsrc, lldsttype)
- } else if srcsz > dstsz {
- TruncOrBitCast(bcx, llsrc, lldsttype)
- } else if signed {
- SExtOrBitCast(bcx, llsrc, lldsttype)
- } else {
- ZExtOrBitCast(bcx, llsrc, lldsttype)
+pub fn cast_is_noop<'tcx>(tcx: &ty::ctxt<'tcx>,
+ expr: &ast::Expr,
+ t_in: Ty<'tcx>,
+ t_out: Ty<'tcx>)
+ -> bool {
+ if let Some(&CastKind::CoercionCast) = tcx.cast_kinds.borrow().get(&expr.id) {
+ return true;
}
-}
-
-fn float_cast(bcx: Block,
- lldsttype: Type,
- llsrctype: Type,
- llsrc: ValueRef)
- -> ValueRef {
- let _icx = push_ctxt("float_cast");
- let srcsz = llsrctype.float_width();
- let dstsz = lldsttype.float_width();
- return if dstsz > srcsz {
- FPExt(bcx, llsrc, lldsttype)
- } else if srcsz > dstsz {
- FPTrunc(bcx, llsrc, lldsttype)
- } else { llsrc };
-}
-
-#[derive(Copy, Clone, PartialEq, Debug)]
-pub enum cast_kind {
- cast_pointer,
- cast_fat_ptr,
- cast_integral,
- cast_float,
- cast_enum,
- cast_other,
-}
-pub fn cast_type_kind<'tcx>(tcx: &ty::ctxt<'tcx>, t: Ty<'tcx>) -> cast_kind {
- match t.sty {
- ty::ty_char => cast_integral,
- ty::ty_float(..) => cast_float,
- ty::ty_rptr(_, mt) | ty::ty_ptr(mt) => {
- if type_is_sized(tcx, mt.ty) {
- cast_pointer
- } else {
- cast_fat_ptr
- }
- }
- ty::ty_bare_fn(..) => cast_pointer,
- ty::ty_int(..) => cast_integral,
- ty::ty_uint(..) => cast_integral,
- ty::ty_bool => cast_integral,
- ty::ty_enum(..) => cast_enum,
- _ => cast_other
- }
-}
-
-pub fn cast_is_noop<'tcx>(t_in: Ty<'tcx>, t_out: Ty<'tcx>) -> bool {
match (ty::deref(t_in, true), ty::deref(t_out, true)) {
(Some(ty::mt{ ty: t_in, .. }), Some(ty::mt{ ty: t_out, .. })) => {
t_in == t_out
}
- _ => false
+ _ => {
+ // This condition isn't redundant with the check for CoercionCast:
+ // different types can be substituted into the same type, and
+ // == equality can be overconservative if there are regions.
+ t_in == t_out
+ }
}
}
fn trans_imm_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
expr: &ast::Expr,
id: ast::NodeId)
- -> DatumBlock<'blk, 'tcx, Expr> {
+ -> DatumBlock<'blk, 'tcx, Expr>
+{
+ use middle::cast::CastTy::*;
+ use middle::cast::IntTy::*;
+
+ fn int_cast(bcx: Block,
+ lldsttype: Type,
+ llsrctype: Type,
+ llsrc: ValueRef,
+ signed: bool)
+ -> ValueRef
+ {
+ let _icx = push_ctxt("int_cast");
+ let srcsz = llsrctype.int_width();
+ let dstsz = lldsttype.int_width();
+ return if dstsz == srcsz {
+ BitCast(bcx, llsrc, lldsttype)
+ } else if srcsz > dstsz {
+ TruncOrBitCast(bcx, llsrc, lldsttype)
+ } else if signed {
+ SExtOrBitCast(bcx, llsrc, lldsttype)
+ } else {
+ ZExtOrBitCast(bcx, llsrc, lldsttype)
+ }
+ }
+
+ fn float_cast(bcx: Block,
+ lldsttype: Type,
+ llsrctype: Type,
+ llsrc: ValueRef)
+ -> ValueRef
+ {
+ let _icx = push_ctxt("float_cast");
+ let srcsz = llsrctype.float_width();
+ let dstsz = lldsttype.float_width();
+ return if dstsz > srcsz {
+ FPExt(bcx, llsrc, lldsttype)
+ } else if srcsz > dstsz {
+ FPTrunc(bcx, llsrc, lldsttype)
+ } else { llsrc };
+ }
+
let _icx = push_ctxt("trans_cast");
let mut bcx = bcx;
let ccx = bcx.ccx();
let t_in = expr_ty_adjusted(bcx, expr);
let t_out = node_id_type(bcx, id);
- let k_in = cast_type_kind(bcx.tcx(), t_in);
- let k_out = cast_type_kind(bcx.tcx(), t_out);
- let s_in = k_in == cast_integral && ty::type_is_signed(t_in);
- let ll_t_in = type_of::arg_type_of(ccx, t_in);
- let ll_t_out = type_of::arg_type_of(ccx, t_out);
+ debug!("trans_cast({:?} as {:?})", t_in, t_out);
+ let mut ll_t_in = type_of::arg_type_of(ccx, t_in);
+ let ll_t_out = type_of::arg_type_of(ccx, t_out);
// Convert the value to be cast into a ValueRef, either by-ref or
// by-value as appropriate given its type:
let mut datum = unpack_datum!(bcx, trans(bcx, expr));
let datum_ty = monomorphize_type(bcx, datum.ty);
- if cast_is_noop(datum_ty, t_out) {
+
+ if cast_is_noop(bcx.tcx(), expr, datum_ty, t_out) {
datum.ty = t_out;
return DatumBlock::new(bcx, datum);
}
- let newval = match (k_in, k_out) {
- (cast_integral, cast_integral) => {
- let llexpr = datum.to_llscalarish(bcx);
- int_cast(bcx, ll_t_out, ll_t_in, llexpr, s_in)
- }
- (cast_float, cast_float) => {
- let llexpr = datum.to_llscalarish(bcx);
- float_cast(bcx, ll_t_out, ll_t_in, llexpr)
- }
- (cast_integral, cast_float) => {
- let llexpr = datum.to_llscalarish(bcx);
- if s_in {
- SIToFP(bcx, llexpr, ll_t_out)
- } else { UIToFP(bcx, llexpr, ll_t_out) }
- }
- (cast_float, cast_integral) => {
- let llexpr = datum.to_llscalarish(bcx);
- if ty::type_is_signed(t_out) {
- FPToSI(bcx, llexpr, ll_t_out)
- } else { FPToUI(bcx, llexpr, ll_t_out) }
- }
- (cast_integral, cast_pointer) => {
- let llexpr = datum.to_llscalarish(bcx);
- IntToPtr(bcx, llexpr, ll_t_out)
- }
- (cast_pointer, cast_integral) => {
- let llexpr = datum.to_llscalarish(bcx);
- PtrToInt(bcx, llexpr, ll_t_out)
- }
- (cast_fat_ptr, cast_integral) => {
- let data_ptr = Load(bcx, get_dataptr(bcx, datum.val));
- PtrToInt(bcx, data_ptr, ll_t_out)
- }
- (cast_pointer, cast_pointer) => {
- let llexpr = datum.to_llscalarish(bcx);
- PointerCast(bcx, llexpr, ll_t_out)
- }
- (cast_fat_ptr, cast_pointer) => {
- let data_ptr = Load(bcx, get_dataptr(bcx, datum.val));
- PointerCast(bcx, data_ptr, ll_t_out)
+ if type_is_fat_ptr(bcx.tcx(), t_in) {
+ assert!(datum.kind.is_by_ref());
+ if type_is_fat_ptr(bcx.tcx(), t_out) {
+ return DatumBlock::new(bcx, Datum::new(
+ PointerCast(bcx, datum.val, ll_t_out.ptr_to()),
+ t_out,
+ Rvalue::new(ByRef)
+ )).to_expr_datumblock();
+ } else {
+ // Return the address
+ return immediate_rvalue_bcx(bcx,
+ PointerCast(bcx,
+ Load(bcx, get_dataptr(bcx, datum.val)),
+ ll_t_out),
+ t_out).to_expr_datumblock();
}
- (cast_enum, cast_integral) |
- (cast_enum, cast_float) => {
- let mut bcx = bcx;
- let repr = adt::represent_type(ccx, t_in);
- let datum = unpack_datum!(
- bcx, datum.to_lvalue_datum(bcx, "trans_imm_cast", expr.id));
- let llexpr_ptr = datum.to_llref();
- let lldiscrim_a =
- adt::trans_get_discr(bcx, &*repr, llexpr_ptr, Some(Type::i64(ccx)));
- match k_out {
- cast_integral => int_cast(bcx, ll_t_out,
- val_ty(lldiscrim_a),
- lldiscrim_a, true),
- cast_float => SIToFP(bcx, lldiscrim_a, ll_t_out),
- _ => {
- ccx.sess().bug(&format!("translating unsupported cast: \
- {} ({:?}) -> {} ({:?})",
- t_in.repr(bcx.tcx()),
- k_in,
- t_out.repr(bcx.tcx()),
- k_out))
- }
- }
+ }
+
+ let r_t_in = CastTy::from_ty(bcx.tcx(), t_in).expect("bad input type for cast");
+ let r_t_out = CastTy::from_ty(bcx.tcx(), t_out).expect("bad output type for cast");
+
+ let (llexpr, signed) = if let Int(CEnum) = r_t_in {
+ let repr = adt::represent_type(ccx, t_in);
+ let datum = unpack_datum!(
+ bcx, datum.to_lvalue_datum(bcx, "trans_imm_cast", expr.id));
+ let llexpr_ptr = datum.to_llref();
+ let discr = adt::trans_get_discr(bcx, &*repr, llexpr_ptr, Some(Type::i64(ccx)));
+ ll_t_in = val_ty(discr);
+ (discr, adt::is_discr_signed(&*repr))
+ } else {
+ (datum.to_llscalarish(bcx), ty::type_is_signed(t_in))
+ };
+
+ let newval = match (r_t_in, r_t_out) {
+ (Ptr(_), Ptr(_)) | (FnPtr, Ptr(_)) | (RPtr(_), Ptr(_)) => {
+ PointerCast(bcx, llexpr, ll_t_out)
}
- _ => ccx.sess().bug(&format!("translating unsupported cast: \
- {} ({:?}) -> {} ({:?})",
- t_in.repr(bcx.tcx()),
- k_in,
- t_out.repr(bcx.tcx()),
- k_out))
+ (Ptr(_), Int(_)) | (FnPtr, Int(_)) => PtrToInt(bcx, llexpr, ll_t_out),
+ (Int(_), Ptr(_)) => IntToPtr(bcx, llexpr, ll_t_out),
+
+ (Int(_), Int(_)) => int_cast(bcx, ll_t_out, ll_t_in, llexpr, signed),
+ (Float, Float) => float_cast(bcx, ll_t_out, ll_t_in, llexpr),
+ (Int(_), Float) if signed => SIToFP(bcx, llexpr, ll_t_out),
+ (Int(_), Float) => UIToFP(bcx, llexpr, ll_t_out),
+ (Float, Int(I)) => FPToSI(bcx, llexpr, ll_t_out),
+ (Float, Int(_)) => FPToUI(bcx, llexpr, ll_t_out),
+
+ _ => ccx.sess().span_bug(expr.span,
+ &format!("translating unsupported cast: \
+ {:?} -> {:?}",
+ t_in,
+ t_out)
+ )
};
return immediate_rvalue_bcx(bcx, newval, t_out).to_expr_datumblock();
}
let _icx = push_ctxt("trans_assign_op");
let mut bcx = bcx;
- debug!("trans_assign_op(expr={})", bcx.expr_to_string(expr));
+ debug!("trans_assign_op(expr={:?})", expr);
// User-defined operator methods cannot be used with `+=` etc right now
assert!(!bcx.tcx().method_map.borrow().contains_key(&MethodCall::expr(expr.id)));
// Construct the resulting datum, using what was the "by ref"
// ValueRef of type `referent_ty` to be the "by value" ValueRef
// of type `&referent_ty`.
- DatumBlock::new(bcx, Datum::new(llref, ptr_ty, RvalueExpr(Rvalue::new(ByValue))))
+ // Pointers to DST types are non-immediate, and therefore still use ByRef.
+ let kind = if type_is_sized(bcx.tcx(), referent_ty) { ByValue } else { ByRef };
+ DatumBlock::new(bcx, Datum::new(llref, ptr_ty, RvalueExpr(Rvalue::new(kind))))
}
fn deref_multiple<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-> DatumBlock<'blk, 'tcx, Expr> {
let ccx = bcx.ccx();
- debug!("deref_once(expr={}, datum={}, method_call={:?})",
- expr.repr(bcx.tcx()),
+ debug!("deref_once(expr={:?}, datum={}, method_call={:?})",
+ expr,
datum.to_string(ccx),
method_call);
};
let r = match datum.ty.sty {
- ty::ty_uniq(content_ty) => {
+ ty::TyBox(content_ty) => {
+ // Make sure we have an lvalue datum here to get the
+ // proper cleanups scheduled
+ let datum = unpack_datum!(
+ bcx, datum.to_lvalue_datum(bcx, "deref", expr.id));
+
if type_is_sized(bcx.tcx(), content_ty) {
- deref_owned_pointer(bcx, expr, datum, content_ty)
+ let ptr = load_ty(bcx, datum.val, datum.ty);
+ DatumBlock::new(bcx, Datum::new(ptr, content_ty, LvalueExpr))
} else {
// A fat pointer and a DST lvalue have the same representation
// just different types. Since there is no temporary for `*e`
// here (because it is unsized), we cannot emulate the sized
// object code path for running drop glue and free. Instead,
// we schedule cleanup for `e`, turning it into an lvalue.
- let datum = unpack_datum!(
- bcx, datum.to_lvalue_datum(bcx, "deref", expr.id));
let datum = Datum::new(datum.val, content_ty, LvalueExpr);
DatumBlock::new(bcx, datum)
}
}
- ty::ty_ptr(ty::mt { ty: content_ty, .. }) |
- ty::ty_rptr(_, ty::mt { ty: content_ty, .. }) => {
+ ty::TyRawPtr(ty::mt { ty: content_ty, .. }) |
+ ty::TyRef(_, ty::mt { ty: content_ty, .. }) => {
if type_is_sized(bcx.tcx(), content_ty) {
let ptr = datum.to_llscalarish(bcx);
_ => {
bcx.tcx().sess.span_bug(
expr.span,
- &format!("deref invoked on expr of illegal type {}",
- datum.ty.repr(bcx.tcx())));
+ &format!("deref invoked on expr of illegal type {:?}",
+ datum.ty));
}
};
expr.id, method_call, r.datum.to_string(ccx));
return r;
-
- /// We microoptimize derefs of owned pointers a bit here. Basically, the idea is to make the
- /// deref of an rvalue result in an rvalue. This helps to avoid intermediate stack slots in the
- /// resulting LLVM. The idea here is that, if the `Box<T>` pointer is an rvalue, then we can
- /// schedule a *shallow* free of the `Box<T>` pointer, and then return a ByRef rvalue into the
- /// pointer. Because the free is shallow, it is legit to return an rvalue, because we know that
- /// the contents are not yet scheduled to be freed. The language rules ensure that the contents
- /// will be used (or moved) before the free occurs.
- fn deref_owned_pointer<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
- expr: &ast::Expr,
- datum: Datum<'tcx, Expr>,
- content_ty: Ty<'tcx>)
- -> DatumBlock<'blk, 'tcx, Expr> {
- match datum.kind {
- RvalueExpr(Rvalue { mode: ByRef }) => {
- let scope = cleanup::temporary_scope(bcx.tcx(), expr.id);
- let ptr = Load(bcx, datum.val);
- if !type_is_zero_size(bcx.ccx(), content_ty) {
- bcx.fcx.schedule_free_value(scope, ptr, cleanup::HeapExchange, content_ty);
- }
- }
- RvalueExpr(Rvalue { mode: ByValue }) => {
- let scope = cleanup::temporary_scope(bcx.tcx(), expr.id);
- if !type_is_zero_size(bcx.ccx(), content_ty) {
- bcx.fcx.schedule_free_value(scope, datum.val, cleanup::HeapExchange,
- content_ty);
- }
- }
- LvalueExpr => { }
- }
-
- // If we had an rvalue in, we produce an rvalue out.
- let (llptr, kind) = match datum.kind {
- LvalueExpr => {
- (Load(bcx, datum.val), LvalueExpr)
- }
- RvalueExpr(Rvalue { mode: ByRef }) => {
- (Load(bcx, datum.val), RvalueExpr(Rvalue::new(ByRef)))
- }
- RvalueExpr(Rvalue { mode: ByValue }) => {
- (datum.val, RvalueExpr(Rvalue::new(ByRef)))
- }
- };
-
- let datum = Datum { ty: content_ty, val: llptr, kind: kind };
- DatumBlock { bcx: bcx, datum: datum }
- }
}
#[derive(Debug)]
fn to_intrinsic_name(&self, tcx: &ty::ctxt, ty: Ty) -> &'static str {
use syntax::ast::IntTy::*;
use syntax::ast::UintTy::*;
- use middle::ty::{ty_int, ty_uint};
+ use middle::ty::{TyInt, TyUint};
let new_sty = match ty.sty {
- ty_int(TyIs) => match &tcx.sess.target.target.target_pointer_width[..] {
- "32" => ty_int(TyI32),
- "64" => ty_int(TyI64),
+ TyInt(TyIs) => match &tcx.sess.target.target.target_pointer_width[..] {
+ "32" => TyInt(TyI32),
+ "64" => TyInt(TyI64),
_ => panic!("unsupported target word size")
},
- ty_uint(TyUs) => match &tcx.sess.target.target.target_pointer_width[..] {
- "32" => ty_uint(TyU32),
- "64" => ty_uint(TyU64),
+ TyUint(TyUs) => match &tcx.sess.target.target.target_pointer_width[..] {
+ "32" => TyUint(TyU32),
+ "64" => TyUint(TyU64),
_ => panic!("unsupported target word size")
},
- ref t @ ty_uint(_) | ref t @ ty_int(_) => t.clone(),
+ ref t @ TyUint(_) | ref t @ TyInt(_) => t.clone(),
_ => panic!("tried to get overflow intrinsic for {:?} applied to non-int type",
*self)
};
match *self {
OverflowOpViaIntrinsic::Add => match new_sty {
- ty_int(TyI8) => "llvm.sadd.with.overflow.i8",
- ty_int(TyI16) => "llvm.sadd.with.overflow.i16",
- ty_int(TyI32) => "llvm.sadd.with.overflow.i32",
- ty_int(TyI64) => "llvm.sadd.with.overflow.i64",
+ TyInt(TyI8) => "llvm.sadd.with.overflow.i8",
+ TyInt(TyI16) => "llvm.sadd.with.overflow.i16",
+ TyInt(TyI32) => "llvm.sadd.with.overflow.i32",
+ TyInt(TyI64) => "llvm.sadd.with.overflow.i64",
- ty_uint(TyU8) => "llvm.uadd.with.overflow.i8",
- ty_uint(TyU16) => "llvm.uadd.with.overflow.i16",
- ty_uint(TyU32) => "llvm.uadd.with.overflow.i32",
- ty_uint(TyU64) => "llvm.uadd.with.overflow.i64",
+ TyUint(TyU8) => "llvm.uadd.with.overflow.i8",
+ TyUint(TyU16) => "llvm.uadd.with.overflow.i16",
+ TyUint(TyU32) => "llvm.uadd.with.overflow.i32",
+ TyUint(TyU64) => "llvm.uadd.with.overflow.i64",
_ => unreachable!(),
},
OverflowOpViaIntrinsic::Sub => match new_sty {
- ty_int(TyI8) => "llvm.ssub.with.overflow.i8",
- ty_int(TyI16) => "llvm.ssub.with.overflow.i16",
- ty_int(TyI32) => "llvm.ssub.with.overflow.i32",
- ty_int(TyI64) => "llvm.ssub.with.overflow.i64",
+ TyInt(TyI8) => "llvm.ssub.with.overflow.i8",
+ TyInt(TyI16) => "llvm.ssub.with.overflow.i16",
+ TyInt(TyI32) => "llvm.ssub.with.overflow.i32",
+ TyInt(TyI64) => "llvm.ssub.with.overflow.i64",
- ty_uint(TyU8) => "llvm.usub.with.overflow.i8",
- ty_uint(TyU16) => "llvm.usub.with.overflow.i16",
- ty_uint(TyU32) => "llvm.usub.with.overflow.i32",
- ty_uint(TyU64) => "llvm.usub.with.overflow.i64",
+ TyUint(TyU8) => "llvm.usub.with.overflow.i8",
+ TyUint(TyU16) => "llvm.usub.with.overflow.i16",
+ TyUint(TyU32) => "llvm.usub.with.overflow.i32",
+ TyUint(TyU64) => "llvm.usub.with.overflow.i64",
_ => unreachable!(),
},
OverflowOpViaIntrinsic::Mul => match new_sty {
- ty_int(TyI8) => "llvm.smul.with.overflow.i8",
- ty_int(TyI16) => "llvm.smul.with.overflow.i16",
- ty_int(TyI32) => "llvm.smul.with.overflow.i32",
- ty_int(TyI64) => "llvm.smul.with.overflow.i64",
+ TyInt(TyI8) => "llvm.smul.with.overflow.i8",
+ TyInt(TyI16) => "llvm.smul.with.overflow.i16",
+ TyInt(TyI32) => "llvm.smul.with.overflow.i32",
+ TyInt(TyI64) => "llvm.smul.with.overflow.i64",
- ty_uint(TyU8) => "llvm.umul.with.overflow.i8",
- ty_uint(TyU16) => "llvm.umul.with.overflow.i16",
- ty_uint(TyU32) => "llvm.umul.with.overflow.i32",
- ty_uint(TyU64) => "llvm.umul.with.overflow.i64",
+ TyUint(TyU8) => "llvm.umul.with.overflow.i8",
+ TyUint(TyU16) => "llvm.umul.with.overflow.i16",
+ TyUint(TyU32) => "llvm.umul.with.overflow.i32",
+ TyUint(TyU64) => "llvm.umul.with.overflow.i64",
_ => unreachable!(),
},
// (since that is where the 32/64 distinction is relevant) but
// the mask's type must match the RHS type (since they will
// both be fed into a and-binop)
- let invert_mask = !shift_mask_val(lhs_llty);
- let invert_mask = C_integral(rhs_llty, invert_mask, true);
+ let invert_mask = shift_mask_val(bcx, lhs_llty, rhs_llty, true);
let outer_bits = And(bcx, rhs, invert_mask, binop_debug_loc);
- let cond = ICmp(bcx, llvm::IntNE, outer_bits,
- C_integral(rhs_llty, 0, false), binop_debug_loc);
+ let cond = build_nonzero_check(bcx, outer_bits, binop_debug_loc);
let result = match *self {
OverflowOpViaInputCheck::Shl =>
build_unchecked_lshift(bcx, lhs, rhs, binop_debug_loc),
}
}
-fn shift_mask_val(llty: Type) -> u64 {
- // i8/u8 can shift by at most 7, i16/u16 by at most 15, etc.
- llty.int_width() - 1
+fn shift_mask_val<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+ llty: Type,
+ mask_llty: Type,
+ invert: bool) -> ValueRef {
+ let kind = llty.kind();
+ match kind {
+ TypeKind::Integer => {
+ // i8/u8 can shift by at most 7, i16/u16 by at most 15, etc.
+ let val = llty.int_width() - 1;
+ if invert {
+ C_integral(mask_llty, !val, true)
+ } else {
+ C_integral(mask_llty, val, false)
+ }
+ },
+ TypeKind::Vector => {
+ let mask = shift_mask_val(bcx, llty.element_type(), mask_llty.element_type(), invert);
+ VectorSplat(bcx, mask_llty.vector_length(), mask)
+ },
+ _ => panic!("shift_mask_val: expected Integer or Vector, found {:?}", kind),
+ }
+}
+
+// Check if an integer or vector contains a nonzero element.
+fn build_nonzero_check<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+ value: ValueRef,
+ binop_debug_loc: DebugLoc) -> ValueRef {
+ let llty = val_ty(value);
+ let kind = llty.kind();
+ match kind {
+ TypeKind::Integer => ICmp(bcx, llvm::IntNE, value, C_null(llty), binop_debug_loc),
+ TypeKind::Vector => {
+ // Check if any elements of the vector are nonzero by treating
+ // it as a wide integer and checking if the integer is nonzero.
+ let width = llty.vector_length() as u64 * llty.element_type().int_width();
+ let int_value = BitCast(bcx, value, Type::ix(bcx.ccx(), width));
+ build_nonzero_check(bcx, int_value, binop_debug_loc)
+ },
+ _ => panic!("build_nonzero_check: expected Integer or Vector, found {:?}", kind),
+ }
}
// To avoid UB from LLVM, these two functions mask RHS with an
let rhs = base::cast_shift_expr_rhs(bcx, ast::BinOp_::BiShr, lhs, rhs);
// #1877, #10183: Ensure that input is always valid
let rhs = shift_mask_rhs(bcx, rhs, binop_debug_loc);
- let is_signed = ty::type_is_signed(lhs_t);
+ let tcx = bcx.tcx();
+ let is_simd = ty::type_is_simd(tcx, lhs_t);
+ let intype = if is_simd {
+ ty::simd_type(tcx, lhs_t)
+ } else {
+ lhs_t
+ };
+ let is_signed = ty::type_is_signed(intype);
if is_signed {
AShr(bcx, lhs, rhs, binop_debug_loc)
} else {
rhs: ValueRef,
debug_loc: DebugLoc) -> ValueRef {
let rhs_llty = val_ty(rhs);
- let mask = shift_mask_val(rhs_llty);
- And(bcx, rhs, C_integral(rhs_llty, mask, false), debug_loc)
+ And(bcx, rhs, shift_mask_val(bcx, rhs_llty, rhs_llty, false), debug_loc)
}
fn with_overflow_check<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, oop: OverflowOp, info: NodeIdAndSpan,
(bcx, res)
}
}
+
+/// We categorize expressions into three kinds. The distinction between
+/// lvalue/rvalue is fundamental to the language. The distinction between the
+/// two kinds of rvalues is an artifact of trans which reflects how we will
+/// generate code for that kind of expression. See trans/expr.rs for more
+/// information.
+#[derive(Copy, Clone)]
+enum ExprKind {
+ Lvalue,
+ RvalueDps,
+ RvalueDatum,
+ RvalueStmt
+}
+
+fn expr_kind(tcx: &ty::ctxt, expr: &ast::Expr) -> ExprKind {
+ if tcx.method_map.borrow().contains_key(&MethodCall::expr(expr.id)) {
+ // Overloaded operations are generally calls, and hence they are
+ // generated via DPS, but there are a few exceptions:
+ return match expr.node {
+ // `a += b` has a unit result.
+ ast::ExprAssignOp(..) => ExprKind::RvalueStmt,
+
+ // the deref method invoked for `*a` always yields an `&T`
+ ast::ExprUnary(ast::UnDeref, _) => ExprKind::Lvalue,
+
+ // the index method invoked for `a[i]` always yields an `&T`
+ ast::ExprIndex(..) => ExprKind::Lvalue,
+
+ // in the general case, result could be any type, use DPS
+ _ => ExprKind::RvalueDps
+ };
+ }
+
+ match expr.node {
+ ast::ExprPath(..) => {
+ match ty::resolve_expr(tcx, expr) {
+ def::DefStruct(_) | def::DefVariant(..) => {
+ if let ty::TyBareFn(..) = ty::node_id_to_type(tcx, expr.id).sty {
+ // ctor function
+ ExprKind::RvalueDatum
+ } else {
+ ExprKind::RvalueDps
+ }
+ }
+
+ // Special case: A unit like struct's constructor must be called without () at the
+ // end (like `UnitStruct`) which means this is an ExprPath to a DefFn. But in case
+ // of unit structs this is should not be interpreted as function pointer but as
+ // call to the constructor.
+ def::DefFn(_, true) => ExprKind::RvalueDps,
+
+ // Fn pointers are just scalar values.
+ def::DefFn(..) | def::DefMethod(..) => ExprKind::RvalueDatum,
+
+ // Note: there is actually a good case to be made that
+ // DefArg's, particularly those of immediate type, ought to
+ // considered rvalues.
+ def::DefStatic(..) |
+ def::DefUpvar(..) |
+ def::DefLocal(..) => ExprKind::Lvalue,
+
+ def::DefConst(..) |
+ def::DefAssociatedConst(..) => ExprKind::RvalueDatum,
+
+ def => {
+ tcx.sess.span_bug(
+ expr.span,
+ &format!("uncategorized def for expr {}: {:?}",
+ expr.id,
+ def));
+ }
+ }
+ }
+
+ ast::ExprUnary(ast::UnDeref, _) |
+ ast::ExprField(..) |
+ ast::ExprTupField(..) |
+ ast::ExprIndex(..) => {
+ ExprKind::Lvalue
+ }
+
+ ast::ExprCall(..) |
+ ast::ExprMethodCall(..) |
+ ast::ExprStruct(..) |
+ ast::ExprRange(..) |
+ ast::ExprTup(..) |
+ ast::ExprIf(..) |
+ ast::ExprMatch(..) |
+ ast::ExprClosure(..) |
+ ast::ExprBlock(..) |
+ ast::ExprRepeat(..) |
+ ast::ExprVec(..) => {
+ ExprKind::RvalueDps
+ }
+
+ ast::ExprIfLet(..) => {
+ tcx.sess.span_bug(expr.span, "non-desugared ExprIfLet");
+ }
+ ast::ExprWhileLet(..) => {
+ tcx.sess.span_bug(expr.span, "non-desugared ExprWhileLet");
+ }
+
+ ast::ExprForLoop(..) => {
+ tcx.sess.span_bug(expr.span, "non-desugared ExprForLoop");
+ }
+
+ ast::ExprLit(ref lit) if ast_util::lit_is_str(&**lit) => {
+ ExprKind::RvalueDps
+ }
+
+ ast::ExprBreak(..) |
+ ast::ExprAgain(..) |
+ ast::ExprRet(..) |
+ ast::ExprWhile(..) |
+ ast::ExprLoop(..) |
+ ast::ExprAssign(..) |
+ ast::ExprInlineAsm(..) |
+ ast::ExprAssignOp(..) => {
+ ExprKind::RvalueStmt
+ }
+
+ ast::ExprLit(_) | // Note: LitStr is carved out above
+ ast::ExprUnary(..) |
+ ast::ExprBox(None, _) |
+ ast::ExprAddrOf(..) |
+ ast::ExprBinary(..) |
+ ast::ExprCast(..) => {
+ ExprKind::RvalueDatum
+ }
+
+ ast::ExprBox(Some(ref place), _) => {
+ // Special case `Box<T>` for now:
+ let def_id = match tcx.def_map.borrow().get(&place.id) {
+ Some(def) => def.def_id(),
+ None => panic!("no def for place"),
+ };
+ if tcx.lang_items.exchange_heap() == Some(def_id) {
+ ExprKind::RvalueDatum
+ } else {
+ ExprKind::RvalueDps
+ }
+ }
+
+ ast::ExprParen(ref e) => expr_kind(tcx, &**e),
+
+ ast::ExprMac(..) => {
+ tcx.sess.span_bug(
+ expr.span,
+ "macro expression remains after expansion");
+ }
+ }
+}
// except according to those terms.
-use back::link;
+use back::{abi, link};
use llvm::{ValueRef, CallConv, get_param};
use llvm;
use middle::weak_lang_items;
+use rustc::ast_map;
use trans::attributes;
use trans::base::{llvm_linkage_by_name, push_ctxt};
use trans::base;
use trans::common::*;
use trans::debuginfo::DebugLoc;
use trans::declare;
+use trans::expr;
use trans::machine;
use trans::monomorphize;
use trans::type_::Type;
use syntax::parse::token::{InternedString, special_idents};
use syntax::parse::token;
use syntax::ast;
-use syntax::{attr, ast_map};
+use syntax::attr;
use syntax::print::pprust;
-use util::ppaux::Repr;
///////////////////////////////////////////////////////////////////////////
// Type definitions
}
};
let llty2 = match ty.sty {
- ty::ty_ptr(ref mt) => type_of::type_of(ccx, mt.ty),
+ ty::TyRawPtr(ref mt) => type_of::type_of(ccx, mt.ty),
_ => {
ccx.sess().span_fatal(foreign_item.span,
"must have type `*T` or `*mut T`");
pub fn register_foreign_item_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
abi: Abi, fty: Ty<'tcx>,
name: &str) -> ValueRef {
- debug!("register_foreign_item_fn(abi={}, \
- ty={}, \
+ debug!("register_foreign_item_fn(abi={:?}, \
+ ty={:?}, \
name={})",
- abi.repr(ccx.tcx()),
- fty.repr(ccx.tcx()),
+ abi,
+ fty,
name);
let cc = llvm_calling_convention(ccx, abi);
-> Block<'blk, 'tcx>
{
let ccx = bcx.ccx();
- let tcx = bcx.tcx();
- debug!("trans_native_call(callee_ty={}, \
+ debug!("trans_native_call(callee_ty={:?}, \
llfn={}, \
llretptr={})",
- callee_ty.repr(tcx),
+ callee_ty,
ccx.tn().val_to_string(llfn),
ccx.tn().val_to_string(llretptr));
let (fn_abi, fn_sig) = match callee_ty.sty {
- ty::ty_bare_fn(_, ref fn_ty) => (fn_ty.abi, &fn_ty.sig),
+ ty::TyBareFn(_, ref fn_ty) => (fn_ty.abi, &fn_ty.sig),
_ => ccx.sess().bug("trans_native_call called on non-function type")
};
let fn_sig = ty::erase_late_bound_regions(ccx.tcx(), fn_sig);
}
}
- for (i, &llarg_rust) in llargs_rust.iter().enumerate() {
- let mut llarg_rust = llarg_rust;
+ let mut offset = 0;
+ for (i, arg_ty) in arg_tys.iter().enumerate() {
+ let mut llarg_rust = llargs_rust[i + offset];
- if arg_tys[i].is_ignore() {
+ if arg_ty.is_ignore() {
continue;
}
i,
ccx.tn().val_to_string(llarg_rust),
rust_indirect,
- ccx.tn().type_to_string(arg_tys[i].ty));
+ ccx.tn().type_to_string(arg_ty.ty));
// Ensure that we always have the Rust value indirectly,
// because it makes bitcasting easier.
base::alloca(bcx,
type_of::type_of(ccx, passed_arg_tys[i]),
"__arg");
- base::store_ty(bcx, llarg_rust, scratch, passed_arg_tys[i]);
+ if type_is_fat_ptr(ccx.tcx(), passed_arg_tys[i]) {
+ Store(bcx, llargs_rust[i + offset], expr::get_dataptr(bcx, scratch));
+ Store(bcx, llargs_rust[i + offset + 1], expr::get_len(bcx, scratch));
+ offset += 1;
+ } else {
+ base::store_ty(bcx, llarg_rust, scratch, passed_arg_tys[i]);
+ }
llarg_rust = scratch;
}
ccx.tn().val_to_string(llarg_rust));
// Check whether we need to do any casting
- match arg_tys[i].cast {
+ match arg_ty.cast {
Some(ty) => llarg_rust = BitCast(bcx, llarg_rust, ty.ptr_to()),
None => ()
}
ccx.tn().val_to_string(llarg_rust));
// Finally, load the value if needed for the foreign ABI
- let foreign_indirect = arg_tys[i].is_indirect();
+ let foreign_indirect = arg_ty.is_indirect();
let llarg_foreign = if foreign_indirect {
llarg_rust
} else {
i, ccx.tn().val_to_string(llarg_foreign));
// fill padding with undef value
- match arg_tys[i].pad {
+ match arg_ty.pad {
Some(ty) => llargs_foreign.push(C_undef(ty)),
None => ()
}
}
};
let sig = &ty.sig.0;
- for (input, ty) in decl.inputs.iter().zip(sig.inputs.iter()) {
+ for (input, ty) in decl.inputs.iter().zip(&sig.inputs) {
check(&*input.ty, *ty)
}
if let ast::Return(ref ty) = decl.output {
abi => {
let ty = ty::node_id_to_type(ccx.tcx(), foreign_item.id);
match ty.sty {
- ty::ty_bare_fn(_, bft) => gate_simd_ffi(ccx.tcx(), &**decl, bft),
+ ty::TyBareFn(_, bft) => gate_simd_ffi(ccx.tcx(), &**decl, bft),
_ => ccx.tcx().sess.span_bug(foreign_item.span,
"foreign fn's sty isn't a bare_fn_ty?")
}
let tys = foreign_types_for_fn_ty(ccx, t);
let llfn_ty = lltype_for_fn_from_foreign_types(ccx, &tys);
let cconv = match t.sty {
- ty::ty_bare_fn(_, ref fn_ty) => {
+ ty::TyBareFn(_, ref fn_ty) => {
llvm_calling_convention(ccx, fn_ty.abi)
}
_ => panic!("expected bare fn in decl_rust_fn_with_foreign_abi")
let llfn_ty = lltype_for_fn_from_foreign_types(ccx, &tys);
let t = ty::node_id_to_type(ccx.tcx(), node_id);
let cconv = match t.sty {
- ty::ty_bare_fn(_, ref fn_ty) => {
+ ty::TyBareFn(_, ref fn_ty) => {
llvm_calling_convention(ccx, fn_ty.abi)
}
_ => panic!("expected bare fn in register_rust_fn_with_foreign_abi")
let ps = ccx.tcx().map.with_path(id, |path| {
let abi = Some(ast_map::PathName(special_idents::clownshoe_abi.name));
- link::mangle(path.chain(abi.into_iter()), hash)
+ link::mangle(path.chain(abi), hash)
});
// Compute the type that the function would have if it were just a
// normal Rust function. This will be the type of the wrappee fn.
match t.sty {
- ty::ty_bare_fn(_, ref f) => {
+ ty::TyBareFn(_, ref f) => {
assert!(f.abi != Rust && f.abi != RustIntrinsic);
}
_ => {
- ccx.sess().bug(&format!("build_rust_fn: extern fn {} has ty {}, \
+ ccx.sess().bug(&format!("build_rust_fn: extern fn {} has ty {:?}, \
expected a bare fn ty",
ccx.tcx().map.path_to_string(id),
- t.repr(tcx)));
+ t));
}
};
- debug!("build_rust_fn: path={} id={} t={}",
+ debug!("build_rust_fn: path={} id={} t={:?}",
ccx.tcx().map.path_to_string(id),
- id, t.repr(tcx));
+ id, t);
let llfn = declare::define_internal_rust_fn(ccx, &ps[..], t).unwrap_or_else(||{
ccx.sess().bug(&format!("symbol `{}` already defined", ps));
t: Ty<'tcx>) {
let _icx = push_ctxt(
"foreign::trans_rust_fn_with_foreign_abi::build_wrap_fn");
- let tcx = ccx.tcx();
- debug!("build_wrap_fn(llrustfn={}, llwrapfn={}, t={})",
+ debug!("build_wrap_fn(llrustfn={}, llwrapfn={}, t={:?})",
ccx.tn().val_to_string(llrustfn),
ccx.tn().val_to_string(llwrapfn),
- t.repr(ccx.tcx()));
+ t);
// Avoid all the Rust generation stuff and just generate raw
// LLVM here.
debug!("out pointer, \
allocad={}, \
llrust_ret_ty={}, \
- return_ty={}",
+ return_ty={:?}",
ccx.tn().val_to_string(slot),
ccx.tn().type_to_string(llrust_ret_ty),
- tys.fn_sig.output.repr(tcx));
+ tys.fn_sig.output);
llrust_args.push(slot);
return_alloca = Some(slot);
}
// If the types in the ABI and the Rust types don't match,
// bitcast the llforeign_arg pointer so it matches the types
// Rust expects.
- if llforeign_arg_ty.cast.is_some() {
+ if llforeign_arg_ty.cast.is_some() && !type_is_fat_ptr(ccx.tcx(), rust_ty){
assert!(!foreign_indirect);
llforeign_arg = builder.bitcast(llforeign_arg, llrust_ty.ptr_to());
}
- let llrust_arg = if rust_indirect {
+ let llrust_arg = if rust_indirect || type_is_fat_ptr(ccx.tcx(), rust_ty) {
llforeign_arg
} else {
if ty::type_is_bool(rust_ty) {
debug!("llrust_arg {}{}: {}", "#",
i, ccx.tn().val_to_string(llrust_arg));
- llrust_args.push(llrust_arg);
+ if type_is_fat_ptr(ccx.tcx(), rust_ty) {
+ let next_llrust_ty = rust_param_tys.next().expect("Not enough parameter types!");
+ llrust_args.push(builder.load(builder.bitcast(builder.gepi(
+ llrust_arg, &[0, abi::FAT_PTR_ADDR]), llrust_ty.ptr_to())));
+ llrust_args.push(builder.load(builder.bitcast(builder.gepi(
+ llrust_arg, &[0, abi::FAT_PTR_EXTRA]), next_llrust_ty.ptr_to())));
+ } else {
+ llrust_args.push(llrust_arg);
+ }
}
// Perform the call itself
- debug!("calling llrustfn = {}, t = {}",
- ccx.tn().val_to_string(llrustfn), t.repr(ccx.tcx()));
+ debug!("calling llrustfn = {}, t = {:?}",
+ ccx.tn().val_to_string(llrustfn), t);
let attributes = attributes::from_fn_type(ccx, t);
let llrust_ret_val = builder.call(llrustfn, &llrust_args, Some(attributes));
fn foreign_types_for_fn_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
ty: Ty<'tcx>) -> ForeignTypes<'tcx> {
let fn_sig = match ty.sty {
- ty::ty_bare_fn(_, ref fn_ty) => &fn_ty.sig,
+ ty::TyBareFn(_, ref fn_ty) => &fn_ty.sig,
_ => ccx.sess().bug("foreign_types_for_fn_ty called on non-function type")
};
let fn_sig = ty::erase_late_bound_regions(ccx.tcx(), fn_sig);
llsig.llret_ty,
llsig.ret_def);
debug!("foreign_types_for_fn_ty(\
- ty={}, \
+ ty={:?}, \
llsig={} -> {}, \
fn_ty={} -> {}, \
ret_def={}",
- ty.repr(ccx.tcx()),
+ ty,
ccx.tn().types_to_str(&llsig.llarg_tys),
ccx.tn().type_to_string(llsig.llret_ty),
ccx.tn().types_to_str(&fn_ty.arg_tys.iter().map(|t| t.ty).collect::<Vec<_>>()),
use trans::monomorphize;
use trans::type_of::{type_of, type_of_dtor, sizing_type_of, align_of};
use trans::type_::Type;
-use util::ppaux;
-use util::ppaux::{ty_to_short_str, Repr};
use arena::TypedArena;
use libc::c_uint;
return tcx.types.i8;
}
match t.sty {
- ty::ty_uniq(typ) if !type_needs_drop(tcx, typ)
+ ty::TyBox(typ) if !type_needs_drop(tcx, typ)
&& type_is_sized(tcx, typ) => {
let llty = sizing_type_of(ccx, typ);
// `Box<ZeroSizeType>` does not allocate.
debug_loc: DebugLoc,
skip_dtor: bool) -> Block<'blk, 'tcx> {
// NB: v is an *alias* of type t here, not a direct value.
- debug!("drop_ty_core(t={}, skip_dtor={})", t.repr(bcx.tcx()), skip_dtor);
+ debug!("drop_ty_core(t={:?}, skip_dtor={})", t, skip_dtor);
let _icx = push_ctxt("drop_ty");
if bcx.fcx.type_needs_drop(t) {
let ccx = bcx.ccx();
DropGlueKind::TyContents(t) => DropGlueKind::TyContents(f(t)),
}
}
-
- fn to_string<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> String {
- let t_str = ppaux::ty_to_string(ccx.tcx(), self.ty());
- match *self {
- DropGlueKind::Ty(_) => format!("DropGlueKind::Ty({})", t_str),
- DropGlueKind::TyContents(_) => format!("DropGlueKind::TyContents({})", t_str),
- }
- }
}
fn get_drop_glue_core<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
g: DropGlueKind<'tcx>) -> ValueRef {
- debug!("make drop glue for {}", g.to_string(ccx));
+ debug!("make drop glue for {:?}", g);
let g = g.map_ty(|t| get_drop_glue_type(ccx, t));
- debug!("drop glue type {}", g.to_string(ccx));
+ debug!("drop glue type {:?}", g);
match ccx.drop_glues().borrow().get(&g) {
Some(&glue) => return glue,
_ => { }
});
ccx.available_drop_glues().borrow_mut().insert(g, fn_nm);
- let _s = StatRecorder::new(ccx, format!("drop {}", ty_to_short_str(ccx.tcx(), t)));
+ let _s = StatRecorder::new(ccx, format!("drop {:?}", t));
let empty_substs = ccx.tcx().mk_substs(Substs::trans_empty());
let (arena, fcx): (TypedArena<_>, FunctionContext);
// llfn is expected be declared to take a parameter of the appropriate
// type, so we don't need to explicitly cast the function parameter.
- let llrawptr0 = get_param(llfn, fcx.arg_pos(0) as c_uint);
+ let llrawptr0 = get_param(llfn, fcx.arg_offset() as c_uint);
let bcx = make_drop_glue(bcx, llrawptr0, g);
finish_fn(&fcx, bcx, ty::FnConverging(ty::mk_nil(ccx.tcx())), DebugLoc::None);
substs: &subst::Substs<'tcx>)
-> Block<'blk, 'tcx>
{
- debug!("trans_struct_drop t: {}", bcx.ty_to_string(t));
+ debug!("trans_struct_drop t: {}", t);
// Find and call the actual destructor
let dtor_addr = get_res_dtor(bcx.ccx(), dtor_did, t, class_did, substs);
pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, info: ValueRef)
-> (ValueRef, ValueRef) {
debug!("calculate size of DST: {}; with lost info: {}",
- bcx.ty_to_string(t), bcx.val_to_string(info));
+ t, bcx.val_to_string(info));
if type_is_sized(bcx.tcx(), t) {
let sizing_type = sizing_type_of(bcx.ccx(), t);
let size = C_uint(bcx.ccx(), llsize_of_alloc(bcx.ccx(), sizing_type));
return (size, align);
}
match t.sty {
- ty::ty_struct(id, substs) => {
+ ty::TyStruct(id, substs) => {
let ccx = bcx.ccx();
// First get the size of all statically known fields.
// Don't use type_of::sizing_type_of because that expects t to be sized.
unsized_align);
(size, align)
}
- ty::ty_trait(..) => {
+ ty::TyTrait(..) => {
// info points to the vtable and the second entry in the vtable is the
// dynamic size of the object.
let info = PointerCast(bcx, info, Type::int(bcx.ccx()).ptr_to());
let align_ptr = GEPi(bcx, info, &[2]);
(Load(bcx, size_ptr), Load(bcx, align_ptr))
}
- ty::ty_vec(_, None) | ty::ty_str => {
+ ty::TySlice(_) | ty::TyStr => {
let unit_ty = ty::sequence_element_type(bcx.tcx(), t);
// The info in this case is the length of the str, so the size is that
// times the unit size.
(Mul(bcx, info, C_uint(bcx.ccx(), unit_size), DebugLoc::None),
C_uint(bcx.ccx(), unit_align))
}
- _ => bcx.sess().bug(&format!("Unexpected unsized type, found {}",
- bcx.ty_to_string(t)))
+ _ => bcx.sess().bug(&format!("Unexpected unsized type, found {}", t))
}
}
let dropped_pattern = C_integral(inttype, adt::dtor_done_usize(bcx.fcx.ccx) as u64, false);
match t.sty {
- ty::ty_uniq(content_ty) => {
- // Support for ty_uniq is built-in and its drop glue is
+ ty::TyBox(content_ty) => {
+ // Support for TyBox is built-in and its drop glue is
// special. It may move to library and have Drop impl. As
- // a safe-guard, assert ty_uniq not used with TyContents.
+ // a safe-guard, assert TyBox not used with TyContents.
assert!(!skip_dtor);
if !type_is_sized(bcx.tcx(), content_ty) {
let llval = GEPi(bcx, v0, &[0, abi::FAT_PTR_ADDR]);
})
}
}
- ty::ty_struct(did, substs) | ty::ty_enum(did, substs) => {
+ ty::TyStruct(did, substs) | ty::TyEnum(did, substs) => {
let tcx = bcx.tcx();
match (ty::ty_dtor(tcx, did), skip_dtor) {
(ty::TraitDtor(dtor, true), false) => {
// stupid and dangerous.
bcx.sess().warn(&format!("Ignoring drop flag in destructor for {}\
because the struct is unsized. See issue\
- #16758",
- bcx.ty_to_string(t)));
+ #16758", t));
trans_struct_drop(bcx, t, v0, dtor, did, substs)
}
}
}
}
}
- ty::ty_trait(..) => {
+ ty::TyTrait(..) => {
// No support in vtable for distinguishing destroying with
// versus without calling Drop::drop. Assert caller is
// okay with always calling the Drop impl, if any.
fn instantiate_inline(ccx: &CrateContext, fn_id: ast::DefId)
-> Option<ast::DefId> {
- let _icx = push_ctxt("maybe_instantiate_inline");
+ debug!("instantiate_inline({:?})", fn_id);
+ let _icx = push_ctxt("instantiate_inline");
+
match ccx.external().borrow().get(&fn_id) {
Some(&Some(node_id)) => {
// Already inline
- debug!("maybe_instantiate_inline({}): already inline as node id {}",
+ debug!("instantiate_inline({}): already inline as node id {}",
ty::item_path_str(ccx.tcx(), fn_id), node_id);
return Some(local_def(node_id));
}
ccx.external_srcs().borrow_mut().insert(item.id, fn_id);
ccx.stats().n_inlines.set(ccx.stats().n_inlines.get() + 1);
- trans_item(ccx, &**item);
+ trans_item(ccx, item);
let linkage = match item.node {
- ast::ItemFn(_, _, _, ref generics, _) => {
+ ast::ItemFn(_, _, _, _, ref generics, _) => {
if generics.is_type_parameterized() {
// Generics have no symbol, so they can't be given any
// linkage.
}
}
}
- _ => ccx.sess().bug("maybe_instantiate_inline: item has a \
+ _ => ccx.sess().bug("instantiate_inline: item has a \
non-enum, non-struct parent")
}
trans_item(ccx, &**item);
}
csearch::FoundAst::FoundParent(_, _) => {
ccx.sess().bug("maybe_get_item_ast returned a FoundParent \
- with a non-item parent");
+ with a non-item parent");
}
csearch::FoundAst::Found(&ast::IITraitItem(_, ref trait_item)) => {
ccx.external().borrow_mut().insert(fn_id, Some(trait_item.id));
empty_substs,
impl_item.id,
&[]);
- // Use InternalLinkage so LLVM can optimize more aggressively.
- SetLinkage(llfn, InternalLinkage);
+ // See linkage comments on items.
+ if ccx.sess().opts.cg.codegen_units == 1 {
+ SetLinkage(llfn, InternalLinkage);
+ } else {
+ SetLinkage(llfn, AvailableExternallyLinkage);
+ }
}
}
use syntax::abi::RustIntrinsic;
use syntax::ast;
use syntax::parse::token;
-use util::ppaux::{Repr, ty_to_string};
pub fn get_simple_intrinsic(ccx: &CrateContext, item: &ast::ForeignItem) -> Option<ValueRef> {
let name = match &token::get_ident(item.ident)[..] {
/// the only intrinsic that needs such verification is `transmute`.
pub fn check_intrinsics(ccx: &CrateContext) {
let mut last_failing_id = None;
- for transmute_restriction in &*ccx.tcx().transmute_restrictions.borrow() {
+ for transmute_restriction in ccx.tcx().transmute_restrictions.borrow().iter() {
// Sometimes, a single call to transmute will push multiple
// type pairs to test in order to exhaustively test the
// possibility around a type parameter. If one of those fails,
continue;
}
- debug!("transmute_restriction: {}", transmute_restriction.repr(ccx.tcx()));
+ debug!("transmute_restriction: {:?}", transmute_restriction);
assert!(!ty::type_has_params(transmute_restriction.substituted_from));
assert!(!ty::type_has_params(transmute_restriction.substituted_to));
transmute_restriction.span,
&format!("transmute called on types with potentially different sizes: \
{} (could be {} bit{}) to {} (could be {} bit{})",
- ty_to_string(ccx.tcx(), transmute_restriction.original_from),
+ transmute_restriction.original_from,
from_type_size as usize,
if from_type_size == 1 {""} else {"s"},
- ty_to_string(ccx.tcx(), transmute_restriction.original_to),
+ transmute_restriction.original_to,
to_type_size as usize,
if to_type_size == 1 {""} else {"s"}));
} else {
transmute_restriction.span,
&format!("transmute called on types with different sizes: \
{} ({} bit{}) to {} ({} bit{})",
- ty_to_string(ccx.tcx(), transmute_restriction.original_from),
+ transmute_restriction.original_from,
from_type_size as usize,
if from_type_size == 1 {""} else {"s"},
- ty_to_string(ccx.tcx(), transmute_restriction.original_to),
+ transmute_restriction.original_to,
to_type_size as usize,
if to_type_size == 1 {""} else {"s"}));
}
let _icx = push_ctxt("trans_intrinsic_call");
let ret_ty = match callee_ty.sty {
- ty::ty_bare_fn(_, ref f) => {
+ ty::TyBareFn(_, ref f) => {
ty::erase_late_bound_regions(bcx.tcx(), &f.sig.output())
}
_ => panic!("expected bare_fn in trans_intrinsic_call")
let val = if datum.kind.is_by_ref() {
load_ty(bcx, datum.val, datum.ty)
} else {
- datum.val
+ from_arg_ty(bcx, datum.val, datum.ty)
};
let cast_val = BitCast(bcx, val, llret_ty);
}
}
+ // For `move_val_init` we can evaluate the destination address
+ // (the first argument) and then trans the source value (the
+ // second argument) directly into the resulting destination
+ // address.
+ if &name[..] == "move_val_init" {
+ if let callee::ArgExprs(ref exprs) = args {
+ let (dest_expr, source_expr) = if exprs.len() != 2 {
+ ccx.sess().bug("expected two exprs as arguments for `move_val_init` intrinsic");
+ } else {
+ (&exprs[0], &exprs[1])
+ };
+
+ // evaluate destination address
+ let dest_datum = unpack_datum!(bcx, expr::trans(bcx, dest_expr));
+ let dest_datum = unpack_datum!(
+ bcx, dest_datum.to_rvalue_datum(bcx, "arg"));
+ let dest_datum = unpack_datum!(
+ bcx, dest_datum.to_appropriate_datum(bcx));
+
+ // `expr::trans_into(bcx, expr, dest)` is equiv to
+ //
+ // `trans(bcx, expr).store_to_dest(dest)`,
+ //
+ // which for `dest == expr::SaveIn(addr)`, is equivalent to:
+ //
+ // `trans(bcx, expr).store_to(bcx, addr)`.
+ let lldest = expr::Dest::SaveIn(dest_datum.val);
+ bcx = expr::trans_into(bcx, source_expr, lldest);
+
+ let llresult = C_nil(ccx);
+ fcx.pop_and_trans_custom_cleanup_scope(bcx, cleanup_scope);
+
+ return Result::new(bcx, llresult);
+ } else {
+ ccx.sess().bug("expected two exprs as arguments for `move_val_init` intrinsic");
+ }
+ }
+
// Push the arguments.
let mut llargs = Vec::new();
bcx = callee::trans_args(bcx,
(_, "size_of_val") => {
let tp_ty = *substs.types.get(FnSpace, 0);
if !type_is_sized(tcx, tp_ty) {
- let info = Load(bcx, expr::get_len(bcx, llargs[0]));
- let (llsize, _) = glue::size_and_align_of_dst(bcx, tp_ty, info);
+ let (llsize, _) = glue::size_and_align_of_dst(bcx, tp_ty, llargs[1]);
llsize
} else {
let lltp_ty = type_of::type_of(ccx, tp_ty);
(_, "min_align_of_val") => {
let tp_ty = *substs.types.get(FnSpace, 0);
if !type_is_sized(tcx, tp_ty) {
- let info = Load(bcx, expr::get_len(bcx, llargs[0]));
- let (_, llalign) = glue::size_and_align_of_dst(bcx, tp_ty, info);
+ let (_, llalign) = glue::size_and_align_of_dst(bcx, tp_ty, llargs[1]);
llalign
} else {
C_uint(ccx, type_of::align_of(ccx, tp_ty))
let lltp_ty = type_of::type_of(ccx, tp_ty);
C_uint(ccx, machine::llalign_of_pref(ccx, lltp_ty))
}
- (_, "move_val_init") => {
- // Create a datum reflecting the value being moved.
- // Use `appropriate_mode` so that the datum is by ref
- // if the value is non-immediate. Note that, with
- // intrinsics, there are no argument cleanups to
- // concern ourselves with, so we can use an rvalue datum.
- let tp_ty = *substs.types.get(FnSpace, 0);
- let mode = appropriate_rvalue_mode(ccx, tp_ty);
- let src = Datum {
- val: llargs[1],
- ty: tp_ty,
- kind: Rvalue::new(mode)
- };
- bcx = src.store_to(bcx, llargs[0]);
- C_nil(ccx)
- }
(_, "drop_in_place") => {
let tp_ty = *substs.types.get(FnSpace, 0);
- glue::drop_ty(bcx, llargs[0], tp_ty, call_debug_location);
+ let ptr = if type_is_sized(tcx, tp_ty) {
+ llargs[0]
+ } else {
+ let scratch = rvalue_scratch_datum(bcx, tp_ty, "tmp");
+ Store(bcx, llargs[0], expr::get_dataptr(bcx, scratch.val));
+ Store(bcx, llargs[1], expr::get_len(bcx, scratch.val));
+ fcx.schedule_lifetime_end(cleanup::CustomScope(cleanup_scope), scratch.val);
+ scratch.val
+ };
+ glue::drop_ty(bcx, ptr, tp_ty, call_debug_location);
C_nil(ccx)
}
(_, "type_name") => {
let tp_ty = *substs.types.get(FnSpace, 0);
- let ty_name = token::intern_and_get_ident(&ty_to_string(ccx.tcx(), tp_ty));
+ let ty_name = token::intern_and_get_ident(&tp_ty.to_string());
C_str_slice(ccx, ty_name)
}
(_, "type_id") => {
let offset = llargs[1];
InBoundsGEP(bcx, ptr, &[offset])
}
+ (_, "arith_offset") => {
+ let ptr = llargs[0];
+ let offset = llargs[1];
+ GEP(bcx, ptr, &[offset])
+ }
(_, "copy_nonoverlapping") => {
copy_intrinsic(bcx,
unsafe {
llvm::LLVMSetAlignment(load, type_of::align_of(ccx, tp_ty));
}
- from_arg_ty(bcx, load, tp_ty)
+ to_arg_ty(bcx, load, tp_ty)
},
(_, "volatile_store") => {
let tp_ty = *substs.types.get(FnSpace, 0);
let ptr = to_arg_ty_ptr(bcx, llargs[0], tp_ty);
- let val = to_arg_ty(bcx, llargs[1], tp_ty);
+ let val = from_arg_ty(bcx, llargs[1], tp_ty);
let store = VolatileStore(bcx, val, ptr);
unsafe {
llvm::LLVMSetAlignment(store, type_of::align_of(ccx, tp_ty));
(_, "discriminant_value") => {
let val_ty = substs.types.get(FnSpace, 0);
match val_ty.sty {
- ty::ty_enum(..) => {
+ ty::TyEnum(..) => {
let repr = adt::represent_type(ccx, *val_ty);
adt::trans_get_discr(bcx, &*repr, llargs[0], Some(llret_ty))
}
let tp_ty = *substs.types.get(FnSpace, 0);
let ptr = to_arg_ty_ptr(bcx, llargs[0], tp_ty);
- let cmp = to_arg_ty(bcx, llargs[1], tp_ty);
- let src = to_arg_ty(bcx, llargs[2], tp_ty);
+ let cmp = from_arg_ty(bcx, llargs[1], tp_ty);
+ let src = from_arg_ty(bcx, llargs[2], tp_ty);
let res = AtomicCmpXchg(bcx, ptr, cmp, src, order,
strongest_failure_ordering);
ExtractValue(bcx, res, 0)
"load" => {
let tp_ty = *substs.types.get(FnSpace, 0);
let ptr = to_arg_ty_ptr(bcx, llargs[0], tp_ty);
- from_arg_ty(bcx, AtomicLoad(bcx, ptr, order), tp_ty)
+ to_arg_ty(bcx, AtomicLoad(bcx, ptr, order), tp_ty)
}
"store" => {
let tp_ty = *substs.types.get(FnSpace, 0);
let ptr = to_arg_ty_ptr(bcx, llargs[0], tp_ty);
- let val = to_arg_ty(bcx, llargs[1], tp_ty);
+ let val = from_arg_ty(bcx, llargs[1], tp_ty);
AtomicStore(bcx, val, ptr, order);
C_nil(ccx)
}
let tp_ty = *substs.types.get(FnSpace, 0);
let ptr = to_arg_ty_ptr(bcx, llargs[0], tp_ty);
- let val = to_arg_ty(bcx, llargs[1], tp_ty);
+ let val = from_arg_ty(bcx, llargs[1], tp_ty);
AtomicRMW(bcx, atom_op, ptr, val, order)
}
}
let ret = C_undef(type_of::type_of(bcx.ccx(), t));
let ret = InsertValue(bcx, ret, result, 0);
let ret = InsertValue(bcx, ret, overflow, 1);
- if type_is_immediate(bcx.ccx(), t) {
+ if !arg_is_indirect(bcx.ccx(), t) {
let tmp = alloc_ty(bcx, t, "tmp");
Store(bcx, ret, tmp);
load_ty(bcx, tmp, t)
use arena::TypedArena;
use back::abi;
use back::link;
-use llvm::{ValueRef, get_param};
+use llvm::{ValueRef, get_params};
use metadata::csearch;
use middle::subst::{Subst, Substs};
use middle::subst::VecPerParamSpace;
use middle::subst;
use middle::traits;
use middle::ty::ClosureTyper;
+use rustc::ast_map;
use trans::base::*;
use trans::build::*;
use trans::callee::*;
use trans::type_of::*;
use middle::ty::{self, Ty};
use middle::ty::MethodCall;
-use util::ppaux::Repr;
use syntax::abi::{Rust, RustCall};
use syntax::parse::token;
-use syntax::{ast, ast_map, attr, visit};
+use syntax::{ast, attr, visit};
use syntax::codemap::DUMMY_SP;
use syntax::ptr::P;
let _icx = push_ctxt("meth::trans_impl");
let tcx = ccx.tcx();
- debug!("trans_impl(name={}, id={})", name.repr(tcx), id);
+ debug!("trans_impl(name={}, id={})", name, id);
let mut v = TransItemVisitor { ccx: ccx };
match origin {
ty::MethodStatic(did) |
ty::MethodStaticClosure(did) => {
+ debug!("trans_method_callee: static, {:?}", did);
Callee {
bcx: bcx,
data: Fn(callee::trans_fn_ref(bcx.ccx(),
}) => {
let trait_ref = ty::Binder(bcx.monomorphize(trait_ref));
let span = bcx.tcx().map.span(method_call.expr_id);
- debug!("method_call={:?} trait_ref={}",
+ debug!("method_call={:?} trait_ref={:?} trait_ref id={:?} substs={:?}",
method_call,
- trait_ref.repr(bcx.tcx()));
+ trait_ref,
+ trait_ref.0.def_id,
+ trait_ref.0.substs);
let origin = fulfill_obligation(bcx.ccx(),
span,
trait_ref.clone());
- debug!("origin = {}", origin.repr(bcx.tcx()));
+ debug!("origin = {:?}", origin);
trans_monomorphized_callee(bcx,
method_call,
trait_ref.def_id(),
rcvr_self,
Vec::new()));
let trait_substs = tcx.mk_substs(trait_substs);
- debug!("trait_substs={}", trait_substs.repr(tcx));
+ debug!("trait_substs={:?}", trait_substs);
let trait_ref = ty::Binder(ty::TraitRef { def_id: trait_id,
substs: trait_substs });
let vtbl = fulfill_obligation(ccx,
immediate_rvalue(llfn, ty)
}
_ => {
- tcx.sess.bug(&format!("static call to invalid vtable: {}",
- vtbl.repr(tcx)));
+ tcx.sess.bug(&format!("static call to invalid vtable: {:?}",
+ vtbl));
}
}
}
Callee { bcx: bcx, data: Fn(llfn) }
}
- traits::VtableClosure(closure_def_id, substs) => {
+ traits::VtableClosure(vtable_closure) => {
// The substitutions should have no type parameters remaining
// after passing through fulfill_obligation
let trait_closure_kind = bcx.tcx().lang_items.fn_trait_kind(trait_id).unwrap();
let llfn = closure::trans_closure_method(bcx.ccx(),
- closure_def_id,
- substs,
+ vtable_closure.closure_def_id,
+ vtable_closure.substs,
MethodCallKey(method_call),
bcx.fcx.param_substs,
trait_closure_kind);
traits::VtableDefaultImpl(..) |
traits::VtableParam(..) => {
bcx.sess().bug(
- &format!("resolved vtable bad vtable {} in trans",
- vtable.repr(bcx.tcx())));
+ &format!("resolved vtable bad vtable {:?} in trans",
+ vtable));
}
}
}
let node_substs = node_id_substs(ccx, node, bcx.fcx.param_substs);
- debug!("rcvr_substs={}", rcvr_substs.repr(ccx.tcx()));
- debug!("node_substs={}", node_substs.repr(ccx.tcx()));
+ debug!("rcvr_substs={:?}", rcvr_substs);
+ debug!("node_substs={:?}", node_substs);
// Break apart the type parameters from the node and type
// parameters from the receiver.
self_datum.val
};
- trans_trait_callee_from_llval(bcx, method_ty, vtable_index, llval)
+ let llself = Load(bcx, GEPi(bcx, llval, &[0, abi::FAT_PTR_ADDR]));
+ let llvtable = Load(bcx, GEPi(bcx, llval, &[0, abi::FAT_PTR_EXTRA]));
+ trans_trait_callee_from_llval(bcx, method_ty, vtable_index, llself, llvtable)
}
/// Same as `trans_trait_callee()` above, except that it is given a by-ref pointer to the object
pub fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
callee_ty: Ty<'tcx>,
vtable_index: usize,
- llpair: ValueRef)
+ llself: ValueRef,
+ llvtable: ValueRef)
-> Callee<'blk, 'tcx> {
let _icx = push_ctxt("meth::trans_trait_callee");
let ccx = bcx.ccx();
// Load the data pointer from the object.
- debug!("trans_trait_callee_from_llval(callee_ty={}, vtable_index={}, llpair={})",
- callee_ty.repr(ccx.tcx()),
+ debug!("trans_trait_callee_from_llval(callee_ty={}, vtable_index={}, llself={}, llvtable={})",
+ callee_ty,
vtable_index,
- bcx.val_to_string(llpair));
- let llboxptr = GEPi(bcx, llpair, &[0, abi::FAT_PTR_ADDR]);
- let llbox = Load(bcx, llboxptr);
- let llself = PointerCast(bcx, llbox, Type::i8p(ccx));
+ bcx.val_to_string(llself),
+ bcx.val_to_string(llvtable));
// Replace the self type (&Self or Box<Self>) with an opaque pointer.
let llcallee_ty = match callee_ty.sty {
- ty::ty_bare_fn(_, ref f) if f.abi == Rust || f.abi == RustCall => {
+ ty::TyBareFn(_, ref f) if f.abi == Rust || f.abi == RustCall => {
let fake_sig =
ty::Binder(ty::FnSig {
inputs: f.sig.0.inputs[1..].to_vec(),
ccx.sess().bug("meth::trans_trait_callee given non-bare-rust-fn");
}
};
- let llvtable = Load(bcx,
- PointerCast(bcx,
- GEPi(bcx, llpair,
- &[0, abi::FAT_PTR_EXTRA]),
- Type::vtable(ccx).ptr_to().ptr_to()));
- let mptr = Load(bcx, GEPi(bcx, llvtable, &[0, vtable_index + VTABLE_OFFSET]));
- let mptr = PointerCast(bcx, mptr, llcallee_ty.ptr_to());
+ let mptr = Load(bcx, GEPi(bcx, llvtable, &[vtable_index + VTABLE_OFFSET]));
return Callee {
bcx: bcx,
data: TraitItem(MethodData {
- llfn: mptr,
- llself: llself,
+ llfn: PointerCast(bcx, mptr, llcallee_ty.ptr_to()),
+ llself: PointerCast(bcx, llself, Type::i8p(ccx)),
})
};
}
let tcx = ccx.tcx();
let trait_id = upcast_trait_ref.def_id();
- debug!("trans_object_shim(object_ty={}, upcast_trait_ref={}, method_offset_in_trait={})",
- object_ty.repr(tcx),
- upcast_trait_ref.repr(tcx),
+ debug!("trans_object_shim(object_ty={:?}, upcast_trait_ref={:?}, method_offset_in_trait={})",
+ object_ty,
+ upcast_trait_ref,
method_offset_in_trait);
let object_trait_ref =
match object_ty.sty {
- ty::ty_trait(ref data) => {
+ ty::TyTrait(ref data) => {
data.principal_trait_ref_with_self_ty(tcx, object_ty)
}
_ => {
- tcx.sess.bug(&format!("trans_object_shim() called on non-object: {}",
- object_ty.repr(tcx)));
+ tcx.sess.bug(&format!("trans_object_shim() called on non-object: {:?}",
+ object_ty));
}
};
// Upcast to the trait in question and extract out the substitutions.
let upcast_trait_ref = ty::erase_late_bound_regions(tcx, &upcast_trait_ref);
let object_substs = upcast_trait_ref.substs.clone().erase_regions();
- debug!("trans_object_shim: object_substs={}", object_substs.repr(tcx));
+ debug!("trans_object_shim: object_substs={:?}", object_substs);
// Lookup the type of this method as declared in the trait and apply substitutions.
let method_ty = match ty::trait_item(tcx, trait_id, method_offset_in_trait) {
let fty = monomorphize::apply_param_substs(tcx, &object_substs, &method_ty.fty);
let fty = tcx.mk_bare_fn(fty);
let method_ty = opaque_method_ty(tcx, fty);
- debug!("trans_object_shim: fty={} method_ty={}", fty.repr(tcx), method_ty.repr(tcx));
+ debug!("trans_object_shim: fty={:?} method_ty={:?}", fty, method_ty);
//
let shim_fn_ty = ty::mk_bare_fn(tcx, None, fty);
&block_arena);
let mut bcx = init_function(&fcx, false, sig.output);
- // the first argument (`self`) will be a trait object
- let llobject = get_param(fcx.llfn, fcx.arg_pos(0) as u32);
-
- debug!("trans_object_shim: llobject={}",
- bcx.val_to_string(llobject));
-
- // the remaining arguments will be, well, whatever they are
- let input_tys =
- match fty.abi {
- RustCall => {
- // unpack the tuple to extract the input type arguments:
- match sig.inputs[1].sty {
- ty::ty_tup(ref tys) => &**tys,
- _ => {
- bcx.sess().bug(
- &format!("rust-call expects a tuple not {}",
- sig.inputs[1].repr(tcx)));
- }
- }
- }
- _ => {
- // skip the self parameter:
- &sig.inputs[1..]
- }
- };
+ let llargs = get_params(fcx.llfn);
- let llargs: Vec<_> =
- input_tys.iter()
- .enumerate()
- .map(|(i, _)| {
- let llarg = get_param(fcx.llfn, fcx.arg_pos(i+1) as u32);
- debug!("trans_object_shim: input #{} == {}",
- i, bcx.val_to_string(llarg));
- llarg
- })
- .collect();
+ let self_idx = fcx.arg_offset();
+ let llself = llargs[self_idx];
+ let llvtable = llargs[self_idx + 1];
+
+ debug!("trans_object_shim: llself={}, llvtable={}",
+ bcx.val_to_string(llself), bcx.val_to_string(llvtable));
assert!(!fcx.needs_ret_allocas);
|bcx, _| trans_trait_callee_from_llval(bcx,
method_bare_fn_ty,
method_offset_in_vtable,
- llobject),
- ArgVals(&llargs),
+ llself, llvtable),
+ ArgVals(&llargs[(self_idx + 2)..]),
dest).bcx;
finish_fn(&fcx, bcx, sig.output, DebugLoc::None);
let tcx = ccx.tcx();
let _icx = push_ctxt("meth::get_vtable");
- debug!("get_vtable(trait_ref={})", trait_ref.repr(tcx));
+ debug!("get_vtable(trait_ref={:?})", trait_ref);
// Check the cache.
match ccx.vtables().borrow().get(&trait_ref) {
nested: _ }) => {
emit_vtable_methods(ccx, id, substs, param_substs).into_iter()
}
- traits::VtableClosure(closure_def_id, substs) => {
+ traits::VtableClosure(
+ traits::VtableClosureData {
+ closure_def_id,
+ substs,
+ nested: _ }) => {
let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_ref.def_id()).unwrap();
let llfn = closure::trans_closure_method(ccx,
closure_def_id,
// an object type; this cannot happen because we
// cannot cast an unsized type into a trait object
tcx.sess.bug(
- &format!("cannot get vtable for an object type: {}",
- data.repr(tcx)));
+ &format!("cannot get vtable for an object type: {:?}",
+ data));
}
traits::VtableParam(..) => {
tcx.sess.bug(
- &format!("resolved vtable for {} to bad vtable {} in trans",
- trait_ref.repr(tcx),
- vtable.repr(tcx)));
+ &format!("resolved vtable for {:?} to bad vtable {:?} in trans",
+ trait_ref,
+ vtable));
}
}
});
{
let tcx = ccx.tcx();
- debug!("emit_vtable_methods(impl_id={}, substs={}, param_substs={})",
- impl_id.repr(tcx),
- substs.repr(tcx),
- param_substs.repr(tcx));
+ debug!("emit_vtable_methods(impl_id={:?}, substs={:?}, param_substs={:?})",
+ impl_id,
+ substs,
+ param_substs);
let trt_id = match ty::impl_trait_ref(tcx, impl_id) {
Some(t_id) => t_id.def_id,
// method could never be called from this object, just supply
// null.
.map(|trait_method_def_id| {
- debug!("emit_vtable_methods: trait_method_def_id={}",
- trait_method_def_id.repr(tcx));
+ debug!("emit_vtable_methods: trait_method_def_id={:?}",
+ trait_method_def_id);
let trait_method_type = match ty::impl_or_trait_item(tcx, trait_method_def_id) {
ty::MethodTraitItem(m) => m,
return nullptr;
}
- debug!("emit_vtable_methods: trait_method_type={}",
- trait_method_type.repr(tcx));
+ debug!("emit_vtable_methods: trait_method_type={:?}",
+ trait_method_type);
// The substitutions we have are on the impl, so we grab
// the method type from the impl to substitute into.
_ => ccx.sess().bug("should be a method, not other assoc item"),
};
- debug!("emit_vtable_methods: impl_method_type={}",
- impl_method_type.repr(tcx));
+ debug!("emit_vtable_methods: impl_method_type={:?}",
+ impl_method_type);
// If this is a default method, it's possible that it
// relies on where clauses that do not hold for this
use middle::subst::{Subst, Substs};
use middle::traits;
use middle::ty_fold::{TypeFolder, TypeFoldable};
+use rustc::ast_map;
use trans::attributes;
use trans::base::{trans_enum_variant, push_ctxt, get_item_val};
use trans::base::trans_fn;
use trans::declare;
use trans::foreign;
use middle::ty::{self, HasProjectionTypes, Ty};
-use util::ppaux::Repr;
use syntax::abi;
use syntax::ast;
-use syntax::ast_map;
use syntax::ast_util::local_def;
use syntax::attr;
use syntax::codemap::DUMMY_SP;
ref_id: Option<ast::NodeId>)
-> (ValueRef, Ty<'tcx>, bool) {
debug!("monomorphic_fn(\
- fn_id={}, \
- real_substs={}, \
+ fn_id={:?}, \
+ real_substs={:?}, \
ref_id={:?})",
- fn_id.repr(ccx.tcx()),
- psubsts.repr(ccx.tcx()),
+ fn_id,
+ psubsts,
ref_id);
assert!(psubsts.types.all(|t| {
};
let item_ty = ty::lookup_item_type(ccx.tcx(), fn_id).ty;
+
+ debug!("monomorphic_fn about to subst into {:?}", item_ty);
let mono_ty = item_ty.subst(ccx.tcx(), psubsts);
match ccx.monomorphized().borrow().get(&hash_id) {
}
debug!("monomorphic_fn(\
- fn_id={}, \
- psubsts={}, \
+ fn_id={:?}, \
+ psubsts={:?}, \
hash_id={:?})",
- fn_id.repr(ccx.tcx()),
- psubsts.repr(ccx.tcx()),
+ fn_id,
+ psubsts,
hash_id);
}
}
- debug!("monomorphic_fn about to subst into {}", item_ty.repr(ccx.tcx()));
-
- debug!("mono_ty = {} (post-substitution)", mono_ty.repr(ccx.tcx()));
+ debug!("mono_ty = {:?} (post-substitution)", mono_ty);
let mono_ty = normalize_associated_type(ccx.tcx(), &mono_ty);
- debug!("mono_ty = {} (post-normalization)", mono_ty.repr(ccx.tcx()));
+ debug!("mono_ty = {:?} (post-normalization)", mono_ty);
ccx.stats().n_monos.set(ccx.stats().n_monos.get() + 1);
ast_map::NodeItem(i) => {
match *i {
ast::Item {
- node: ast::ItemFn(ref decl, _, abi, _, ref body),
+ node: ast::ItemFn(ref decl, _, _, abi, _, ref body),
..
} => {
let d = mk_lldecl(abi);
param_substs: &Substs<'tcx>,
value: &T)
-> T
- where T : TypeFoldable<'tcx> + Repr<'tcx> + HasProjectionTypes + Clone
+ where T : TypeFoldable<'tcx> + HasProjectionTypes
{
let substituted = value.subst(tcx, param_substs);
normalize_associated_type(tcx, &substituted)
/// and hence we can be sure that all associated types will be
/// completely normalized away.
pub fn normalize_associated_type<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> T
- where T : TypeFoldable<'tcx> + Repr<'tcx> + HasProjectionTypes + Clone
+ where T : TypeFoldable<'tcx> + HasProjectionTypes
{
- debug!("normalize_associated_type(t={})", value.repr(tcx));
+ debug!("normalize_associated_type(t={:?})", value);
let value = erase_regions(tcx, value);
let traits::Normalized { value: result, obligations } =
traits::normalize(&mut selcx, cause, &value);
- debug!("normalize_associated_type: result={} obligations={}",
- result.repr(tcx),
- obligations.repr(tcx));
+ debug!("normalize_associated_type: result={:?} obligations={:?}",
+ result,
+ obligations);
- let mut fulfill_cx = traits::FulfillmentContext::new();
+ let mut fulfill_cx = traits::FulfillmentContext::new(true);
for obligation in obligations {
fulfill_cx.register_predicate_obligation(&infcx, obligation);
}
use trans::type_::Type;
use trans::type_of;
use middle::ty::{self, Ty};
-use util::ppaux::ty_to_string;
use syntax::ast;
use syntax::parse::token::InternedString;
impl<'tcx> VecTypes<'tcx> {
pub fn to_string<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> String {
format!("VecTypes {{unit_ty={}, llunit_ty={}}}",
- ty_to_string(ccx.tcx(), self.unit_ty),
+ self.unit_ty,
ccx.tn().type_to_string(self.llunit_ty))
}
}
// to store the array of the suitable size, so all we have to do is
// generate the content.
- debug!("trans_fixed_vstore(expr={}, dest={})",
- bcx.expr_to_string(expr), dest.to_string(bcx.ccx()));
+ debug!("trans_fixed_vstore(expr={:?}, dest={})",
+ expr, dest.to_string(bcx.ccx()));
let vt = vec_types_from_expr(bcx, expr);
let ccx = fcx.ccx;
let mut bcx = bcx;
- debug!("trans_slice_vec(slice_expr={})",
- bcx.expr_to_string(slice_expr));
+ debug!("trans_slice_vec(slice_expr={:?})",
+ slice_expr);
let vec_ty = node_id_type(bcx, slice_expr.id);
str_lit: InternedString,
dest: Dest)
-> Block<'blk, 'tcx> {
- debug!("trans_lit_str(lit_expr={}, dest={})",
- bcx.expr_to_string(lit_expr),
+ debug!("trans_lit_str(lit_expr={:?}, dest={})",
+ lit_expr,
dest.to_string(bcx.ccx()));
match dest {
let fcx = bcx.fcx;
let mut bcx = bcx;
- debug!("write_content(vt={}, dest={}, vstore_expr={})",
+ debug!("write_content(vt={}, dest={}, vstore_expr={:?})",
vt.to_string(bcx.ccx()),
dest.to_string(bcx.ccx()),
- bcx.expr_to_string(vstore_expr));
+ vstore_expr);
match content_expr.node {
ast::ExprLit(ref lit) => {
let ccx = bcx.ccx();
match vec_ty.sty {
- ty::ty_vec(_, Some(n)) => get_fixed_base_and_len(bcx, llval, n),
- ty::ty_vec(_, None) | ty::ty_str => {
+ ty::TyArray(_, n) => get_fixed_base_and_len(bcx, llval, n),
+ ty::TySlice(_) | ty::TyStr => {
let base = Load(bcx, expr::get_dataptr(bcx, llval));
let len = Load(bcx, expr::get_len(bcx, llval));
(base, len)
}
// Only used for pattern matching.
- ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => {
+ ty::TyBox(ty) | ty::TyRef(_, ty::mt{ty, ..}) => {
let inner = if type_is_sized(bcx.tcx(), ty) {
Load(bcx, llval)
} else {
Type::struct_(ccx, &[], false)
}
- pub fn vtable(ccx: &CrateContext) -> Type {
- Type::array(&Type::i8p(ccx).ptr_to(), 1)
- }
-
pub fn glue_fn(ccx: &CrateContext, t: Type) -> Type {
Type::func(&[t], &Type::void(ccx))
}
use trans::foreign;
use trans::machine;
use middle::ty::{self, RegionEscape, Ty};
-use util::ppaux;
-use util::ppaux::Repr;
use trans::type_::Type;
pub fn arg_is_indirect<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
arg_ty: Ty<'tcx>) -> bool {
- !type_is_immediate(ccx, arg_ty)
+ !type_is_immediate(ccx, arg_ty) && !type_is_fat_ptr(ccx.tcx(), arg_ty)
}
pub fn return_uses_outptr<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
ty: Ty<'tcx>) -> bool {
- !type_is_immediate(ccx, ty)
+ arg_is_indirect(ccx, ty)
}
pub fn type_of_explicit_arg<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
}
match inputs[inputs.len() - 1].sty {
- ty::ty_tup(ref tupled_arguments) => {
+ ty::TyTuple(ref tupled_arguments) => {
debug!("untuple_arguments_if_necessary(): untupling arguments");
for &tupled_argument in tupled_arguments {
result.push(tupled_argument);
abi: abi::Abi)
-> Type
{
- debug!("type_of_rust_fn(sig={},abi={:?})",
- sig.repr(cx.tcx()),
+ debug!("type_of_rust_fn(sig={:?},abi={:?})",
+ sig,
abi);
let sig = ty::erase_late_bound_regions(cx.tcx(), sig);
}
// ... then explicit args.
- let input_tys = inputs.iter().map(|&arg_ty| type_of_explicit_arg(cx, arg_ty));
- atys.extend(input_tys);
+ for input in &inputs {
+ let arg_ty = type_of_explicit_arg(cx, input);
+
+ if type_is_fat_ptr(cx.tcx(), input) {
+ atys.extend(arg_ty.field_types());
+ } else {
+ atys.push(arg_ty);
+ }
+ }
Type::func(&atys[..], &lloutputtype)
}
// Given a function type and a count of ty params, construct an llvm type
pub fn type_of_fn_from_ty<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fty: Ty<'tcx>) -> Type {
match fty.sty {
- ty::ty_bare_fn(_, ref f) => {
+ ty::TyBareFn(_, ref f) => {
// FIXME(#19925) once fn item types are
// zero-sized, we'll need to do something here
if f.abi == abi::Rust || f.abi == abi::RustCall {
Type::struct_(cx, &[Type::i8p(cx), Type::i8p(cx)], false)
}
- ty::ty_bool => Type::bool(cx),
- ty::ty_char => Type::char(cx),
- ty::ty_int(t) => Type::int_from_ty(cx, t),
- ty::ty_uint(t) => Type::uint_from_ty(cx, t),
- ty::ty_float(t) => Type::float_from_ty(cx, t),
+ ty::TyBool => Type::bool(cx),
+ ty::TyChar => Type::char(cx),
+ ty::TyInt(t) => Type::int_from_ty(cx, t),
+ ty::TyUint(t) => Type::uint_from_ty(cx, t),
+ ty::TyFloat(t) => Type::float_from_ty(cx, t),
- ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) | ty::ty_ptr(ty::mt{ty, ..}) => {
+ ty::TyBox(ty) | ty::TyRef(_, ty::mt{ty, ..}) | ty::TyRawPtr(ty::mt{ty, ..}) => {
if type_is_sized(cx.tcx(), ty) {
Type::i8p(cx)
} else {
}
}
- ty::ty_bare_fn(..) => Type::i8p(cx),
+ ty::TyBareFn(..) => Type::i8p(cx),
- ty::ty_vec(ty, Some(size)) => {
+ ty::TyArray(ty, size) => {
let llty = sizing_type_of(cx, ty);
let size = size as u64;
ensure_array_fits_in_address_space(cx, llty, size, t);
Type::array(&llty, size)
}
- ty::ty_tup(ref tys) if tys.is_empty() => {
+ ty::TyTuple(ref tys) if tys.is_empty() => {
Type::nil(cx)
}
- ty::ty_tup(..) | ty::ty_enum(..) | ty::ty_closure(..) => {
+ ty::TyTuple(..) | ty::TyEnum(..) | ty::TyClosure(..) => {
let repr = adt::represent_type(cx, t);
adt::sizing_type_of(cx, &*repr, false)
}
- ty::ty_struct(..) => {
+ ty::TyStruct(..) => {
if ty::type_is_simd(cx.tcx(), t) {
let llet = type_of(cx, ty::simd_type(cx.tcx(), t));
let n = ty::simd_size(cx.tcx(), t) as u64;
}
}
- ty::ty_projection(..) | ty::ty_infer(..) | ty::ty_param(..) | ty::ty_err(..) => {
- cx.sess().bug(&format!("fictitious type {} in sizing_type_of()",
- ppaux::ty_to_string(cx.tcx(), t)))
+ ty::TyProjection(..) | ty::TyInfer(..) | ty::TyParam(..) | ty::TyError(..) => {
+ cx.sess().bug(&format!("fictitious type {:?} in sizing_type_of()",
+ t))
}
- ty::ty_vec(_, None) | ty::ty_trait(..) | ty::ty_str => unreachable!()
+ ty::TySlice(_) | ty::TyTrait(..) | ty::TyStr => unreachable!()
};
cx.llsizingtypes().borrow_mut().insert(t, llsizingty);
None => ()
}
- debug!("type_of {} {:?}", t.repr(cx.tcx()), t.sty);
+ debug!("type_of {:?}", t);
assert!(!t.has_escaping_regions());
if t != t_norm {
let llty = in_memory_type_of(cx, t_norm);
- debug!("--> normalized {} {:?} to {} {:?} llty={}",
- t.repr(cx.tcx()),
+ debug!("--> normalized {:?} {:?} to {:?} {:?} llty={}",
t,
- t_norm.repr(cx.tcx()),
+ t,
+ t_norm,
t_norm,
cx.tn().type_to_string(llty));
cx.lltypes().borrow_mut().insert(t, llty);
}
let mut llty = match t.sty {
- ty::ty_bool => Type::bool(cx),
- ty::ty_char => Type::char(cx),
- ty::ty_int(t) => Type::int_from_ty(cx, t),
- ty::ty_uint(t) => Type::uint_from_ty(cx, t),
- ty::ty_float(t) => Type::float_from_ty(cx, t),
- ty::ty_enum(did, ref substs) => {
+ ty::TyBool => Type::bool(cx),
+ ty::TyChar => Type::char(cx),
+ ty::TyInt(t) => Type::int_from_ty(cx, t),
+ ty::TyUint(t) => Type::uint_from_ty(cx, t),
+ ty::TyFloat(t) => Type::float_from_ty(cx, t),
+ ty::TyEnum(did, ref substs) => {
// Only create the named struct, but don't fill it in. We
// fill it in *after* placing it into the type cache. This
// avoids creating more than one copy of the enum when one
let name = llvm_type_name(cx, did, tps);
adt::incomplete_type_of(cx, &*repr, &name[..])
}
- ty::ty_closure(..) => {
+ ty::TyClosure(..) => {
// Only create the named struct, but don't fill it in. We
// fill it in *after* placing it into the type cache.
let repr = adt::represent_type(cx, t);
adt::incomplete_type_of(cx, &*repr, "closure")
}
- ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) | ty::ty_ptr(ty::mt{ty, ..}) => {
+ ty::TyBox(ty) | ty::TyRef(_, ty::mt{ty, ..}) | ty::TyRawPtr(ty::mt{ty, ..}) => {
if !type_is_sized(cx.tcx(), ty) {
- if let ty::ty_str = ty.sty {
+ if let ty::TyStr = ty.sty {
// This means we get a nicer name in the output (str is always
// unsized).
cx.tn().find_type("str_slice").unwrap()
let ptr_ty = in_memory_type_of(cx, ty).ptr_to();
let unsized_part = ty::struct_tail(cx.tcx(), ty);
let info_ty = match unsized_part.sty {
- ty::ty_str | ty::ty_vec(..) => {
+ ty::TyStr | ty::TyArray(..) | ty::TySlice(_) => {
Type::uint_from_ty(cx, ast::TyUs)
}
- ty::ty_trait(_) => Type::vtable_ptr(cx),
+ ty::TyTrait(_) => Type::vtable_ptr(cx),
_ => panic!("Unexpected type returned from \
- struct_tail: {} for ty={}",
- unsized_part.repr(cx.tcx()), ty.repr(cx.tcx()))
+ struct_tail: {:?} for ty={:?}",
+ unsized_part, ty)
};
Type::struct_(cx, &[ptr_ty, info_ty], false)
}
}
}
- ty::ty_vec(ty, Some(size)) => {
+ ty::TyArray(ty, size) => {
let size = size as u64;
let llty = in_memory_type_of(cx, ty);
ensure_array_fits_in_address_space(cx, llty, size, t);
// traits have the type of u8. This is so that the data pointer inside
// fat pointers is of the right type (e.g. for array accesses), even
// when taking the address of an unsized field in a struct.
- ty::ty_vec(ty, None) => in_memory_type_of(cx, ty),
- ty::ty_str | ty::ty_trait(..) => Type::i8(cx),
+ ty::TySlice(ty) => in_memory_type_of(cx, ty),
+ ty::TyStr | ty::TyTrait(..) => Type::i8(cx),
- ty::ty_bare_fn(..) => {
+ ty::TyBareFn(..) => {
type_of_fn_from_ty(cx, t).ptr_to()
}
- ty::ty_tup(ref tys) if tys.is_empty() => Type::nil(cx),
- ty::ty_tup(..) => {
+ ty::TyTuple(ref tys) if tys.is_empty() => Type::nil(cx),
+ ty::TyTuple(..) => {
let repr = adt::represent_type(cx, t);
adt::type_of(cx, &*repr)
}
- ty::ty_struct(did, ref substs) => {
+ ty::TyStruct(did, ref substs) => {
if ty::type_is_simd(cx.tcx(), t) {
let llet = in_memory_type_of(cx, ty::simd_type(cx.tcx(), t));
let n = ty::simd_size(cx.tcx(), t) as u64;
}
}
- ty::ty_infer(..) => cx.sess().bug("type_of with ty_infer"),
- ty::ty_projection(..) => cx.sess().bug("type_of with ty_projection"),
- ty::ty_param(..) => cx.sess().bug("type_of with ty_param"),
- ty::ty_err(..) => cx.sess().bug("type_of with ty_err"),
+ ty::TyInfer(..) => cx.sess().bug("type_of with TyInfer"),
+ ty::TyProjection(..) => cx.sess().bug("type_of with TyProjection"),
+ ty::TyParam(..) => cx.sess().bug("type_of with ty_param"),
+ ty::TyError(..) => cx.sess().bug("type_of with TyError"),
};
- debug!("--> mapped t={} {:?} to llty={}",
- t.repr(cx.tcx()),
+ debug!("--> mapped t={:?} {:?} to llty={}",
+ t,
t,
cx.tn().type_to_string(llty));
// If this was an enum or struct, fill in the type now.
match t.sty {
- ty::ty_enum(..) | ty::ty_struct(..) | ty::ty_closure(..)
+ ty::TyEnum(..) | ty::TyStruct(..) | ty::TyClosure(..)
if !ty::type_is_simd(cx.tcx(), t) => {
let repr = adt::represent_type(cx, t);
adt::finish_type_of(cx, &*repr, &mut llty);
tps: &[Ty<'tcx>])
-> String {
let base = ty::item_path_str(cx.tcx(), did);
- let strings: Vec<String> = tps.iter().map(|t| t.repr(cx.tcx())).collect();
+ let strings: Vec<String> = tps.iter().map(|t| t.to_string()).collect();
let tstr = if strings.is_empty() {
base
} else {
//! an rptr (`&r.T`) use the region `r` that appears in the rptr.
use middle::astconv_util::{prim_ty_to_ty, check_path_args, NO_TPS, NO_REGIONS};
-use middle::const_eval;
+use middle::const_eval::{self, ConstVal};
use middle::def;
use middle::implicator::object_region_bounds;
use middle::resolve_lifetime as rl;
use middle::privacy::{AllPublic, LastMod};
use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs};
use middle::traits;
-use middle::ty::{self, RegionEscape, Ty};
+use middle::ty::{self, RegionEscape, Ty, AsPredicate};
+use middle::ty_fold;
use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope, ExplicitRscope,
ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope};
use util::common::{ErrorReported, FN_OUTPUT_NAME};
use util::nodemap::FnvHashSet;
-use util::ppaux::{self, Repr, UserString};
use std::iter::repeat;
use std::slice;
}
};
- debug!("ast_region_to_region(lifetime={} id={}) yields {}",
- lifetime.repr(tcx),
+ debug!("ast_region_to_region(lifetime={:?} id={}) yields {:?}",
+ lifetime,
lifetime.id,
- r.repr(tcx));
+ r);
r
}
}
};
- debug!("opt_ast_region_to_region(opt_lifetime={}) yields {}",
- opt_lifetime.repr(this.tcx()),
- r.repr(this.tcx()));
+ debug!("opt_ast_region_to_region(opt_lifetime={:?}) yields {:?}",
+ opt_lifetime,
+ r);
r
}
ast::AngleBracketedParameters(ref data) => {
convert_angle_bracketed_parameters(this, rscope, span, decl_generics, data)
}
- ast::ParenthesizedParameters(ref data) => {
+ ast::ParenthesizedParameters(..) => {
span_err!(tcx.sess, span, E0214,
- "parenthesized parameters may only be used with a trait");
- convert_parenthesized_parameters(this, rscope, span, decl_generics, data)
+ "parenthesized parameters may only be used with a trait");
+ let ty_param_defs = decl_generics.types.get_slice(TypeSpace);
+ (Substs::empty(),
+ ty_param_defs.iter().map(|_| tcx.types.err).collect(),
+ vec![])
}
};
{
let tcx = this.tcx();
- debug!("create_substs_for_ast_path(decl_generics={}, self_ty={}, \
- types_provided={}, region_substs={}",
- decl_generics.repr(tcx), self_ty.repr(tcx), types_provided.repr(tcx),
- region_substs.repr(tcx));
+ debug!("create_substs_for_ast_path(decl_generics={:?}, self_ty={:?}, \
+ types_provided={:?}, region_substs={:?}",
+ decl_generics, self_ty, types_provided,
+ region_substs);
assert_eq!(region_substs.regions().len(TypeSpace), decl_generics.regions.len(TypeSpace));
assert!(region_substs.types.is_empty());
// defaults. This will lead to an ICE if we are not
// careful!
if self_ty.is_none() && ty::type_has_self(default) {
- tcx.sess.span_err(
- span,
- &format!("the type parameter `{}` must be explicitly specified \
- in an object type because its default value `{}` references \
- the type `Self`",
- param.name.user_string(tcx),
- default.user_string(tcx)));
+ span_err!(tcx.sess, span, E0393,
+ "the type parameter `{}` must be explicitly specified \
+ in an object type because its default value `{}` references \
+ the type `Self`",
+ param.name,
+ default);
substs.types.push(TypeSpace, tcx.types.err);
} else {
// This is a default type parameter.
let mut lifetimes_for_params: Vec<(String, usize)> = Vec::new();
let mut possible_implied_output_region = None;
- for (input_type, input_pat) in input_tys.iter().zip(input_pats.into_iter()) {
+ for (input_type, input_pat) in input_tys.iter().zip(input_pats) {
let mut accumulator = Vec::new();
ty::accumulate_lifetimes_in_type(&mut accumulator, *input_type);
def::DefTrait(trait_def_id) => trait_def_id,
_ => {
span_fatal!(this.tcx().sess, path.span, E0245, "`{}` is not a trait",
- path.user_string(this.tcx()));
+ path);
}
}
}
let candidate = try!(one_bound_for_assoc_type(tcx,
candidates,
- &trait_ref.user_string(tcx),
+ &trait_ref.to_string(),
&token::get_name(binding.item_name),
binding.span));
});
match (&ty.node, full_span) {
(&ast::TyRptr(None, ref mut_ty), Some(full_span)) => {
+ let mutbl_str = if mut_ty.mutbl == ast::MutMutable { "mut " } else { "" };
this.tcx().sess
.span_suggestion(full_span, "try adding parentheses (per RFC 438):",
format!("&{}({} +{})",
- ppaux::mutability_to_string(mut_ty.mutbl),
+ mutbl_str,
pprust::ty_to_string(&*mut_ty.ty),
pprust::bounds_to_string(bounds)));
}
(&ast::TyRptr(Some(ref lt), ref mut_ty), Some(full_span)) => {
+ let mutbl_str = if mut_ty.mutbl == ast::MutMutable { "mut " } else { "" };
this.tcx().sess
.span_suggestion(full_span, "try adding parentheses (per RFC 438):",
format!("&{} {}({} +{})",
pprust::lifetime_to_string(lt),
- ppaux::mutability_to_string(mut_ty.mutbl),
+ mutbl_str,
pprust::ty_to_string(&*mut_ty.ty),
pprust::bounds_to_string(bounds)));
}
bounds);
let result = make_object_type(this, span, trait_ref, existential_bounds);
- debug!("trait_ref_to_object_type: result={}",
- result.repr(this.tcx()));
+ debug!("trait_ref_to_object_type: result={:?}",
+ result);
result
}
bounds: ty::ExistentialBounds<'tcx>)
-> Ty<'tcx> {
let tcx = this.tcx();
- let object = ty::TyTrait {
+ let object = ty::TraitTy {
principal: principal,
bounds: bounds
};
for (trait_def_id, name) in associated_types {
span_err!(tcx.sess, span, E0191,
"the value of the associated type `{}` (from the trait `{}`) must be specified",
- name.user_string(tcx),
+ name,
ty::item_path_str(tcx, trait_def_id));
}
span_note!(tcx.sess, span,
"associated type `{}` could derive from `{}`",
ty_param_name,
- bound.user_string(tcx));
+ bound);
}
}
let tcx = this.tcx();
let assoc_name = item_segment.identifier.name;
- debug!("associated_path_def_to_ty: {}::{}", ty.repr(tcx), token::get_name(assoc_name));
+ debug!("associated_path_def_to_ty: {:?}::{}", ty, assoc_name);
check_path_args(tcx, slice::ref_slice(item_segment), NO_TPS | NO_REGIONS);
_ => unreachable!()
}
}
- (&ty::ty_param(_), def::DefTyParam(..)) |
- (&ty::ty_param(_), def::DefSelfTy(Some(_), None)) => {
+ (&ty::TyParam(_), def::DefTyParam(..)) |
+ (&ty::TyParam(_), def::DefSelfTy(Some(_), None)) => {
// A type parameter or Self, we need to find the associated item from
// a bound.
let ty_param_node_id = ty_path_def.local_node_id();
_ => {
report_ambiguous_associated_type(tcx,
span,
- &ty.user_string(tcx),
+ &ty.to_string(),
"Trait",
&token::get_name(assoc_name));
return (tcx.types.err, ty_path_def);
return tcx.types.err;
};
- debug!("qpath_to_ty: self_type={}", self_ty.repr(tcx));
+ debug!("qpath_to_ty: self_type={:?}", self_ty);
let trait_ref = ast_path_to_mono_trait_ref(this,
rscope,
Some(self_ty),
trait_segment);
- debug!("qpath_to_ty: trait_ref={}", trait_ref.repr(tcx));
+ debug!("qpath_to_ty: trait_ref={:?}", trait_ref);
this.projected_ty(span, trait_ref, item_segment.identifier.name)
}
// Self in impl (we know the concrete type).
check_path_args(tcx, base_segments, NO_TPS | NO_REGIONS);
if let Some(&ty) = tcx.ast_ty_to_ty_cache.borrow().get(&self_ty_id) {
- ty
+ if let Some(free_substs) = this.get_free_substs() {
+ ty.subst(tcx, free_substs)
+ } else {
+ ty
+ }
} else {
tcx.sess.span_bug(span, "self type has not been fully resolved")
}
let mut def = *def;
// If any associated type segments remain, attempt to resolve them.
for segment in assoc_segments {
- if ty.sty == ty::ty_err {
+ if ty.sty == ty::TyError {
break;
}
// This is pretty bad (it will fail except for T::A and Self::A).
ast_ty: &ast::Ty)
-> Ty<'tcx>
{
- debug!("ast_ty_to_ty(ast_ty={})",
- ast_ty.repr(this.tcx()));
+ debug!("ast_ty_to_ty(ast_ty={:?})",
+ ast_ty);
let tcx = this.tcx();
}
ast::TyRptr(ref region, ref mt) => {
let r = opt_ast_region_to_region(this, rscope, ast_ty.span, region);
- debug!("ty_rptr r={}", r.repr(this.tcx()));
+ debug!("TyRef r={:?}", r);
let rscope1 =
&ObjectLifetimeDefaultRscope::new(
rscope,
- Some(ty::ObjectLifetimeDefault::Specific(r)));
+ ty::ObjectLifetimeDefault::Specific(r));
let t = ast_ty_to_ty(this, rscope1, &*mt.ty);
ty::mk_rptr(tcx, tcx.mk_region(r), ty::mt {ty: t, mutbl: mt.mutbl})
}
ast::TyParen(ref typ) => ast_ty_to_ty(this, rscope, &**typ),
ast::TyBareFn(ref bf) => {
if bf.decl.variadic && bf.abi != abi::C {
- span_err!(tcx.sess, ast_ty.span, E0222,
+ span_err!(tcx.sess, ast_ty.span, E0045,
"variadic function must have C calling convention");
}
let bare_fn = ty_of_bare_fn(this, bf.unsafety, bf.abi, &*bf.decl);
depth: path.segments.len()
}
} else {
- tcx.sess.span_bug(ast_ty.span,
- &format!("unbound path {}", ast_ty.repr(tcx)))
+ tcx.sess.span_bug(ast_ty.span, &format!("unbound path {:?}", ast_ty))
};
let def = path_res.base_def;
let base_ty_end = path.segments.len() - path_res.depth;
&path.segments[..base_ty_end],
&path.segments[base_ty_end..]);
- if path_res.depth != 0 && ty.sty != ty::ty_err {
+ if path_res.depth != 0 && ty.sty != ty::TyError {
// Write back the new resolution.
tcx.def_map.borrow_mut().insert(ast_ty.id, def::PathResolution {
base_def: def,
match const_eval::eval_const_expr_partial(tcx, &**e, Some(tcx.types.usize)) {
Ok(r) => {
match r {
- const_eval::const_int(i) =>
+ ConstVal::Int(i) =>
ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &**ty),
Some(i as usize)),
- const_eval::const_uint(i) =>
+ ConstVal::Uint(i) =>
ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &**ty),
Some(i as usize)),
_ => {
let impl_modifiers = count_modifiers(self_info.untransformed_self_ty);
let method_modifiers = count_modifiers(explicit_type);
- debug!("determine_explicit_self_category(self_info.untransformed_self_ty={} \
- explicit_type={} \
+ debug!("determine_explicit_self_category(self_info.untransformed_self_ty={:?} \
+ explicit_type={:?} \
modifiers=({},{})",
- self_info.untransformed_self_ty.repr(this.tcx()),
- explicit_type.repr(this.tcx()),
+ self_info.untransformed_self_ty,
+ explicit_type,
impl_modifiers,
method_modifiers);
ty::ByValueExplicitSelfCategory
} else {
match explicit_type.sty {
- ty::ty_rptr(r, mt) => ty::ByReferenceExplicitSelfCategory(*r, mt.mutbl),
- ty::ty_uniq(_) => ty::ByBoxExplicitSelfCategory,
+ ty::TyRef(r, mt) => ty::ByReferenceExplicitSelfCategory(*r, mt.mutbl),
+ ty::TyBox(_) => ty::ByBoxExplicitSelfCategory,
_ => ty::ByValueExplicitSelfCategory,
}
}
fn count_modifiers(ty: Ty) -> usize {
match ty.sty {
- ty::ty_rptr(_, mt) => count_modifiers(mt.ty) + 1,
- ty::ty_uniq(t) => count_modifiers(t) + 1,
+ ty::TyRef(_, mt) => count_modifiers(mt.ty) + 1,
+ ty::TyBox(t) => count_modifiers(t) + 1,
_ => 0,
}
}
expected_sig: Option<ty::FnSig<'tcx>>)
-> ty::ClosureTy<'tcx>
{
- debug!("ty_of_closure(expected_sig={})",
- expected_sig.repr(this.tcx()));
+ debug!("ty_of_closure(expected_sig={:?})",
+ expected_sig);
// new region names that appear inside of the fn decl are bound to
// that function type
ast::NoReturn(..) => ty::FnDiverging
};
- debug!("ty_of_closure: input_tys={}", input_tys.repr(this.tcx()));
- debug!("ty_of_closure: output_ty={}", output_ty.repr(this.tcx()));
+ debug!("ty_of_closure: input_tys={:?}", input_tys);
+ debug!("ty_of_closure: output_ty={:?}", output_ty);
ty::ClosureTy {
unsafety: unsafety,
"only the builtin traits can be used as closure or object bounds");
}
- let region_bound = compute_object_lifetime_bound(this,
- rscope,
- span,
- ®ion_bounds,
- principal_trait_ref,
- builtin_bounds);
+ let region_bound =
+ compute_object_lifetime_bound(this,
+ span,
+ ®ion_bounds,
+ principal_trait_ref,
+ builtin_bounds);
+
+ let (region_bound, will_change) = match region_bound {
+ Some(r) => (r, false),
+ None => {
+ match rscope.object_lifetime_default(span) {
+ Some(r) => (r, rscope.object_lifetime_default_will_change_in_1_3()),
+ None => {
+ span_err!(this.tcx().sess, span, E0228,
+ "the lifetime bound for this object type cannot be deduced \
+ from context; please supply an explicit bound");
+ (ty::ReStatic, false)
+ }
+ }
+ }
+ };
+
+ debug!("region_bound: {:?} will_change: {:?}",
+ region_bound, will_change);
ty::sort_bounds_list(&mut projection_bounds);
region_bound: region_bound,
builtin_bounds: builtin_bounds,
projection_bounds: projection_bounds,
+ region_bound_will_change: will_change,
}
}
/// region bounds. It may be that we can derive no bound at all, in which case we return `None`.
fn compute_object_lifetime_bound<'tcx>(
this: &AstConv<'tcx>,
- rscope: &RegionScope,
span: Span,
explicit_region_bounds: &[&ast::Lifetime],
principal_trait_ref: ty::PolyTraitRef<'tcx>,
builtin_bounds: ty::BuiltinBounds)
- -> ty::Region
+ -> Option<ty::Region> // if None, use the default
{
let tcx = this.tcx();
debug!("compute_opt_region_bound(explicit_region_bounds={:?}, \
- principal_trait_ref={}, builtin_bounds={})",
+ principal_trait_ref={:?}, builtin_bounds={:?})",
explicit_region_bounds,
- principal_trait_ref.repr(tcx),
- builtin_bounds.repr(tcx));
+ principal_trait_ref,
+ builtin_bounds);
if explicit_region_bounds.len() > 1 {
span_err!(tcx.sess, explicit_region_bounds[1].span, E0226,
if !explicit_region_bounds.is_empty() {
// Explicitly specified region bound. Use that.
let r = explicit_region_bounds[0];
- return ast_region_to_region(tcx, r);
+ return Some(ast_region_to_region(tcx, r));
}
if let Err(ErrorReported) = this.ensure_super_predicates(span,principal_trait_ref.def_id()) {
- return ty::ReStatic;
+ return Some(ty::ReStatic);
}
// No explicit region bound specified. Therefore, examine trait
object_region_bounds(tcx, &principal_trait_ref, builtin_bounds);
// If there are no derived region bounds, then report back that we
- // can find no region bound.
+ // can find no region bound. The caller will use the default.
if derived_region_bounds.is_empty() {
- match rscope.object_lifetime_default(span) {
- Some(r) => { return r; }
- None => {
- span_err!(this.tcx().sess, span, E0228,
- "the lifetime bound for this object type cannot be deduced \
- from context; please supply an explicit bound");
- return ty::ReStatic;
- }
- }
+ return None;
}
// If any of the derived region bounds are 'static, that is always
// the best choice.
if derived_region_bounds.iter().any(|r| ty::ReStatic == *r) {
- return ty::ReStatic;
+ return Some(ty::ReStatic);
}
// Determine whether there is exactly one unique region in the set
span_err!(tcx.sess, span, E0227,
"ambiguous lifetime bound, explicit lifetime bound required");
}
- return r;
+ return Some(r);
}
pub struct PartitionedBounds<'a> {
ast_bounds: &'a [ast::TyParamBound])
-> PartitionedBounds<'a>
{
- let mut builtin_bounds = ty::empty_builtin_bounds();
+ let mut builtin_bounds = ty::BuiltinBounds::empty();
let mut region_bounds = Vec::new();
let mut trait_bounds = Vec::new();
for ast_bound in ast_bounds {
"wrong number of lifetime parameters: expected {}, found {}",
expected, number);
}
+
+// A helper struct for conveniently grouping a set of bounds which we pass to
+// and return from functions in multiple places.
+#[derive(PartialEq, Eq, Clone, Debug)]
+pub struct Bounds<'tcx> {
+ pub region_bounds: Vec<ty::Region>,
+ pub builtin_bounds: ty::BuiltinBounds,
+ pub trait_bounds: Vec<ty::PolyTraitRef<'tcx>>,
+ pub projection_bounds: Vec<ty::PolyProjectionPredicate<'tcx>>,
+}
+
+impl<'tcx> Bounds<'tcx> {
+ pub fn predicates(&self,
+ tcx: &ty::ctxt<'tcx>,
+ param_ty: Ty<'tcx>)
+ -> Vec<ty::Predicate<'tcx>>
+ {
+ let mut vec = Vec::new();
+
+ for builtin_bound in &self.builtin_bounds {
+ match traits::trait_ref_for_builtin_bound(tcx, builtin_bound, param_ty) {
+ Ok(trait_ref) => { vec.push(trait_ref.as_predicate()); }
+ Err(ErrorReported) => { }
+ }
+ }
+
+ for ®ion_bound in &self.region_bounds {
+ // account for the binder being introduced below; no need to shift `param_ty`
+ // because, at present at least, it can only refer to early-bound regions
+ let region_bound = ty_fold::shift_region(region_bound, 1);
+ vec.push(ty::Binder(ty::OutlivesPredicate(param_ty, region_bound)).as_predicate());
+ }
+
+ for bound_trait_ref in &self.trait_bounds {
+ vec.push(bound_trait_ref.as_predicate());
+ }
+
+ for projection in &self.projection_bounds {
+ vec.push(projection.as_predicate());
+ }
+
+ vec
+ }
+}
use middle::ty::{self, Ty};
use check::{check_expr, check_expr_has_type, check_expr_with_expectation};
use check::{check_expr_coercable_to_type, demand, FnCtxt, Expectation};
+use check::{check_expr_with_lvalue_pref, LvaluePreference};
use check::{instantiate_path, resolve_ty_and_def_ufcs, structurally_resolved_type};
use require_same_types;
use util::nodemap::FnvHashMap;
-use util::ppaux::Repr;
use std::cmp::{self, Ordering};
use std::collections::hash_map::Entry::{Occupied, Vacant};
let fcx = pcx.fcx;
let tcx = pcx.fcx.ccx.tcx;
- debug!("check_pat(pat={},expected={})",
- pat.repr(tcx),
- expected.repr(tcx));
+ debug!("check_pat(pat={:?},expected={:?})",
+ pat,
+ expected);
match pat.node {
ast::PatWild(_) => {
if let ast::ExprLit(ref lt) = lt.node {
if let ast::LitBinary(_) = lt.node {
let expected_ty = structurally_resolved_type(fcx, pat.span, expected);
- if let ty::ty_rptr(_, mt) = expected_ty.sty {
- if let ty::ty_vec(_, None) = mt.ty.sty {
+ if let ty::TyRef(_, mt) = expected_ty.sty {
+ if let ty::TySlice(_) = mt.ty.sty {
pat_ty = ty::mk_slice(tcx, tcx.mk_region(ty::ReStatic),
ty::mt{ ty: tcx.types.u8, mutbl: ast::MutImmutable })
}
demand::suptype(fcx, pat.span, expected, pat_ty);
}
ast::PatRange(ref begin, ref end) => {
- check_expr(fcx, &**begin);
- check_expr(fcx, &**end);
-
- let lhs_ty = fcx.expr_ty(&**begin);
- let rhs_ty = fcx.expr_ty(&**end);
-
- let lhs_eq_rhs =
- require_same_types(
- tcx, Some(fcx.infcx()), false, pat.span, lhs_ty, rhs_ty,
- || "mismatched types in range".to_string());
-
- let numeric_or_char =
- lhs_eq_rhs && (ty::type_is_numeric(lhs_ty) || ty::type_is_char(lhs_ty));
-
- if numeric_or_char {
- match const_eval::compare_lit_exprs(tcx, &**begin, &**end, Some(lhs_ty)) {
- Some(Ordering::Less) |
- Some(Ordering::Equal) => {}
- Some(Ordering::Greater) => {
- span_err!(tcx.sess, begin.span, E0030,
- "lower range bound must be less than upper");
- }
- None => {
- span_err!(tcx.sess, begin.span, E0031,
- "mismatched types in range");
- }
- }
- } else {
- span_err!(tcx.sess, begin.span, E0029,
- "only char and numeric types are allowed in range");
+ check_expr(fcx, begin);
+ check_expr(fcx, end);
+
+ let lhs_ty = fcx.expr_ty(begin);
+ let rhs_ty = fcx.expr_ty(end);
+
+ // Check that both end-points are of numeric or char type.
+ let numeric_or_char = |t| ty::type_is_numeric(t) || ty::type_is_char(t);
+ let lhs_compat = numeric_or_char(lhs_ty);
+ let rhs_compat = numeric_or_char(rhs_ty);
+
+ if !lhs_compat || !rhs_compat {
+ let span = if !lhs_compat && !rhs_compat {
+ pat.span
+ } else if !lhs_compat {
+ begin.span
+ } else {
+ end.span
+ };
+
+ // Note: spacing here is intentional, we want a space before "start" and "end".
+ span_err!(tcx.sess, span, E0029,
+ "only char and numeric types are allowed in range patterns\n \
+ start type: {}\n end type: {}",
+ fcx.infcx().ty_to_string(lhs_ty),
+ fcx.infcx().ty_to_string(rhs_ty)
+ );
+ return;
+ }
+
+ // Check that the types of the end-points can be unified.
+ let types_unify = require_same_types(
+ tcx, Some(fcx.infcx()), false, pat.span, rhs_ty, lhs_ty,
+ || "mismatched types in range".to_string()
+ );
+
+ // It's ok to return without a message as `require_same_types` prints an error.
+ if !types_unify {
+ return;
}
- fcx.write_ty(pat.id, lhs_ty);
+ // Now that we know the types can be unified we find the unified type and use
+ // it to type the entire expression.
+ let common_type = fcx.infcx().resolve_type_vars_if_possible(&lhs_ty);
+
+ fcx.write_ty(pat.id, common_type);
+
+ // Finally we evaluate the constants and check that the range is non-empty.
+ let get_substs = |id| fcx.item_substs()[&id].substs.clone();
+ match const_eval::compare_lit_exprs(tcx, begin, end, Some(&common_type), get_substs) {
+ Some(Ordering::Less) |
+ Some(Ordering::Equal) => {}
+ Some(Ordering::Greater) => {
+ span_err!(tcx.sess, begin.span, E0030,
+ "lower range bound must be less than or equal to upper");
+ }
+ None => tcx.sess.span_bug(begin.span, "literals of different types in range pat")
+ }
// subtyping doesn't matter here, as the value is some kind of scalar
demand::eqtype(fcx, pat.span, expected, lhs_ty);
}
} else {
tcx.sess.span_bug(pat.span,
- &format!("unbound path {}", pat.repr(tcx)))
+ &format!("unbound path {:?}", pat))
};
if let Some((opt_ty, segments, def)) =
resolve_ty_and_def_ufcs(fcx, path_res, Some(self_ty),
let pat_ty = ty::mk_tup(tcx, element_tys.clone());
fcx.write_ty(pat.id, pat_ty);
demand::eqtype(fcx, pat.span, expected, pat_ty);
- for (element_pat, element_ty) in elements.iter().zip(element_tys.into_iter()) {
+ for (element_pat, element_ty) in elements.iter().zip(element_tys) {
check_pat(pcx, &**element_pat, element_ty);
}
}
let expected_ty = structurally_resolved_type(fcx, pat.span, expected);
let inner_ty = fcx.infcx().next_ty_var();
let pat_ty = match expected_ty.sty {
- ty::ty_vec(_, Some(size)) => ty::mk_vec(tcx, inner_ty, Some({
+ ty::TyArray(_, size) => ty::mk_vec(tcx, inner_ty, Some({
let min_len = before.len() + after.len();
match *slice {
Some(_) => cmp::max(min_len, size),
if pat_is_binding(&tcx.def_map, inner) {
let expected = fcx.infcx().shallow_resolve(expected);
ty::deref(expected, true).map_or(true, |mt| match mt.ty.sty {
- ty::ty_trait(_) => {
+ ty::TyTrait(_) => {
// This is "x = SomeTrait" being reduced from
// "let &x = &SomeTrait" or "let box x = Box<SomeTrait>", an error.
span_err!(tcx.sess, span, E0033,
// Not entirely obvious: if matches may create ref bindings, we
// want to use the *precise* type of the discriminant, *not* some
// supertype, as the "discriminant type" (issue #23116).
- let contains_ref_bindings = arms.iter().any(|a| tcx.arm_contains_ref_binding(a));
+ let contains_ref_bindings = arms.iter()
+ .filter_map(|a| tcx.arm_contains_ref_binding(a))
+ .max_by(|m| match *m {
+ ast::MutMutable => 1,
+ ast::MutImmutable => 0,
+ });
let discrim_ty;
- if contains_ref_bindings {
- check_expr(fcx, discrim);
+ if let Some(m) = contains_ref_bindings {
+ check_expr_with_lvalue_pref(fcx, discrim, LvaluePreference::from_mutbl(m));
discrim_ty = fcx.expr_ty(discrim);
} else {
// ...but otherwise we want to use any supertype of the
_ => {
let def_type = ty::lookup_item_type(tcx, def.def_id());
match def_type.ty.sty {
- ty::ty_struct(struct_def_id, _) =>
+ ty::TyStruct(struct_def_id, _) =>
(struct_def_id, struct_def_id),
- ty::ty_enum(enum_def_id, _)
+ ty::TyEnum(enum_def_id, _)
if def == def::DefVariant(enum_def_id, def.def_id(), true) =>
(enum_def_id, def.def_id()),
_ => {
let real_path_ty = fcx.node_ty(pat.id);
let (arg_tys, kind_name): (Vec<_>, &'static str) = match real_path_ty.sty {
- ty::ty_enum(enum_def_id, expected_substs)
+ ty::TyEnum(enum_def_id, expected_substs)
if def == def::DefVariant(enum_def_id, def.def_id(), false) =>
{
let variant = ty::enum_variant_with_id(tcx, enum_def_id, def.def_id());
.collect(),
"variant")
}
- ty::ty_struct(struct_def_id, expected_substs) => {
+ ty::TyStruct(struct_def_id, expected_substs) => {
let struct_fields = ty::struct_fields(tcx, struct_def_id, expected_substs);
(struct_fields.iter()
.map(|field| fcx.instantiate_type_scheme(pat.span,
if let Some(subpats) = subpats {
if subpats.len() == arg_tys.len() {
- for (subpat, arg_ty) in subpats.iter().zip(arg_tys.iter()) {
- check_pat(pcx, &**subpat, *arg_ty);
+ for (subpat, arg_ty) in subpats.iter().zip(arg_tys) {
+ check_pat(pcx, &**subpat, arg_ty);
}
} else if arg_tys.is_empty() {
span_err!(tcx.sess, pat.span, E0024,
use middle::traits::{self, FulfillmentContext, Normalized, MiscObligation,
SelectionContext, ObligationCause};
use middle::ty::{self, HasProjectionTypes};
-use middle::ty_fold::{TypeFoldable, TypeFolder};
+use middle::ty_fold::TypeFoldable;
use syntax::ast;
use syntax::codemap::Span;
-use util::ppaux::Repr;
pub fn normalize_associated_types_in<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
typer: &(ty::ClosureTyper<'tcx>+'a),
body_id: ast::NodeId,
value: &T)
-> T
- where T : TypeFoldable<'tcx> + HasProjectionTypes + Clone + Repr<'tcx>
+ where T : TypeFoldable<'tcx> + HasProjectionTypes
{
- debug!("normalize_associated_types_in(value={})", value.repr(infcx.tcx));
+ debug!("normalize_associated_types_in(value={:?})", value);
let mut selcx = SelectionContext::new(infcx, typer);
let cause = ObligationCause::new(span, body_id, MiscObligation);
let Normalized { value: result, obligations } = traits::normalize(&mut selcx, cause, value);
- debug!("normalize_associated_types_in: result={} predicates={}",
- result.repr(infcx.tcx),
- obligations.repr(infcx.tcx));
+ debug!("normalize_associated_types_in: result={:?} predicates={:?}",
+ result,
+ obligations);
for obligation in obligations {
fulfillment_cx.register_predicate_obligation(infcx, obligation);
}
use syntax::codemap::Span;
use syntax::parse::token;
use syntax::ptr::P;
-use util::ppaux::Repr;
/// Check that it is legal to call methods of the trait corresponding
/// to `trait_id` (this only cares about the trait, not the specific
autoderefs: usize)
-> Option<CallStep<'tcx>>
{
- debug!("try_overloaded_call_step(call_expr={}, adjusted_ty={}, autoderefs={})",
- call_expr.repr(fcx.tcx()),
- adjusted_ty.repr(fcx.tcx()),
+ debug!("try_overloaded_call_step(call_expr={:?}, adjusted_ty={:?}, autoderefs={})",
+ call_expr,
+ adjusted_ty,
autoderefs);
// If the callee is a bare function or a closure, then we're all set.
match structurally_resolved_type(fcx, callee_expr.span, adjusted_ty).sty {
- ty::ty_bare_fn(..) => {
+ ty::TyBareFn(..) => {
fcx.write_autoderef_adjustment(callee_expr.id, autoderefs);
return Some(CallStep::Builtin);
}
- ty::ty_closure(def_id, substs) => {
+ ty::TyClosure(def_id, substs) => {
assert_eq!(def_id.krate, ast::LOCAL_CRATE);
// Check whether this is a call to a closure where we
// over the top. The simplest fix by far is to just ignore
// this case and deref again, so we wind up with
// `FnMut::call_mut(&mut *x, ())`.
- ty::ty_rptr(..) if autoderefs == 0 => {
+ ty::TyRef(..) if autoderefs == 0 => {
return None;
}
-> Option<ty::MethodCallee<'tcx>>
{
// Try the options that are least restrictive on the caller first.
- for &(opt_trait_def_id, method_name) in [
+ for &(opt_trait_def_id, method_name) in &[
(fcx.tcx().lang_items.fn_trait(), token::intern("call")),
(fcx.tcx().lang_items.fn_mut_trait(), token::intern("call_mut")),
(fcx.tcx().lang_items.fn_once_trait(), token::intern("call_once")),
- ].iter() {
+ ] {
let trait_def_id = match opt_trait_def_id {
Some(def_id) => def_id,
None => continue,
let error_fn_sig;
let fn_sig = match callee_ty.sty {
- ty::ty_bare_fn(_, &ty::BareFnTy {ref sig, ..}) => {
+ ty::TyBareFn(_, &ty::BareFnTy {ref sig, ..}) => {
sig
}
_ => {
fcx.inh.method_map.borrow_mut().insert(method_call, method_callee);
}
+#[derive(Debug)]
struct CallResolution<'tcx> {
call_expr: &'tcx ast::Expr,
callee_expr: &'tcx ast::Expr,
closure_def_id: ast::DefId,
}
-impl<'tcx> Repr<'tcx> for CallResolution<'tcx> {
- fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
- format!("CallResolution(call_expr={}, callee_expr={}, adjusted_ty={}, \
- autoderefs={}, fn_sig={}, closure_def_id={})",
- self.call_expr.repr(tcx),
- self.callee_expr.repr(tcx),
- self.adjusted_ty.repr(tcx),
- self.autoderefs,
- self.fn_sig.repr(tcx),
- self.closure_def_id.repr(tcx))
- }
-}
-
impl<'tcx> DeferredCallResolution<'tcx> for CallResolution<'tcx> {
fn resolve<'a>(&mut self, fcx: &FnCtxt<'a,'tcx>) {
- debug!("DeferredCallResolution::resolve() {}",
- self.repr(fcx.tcx()));
+ debug!("DeferredCallResolution::resolve() {:?}",
+ self);
// we should not be invoked until the closure kind has been
// determined by upvar inference
ty::no_late_bound_regions(fcx.tcx(),
ty::ty_fn_sig(method_callee.ty)).unwrap();
- debug!("attempt_resolution: method_callee={}",
- method_callee.repr(fcx.tcx()));
+ debug!("attempt_resolution: method_callee={:?}",
+ method_callee);
for (&method_arg_ty, &self_arg_ty) in
- method_sig.inputs[1..].iter().zip(self.fn_sig.inputs.iter())
+ method_sig.inputs[1..].iter().zip(&self.fn_sig.inputs)
{
demand::eqtype(fcx, self.call_expr.span, self_arg_ty, method_arg_ty);
}
// except according to those terms.
//! Code for type-checking cast expressions.
+//!
+//! A cast `e as U` is valid if one of the following holds:
+//! * `e` has type `T` and `T` coerces to `U`; *coercion-cast*
+//! * `e` has type `*T`, `U` is `*U_0`, and either `U_0: Sized` or
+//! unsize_kind(`T`) = unsize_kind(`U_0`); *ptr-ptr-cast*
+//! * `e` has type `*T` and `U` is a numeric type, while `T: Sized`; *ptr-addr-cast*
+//! * `e` is an integer and `U` is `*U_0`, while `U_0: Sized`; *addr-ptr-cast*
+//! * `e` has type `T` and `T` and `U` are any numeric types; *numeric-cast*
+//! * `e` is a C-like enum and `U` is an integer type; *enum-cast*
+//! * `e` has type `bool` or `char` and `U` is an integer; *prim-int-cast*
+//! * `e` has type `u8` and `U` is `char`; *u8-char-cast*
+//! * `e` has type `&[T; n]` and `U` is `*const T`; *array-ptr-cast*
+//! * `e` is a function pointer type and `U` has type `*T`,
+//! while `T: Sized`; *fptr-ptr-cast*
+//! * `e` is a function pointer type and `U` is an integer; *fptr-addr-cast*
+//!
+//! where `&.T` and `*T` are references of either mutability,
+//! and where unsize_kind(`T`) is the kind of the unsize info
+//! in `T` - the vtable for a trait definition (e.g. `fmt::Display` or
+//! `Iterator`, not `Iterator<Item=u8>`) or a length (or `()` if `T: Sized`).
+//!
+//! Note that lengths are not adjusted when casting raw slices -
+//! `T: *const [u16] as *const [u8]` creates a slice that only includes
+//! half of the original memory.
+//!
+//! Casting is not transitive, that is, even if `e as U1 as U2` is a valid
+//! expression, `e as U2` is not necessarily so (in fact it will only be valid if
+//! `U1` coerces to `U2`).
use super::coercion;
use super::demand;
use super::structurally_resolved_type;
use lint;
-use middle::infer;
+use middle::cast::{CastKind, CastTy};
use middle::ty;
use middle::ty::Ty;
use syntax::ast;
+use syntax::ast::UintTy::{TyU8};
use syntax::codemap::Span;
/// Reifies a cast check to be checked once we have full type information for
span: Span,
}
+/// The kind of the unsize info (length or vtable) - we only allow casts between
+/// fat pointers if their unsize-infos have the same kind.
+#[derive(Copy, Clone, PartialEq, Eq)]
+enum UnsizeKind<'tcx> {
+ Vtable(ast::DefId),
+ Length,
+ /// The unsize info of this projection
+ OfProjection(&'tcx ty::ProjectionTy<'tcx>),
+ /// The unsize info of this parameter
+ OfParam(&'tcx ty::ParamTy)
+}
+
+/// Returns the kind of unsize information of t, or None
+/// if t is sized or it is unknown.
+fn unsize_kind<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>,
+ t: Ty<'tcx>)
+ -> Option<UnsizeKind<'tcx>> {
+ match t.sty {
+ ty::TySlice(_) | ty::TyStr => Some(UnsizeKind::Length),
+ ty::TyTrait(ref tty) => Some(UnsizeKind::Vtable(tty.principal_def_id())),
+ ty::TyStruct(did, substs) => {
+ match ty::struct_fields(fcx.tcx(), did, substs).pop() {
+ None => None,
+ Some(f) => unsize_kind(fcx, f.mt.ty)
+ }
+ }
+ // We should really try to normalize here.
+ ty::TyProjection(ref pi) => Some(UnsizeKind::OfProjection(pi)),
+ ty::TyParam(ref p) => Some(UnsizeKind::OfParam(p)),
+ _ => None
+ }
+}
+
+#[derive(Copy, Clone)]
+enum CastError {
+ CastToBool,
+ CastToChar,
+ DifferingKinds,
+ IllegalCast,
+ NeedViaPtr,
+ NeedViaInt,
+ NeedViaUsize,
+ NonScalar,
+}
+
impl<'tcx> CastCheck<'tcx> {
pub fn new(expr: ast::Expr, expr_ty: Ty<'tcx>, cast_ty: Ty<'tcx>, span: Span)
-> CastCheck<'tcx> {
span: span,
}
}
-}
-pub fn check_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, cast: &CastCheck<'tcx>) {
- fn cast_through_integer_err<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
- span: Span,
- t_1: Ty<'tcx>,
- t_e: Ty<'tcx>) {
- fcx.type_error_message(span, |actual| {
- format!("illegal cast; cast through an \
- integer first: `{}` as `{}`",
- actual,
- fcx.infcx().ty_to_string(t_1))
- }, t_e, None);
+ fn report_cast_error<'a>(&self, fcx: &FnCtxt<'a, 'tcx>,
+ e: CastError) {
+ match e {
+ CastError::NeedViaPtr |
+ CastError::NeedViaInt |
+ CastError::NeedViaUsize => {
+ fcx.type_error_message(self.span, |actual| {
+ format!("illegal cast; cast through {} first: `{}` as `{}`",
+ match e {
+ CastError::NeedViaPtr => "a raw pointer",
+ CastError::NeedViaInt => "an integer",
+ CastError::NeedViaUsize => "a usize",
+ _ => unreachable!()
+ },
+ actual,
+ fcx.infcx().ty_to_string(self.cast_ty))
+ }, self.expr_ty, None)
+ }
+ CastError::CastToBool => {
+ span_err!(fcx.tcx().sess, self.span, E0054,
+ "cannot cast as `bool`, compare with zero instead");
+ }
+ CastError::CastToChar => {
+ fcx.type_error_message(self.span, |actual| {
+ format!("only `u8` can be cast as `char`, not `{}`", actual)
+ }, self.expr_ty, None);
+ }
+ CastError::NonScalar => {
+ fcx.type_error_message(self.span, |actual| {
+ format!("non-scalar cast: `{}` as `{}`",
+ actual,
+ fcx.infcx().ty_to_string(self.cast_ty))
+ }, self.expr_ty, None);
+ }
+ CastError::IllegalCast => {
+ fcx.type_error_message(self.span, |actual| {
+ format!("illegal cast: `{}` as `{}`",
+ actual,
+ fcx.infcx().ty_to_string(self.cast_ty))
+ }, self.expr_ty, None);
+ }
+ CastError::DifferingKinds => {
+ fcx.type_error_message(self.span, |actual| {
+ format!("illegal cast: `{}` as `{}`; vtable kinds may not match",
+ actual,
+ fcx.infcx().ty_to_string(self.cast_ty))
+ }, self.expr_ty, None);
+ }
+ }
+ }
+
+ fn trivial_cast_lint<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) {
+ let t_cast = self.cast_ty;
+ let t_expr = self.expr_ty;
+ if ty::type_is_numeric(t_cast) && ty::type_is_numeric(t_expr) {
+ fcx.tcx().sess.add_lint(lint::builtin::TRIVIAL_NUMERIC_CASTS,
+ self.expr.id,
+ self.span,
+ format!("trivial numeric cast: `{}` as `{}`. Cast can be \
+ replaced by coercion, this might require type \
+ ascription or a temporary variable",
+ fcx.infcx().ty_to_string(t_expr),
+ fcx.infcx().ty_to_string(t_cast)));
+ } else {
+ fcx.tcx().sess.add_lint(lint::builtin::TRIVIAL_CASTS,
+ self.expr.id,
+ self.span,
+ format!("trivial cast: `{}` as `{}`. Cast can be \
+ replaced by coercion, this might require type \
+ ascription or a temporary variable",
+ fcx.infcx().ty_to_string(t_expr),
+ fcx.infcx().ty_to_string(t_cast)));
+ }
+
}
- let span = cast.span;
- let e = &cast.expr;
- let t_e = structurally_resolved_type(fcx, span, cast.expr_ty);
- let t_1 = structurally_resolved_type(fcx, span, cast.cast_ty);
- let tcx = fcx.tcx();
-
- // Check for trivial casts.
- if !ty::type_has_ty_infer(t_1) {
- if let Ok(()) = coercion::mk_assignty(fcx, e, t_e, t_1) {
- if ty::type_is_numeric(t_1) && ty::type_is_numeric(t_e) {
- tcx.sess.add_lint(lint::builtin::TRIVIAL_NUMERIC_CASTS,
- e.id,
- span,
- format!("trivial numeric cast: `{}` as `{}`. Cast can be \
- replaced by coercion, this might require type \
- ascription or a temporary variable",
- fcx.infcx().ty_to_string(t_e),
- fcx.infcx().ty_to_string(t_1)));
- } else {
- tcx.sess.add_lint(lint::builtin::TRIVIAL_CASTS,
- e.id,
- span,
- format!("trivial cast: `{}` as `{}`. Cast can be \
- replaced by coercion, this might require type \
- ascription or a temporary variable",
- fcx.infcx().ty_to_string(t_e),
- fcx.infcx().ty_to_string(t_1)));
+ pub fn check<'a>(mut self, fcx: &FnCtxt<'a, 'tcx>) {
+ self.expr_ty = structurally_resolved_type(fcx, self.span, self.expr_ty);
+ self.cast_ty = structurally_resolved_type(fcx, self.span, self.cast_ty);
+
+ debug!("check_cast({}, {:?} as {:?})", self.expr.id, self.expr_ty,
+ self.cast_ty);
+
+ if ty::type_is_error(self.expr_ty) || ty::type_is_error(self.cast_ty) {
+ // No sense in giving duplicate error messages
+ } else if self.try_coercion_cast(fcx) {
+ self.trivial_cast_lint(fcx);
+ debug!(" -> CoercionCast");
+ fcx.tcx().cast_kinds.borrow_mut().insert(self.expr.id,
+ CastKind::CoercionCast);
+ } else { match self.do_check(fcx) {
+ Ok(k) => {
+ debug!(" -> {:?}", k);
+ fcx.tcx().cast_kinds.borrow_mut().insert(self.expr.id, k);
}
- return;
+ Err(e) => self.report_cast_error(fcx, e)
+ };}
+ }
+
+ /// Check a cast, and report an error if one exists. In some cases, this
+ /// can return Ok and create type errors in the fcx rather than returning
+ /// directly. coercion-cast is handled in check instead of here.
+ fn do_check<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<CastKind, CastError> {
+ use middle::cast::IntTy::*;
+ use middle::cast::CastTy::*;
+
+ let (t_from, t_cast) = match (CastTy::from_ty(fcx.tcx(), self.expr_ty),
+ CastTy::from_ty(fcx.tcx(), self.cast_ty)) {
+ (Some(t_from), Some(t_cast)) => (t_from, t_cast),
+ _ => {
+ return Err(CastError::NonScalar)
+ }
+ };
+
+ match (t_from, t_cast) {
+ // These types have invariants! can't cast into them.
+ (_, RPtr(_)) | (_, Int(CEnum)) | (_, FnPtr) => Err(CastError::NonScalar),
+
+ // * -> Bool
+ (_, Int(Bool)) => Err(CastError::CastToBool),
+
+ // * -> Char
+ (Int(U(ast::TyU8)), Int(Char)) => Ok(CastKind::U8CharCast), // u8-char-cast
+ (_, Int(Char)) => Err(CastError::CastToChar),
+
+ // prim -> float,ptr
+ (Int(Bool), Float) | (Int(CEnum), Float) | (Int(Char), Float)
+ => Err(CastError::NeedViaInt),
+ (Int(Bool), Ptr(_)) | (Int(CEnum), Ptr(_)) | (Int(Char), Ptr(_))
+ => Err(CastError::NeedViaUsize),
+
+ // ptr -> *
+ (Ptr(m_e), Ptr(m_c)) => self.check_ptr_ptr_cast(fcx, m_e, m_c), // ptr-ptr-cast
+ (Ptr(m_expr), Int(_)) => self.check_ptr_addr_cast(fcx, m_expr), // ptr-addr-cast
+ (Ptr(_), Float) | (FnPtr, Float) => Err(CastError::NeedViaUsize),
+ (FnPtr, Int(_)) => Ok(CastKind::FnPtrAddrCast),
+ (RPtr(_), Int(_)) | (RPtr(_), Float) => Err(CastError::NeedViaPtr),
+ // * -> ptr
+ (Int(_), Ptr(mt)) => self.check_addr_ptr_cast(fcx, mt), // addr-ptr-cast
+ (FnPtr, Ptr(mt)) => self.check_fptr_ptr_cast(fcx, mt),
+ (Float, Ptr(_)) => Err(CastError::NeedViaUsize),
+ (RPtr(rmt), Ptr(mt)) => self.check_ref_cast(fcx, rmt, mt), // array-ptr-cast
+
+ // prim -> prim
+ (Int(CEnum), Int(_)) => Ok(CastKind::EnumCast),
+ (Int(Char), Int(_)) | (Int(Bool), Int(_)) => Ok(CastKind::PrimIntCast),
+
+ (Int(_), Int(_)) |
+ (Int(_), Float) |
+ (Float, Int(_)) |
+ (Float, Float) => Ok(CastKind::NumericCast),
+
}
}
- let t_e_is_bare_fn_item = ty::type_is_bare_fn_item(t_e);
- let t_e_is_scalar = ty::type_is_scalar(t_e);
- let t_e_is_integral = ty::type_is_integral(t_e);
- let t_e_is_float = ty::type_is_floating_point(t_e);
- let t_e_is_c_enum = ty::type_is_c_like_enum(tcx, t_e);
-
- let t_1_is_scalar = ty::type_is_scalar(t_1);
- let t_1_is_integral = ty::type_is_integral(t_1);
- let t_1_is_char = ty::type_is_char(t_1);
- let t_1_is_bare_fn = ty::type_is_bare_fn(t_1);
- let t_1_is_float = ty::type_is_floating_point(t_1);
- let t_1_is_c_enum = ty::type_is_c_like_enum(tcx, t_1);
- let t1_is_fat_ptr = fcx.type_is_fat_ptr(t_1, span);
-
- // casts to scalars other than `char` and `bare fn` are trivial
- let t_1_is_trivial = t_1_is_scalar && !t_1_is_char && !t_1_is_bare_fn;
-
- if t_e_is_bare_fn_item && t_1_is_bare_fn {
- demand::coerce(fcx, e.span, t_1, &e);
- } else if t_1_is_char {
- let t_e = fcx.infcx().shallow_resolve(t_e);
- if t_e.sty != ty::ty_uint(ast::TyU8) {
- fcx.type_error_message(span, |actual| {
- format!("only `u8` can be cast as `char`, not `{}`", actual)
- }, t_e, None);
+ fn check_ptr_ptr_cast<'a>(&self,
+ fcx: &FnCtxt<'a, 'tcx>,
+ m_expr: &'tcx ty::mt<'tcx>,
+ m_cast: &'tcx ty::mt<'tcx>)
+ -> Result<CastKind, CastError>
+ {
+ debug!("check_ptr_ptr_cast m_expr={:?} m_cast={:?}",
+ m_expr, m_cast);
+ // ptr-ptr cast. vtables must match.
+
+ // Cast to sized is OK
+ if fcx.type_is_known_to_be_sized(m_cast.ty, self.span) {
+ return Ok(CastKind::PtrPtrCast);
}
- } else if t_1.sty == ty::ty_bool {
- span_err!(tcx.sess, span, E0054,
- "cannot cast as `bool`, compare with zero instead");
- } else if t_e_is_float && (t_1_is_scalar || t_1_is_c_enum) &&
- !(t_1_is_integral || t_1_is_float) {
- // Casts from float must go through an integer
- cast_through_integer_err(fcx, span, t_1, t_e)
- } else if t_1_is_float && (t_e_is_scalar || t_e_is_c_enum) &&
- !(t_e_is_integral || t_e_is_float || t_e.sty == ty::ty_bool) {
- // Casts to float must go through an integer or boolean
- cast_through_integer_err(fcx, span, t_1, t_e)
- } else if t_e_is_c_enum && t_1_is_trivial {
- if ty::type_is_unsafe_ptr(t_1) {
- // ... and likewise with C enum -> *T
- cast_through_integer_err(fcx, span, t_1, t_e)
+
+ // sized -> unsized? report illegal cast (don't complain about vtable kinds)
+ if fcx.type_is_known_to_be_sized(m_expr.ty, self.span) {
+ return Err(CastError::IllegalCast);
}
- // casts from C-like enums are allowed
- } else if ty::type_is_region_ptr(t_e) && ty::type_is_unsafe_ptr(t_1) {
- fn types_compatible<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span,
- t1: Ty<'tcx>, t2: Ty<'tcx>) -> bool {
- match t1.sty {
- ty::ty_vec(_, Some(_)) => {}
- _ => return false
- }
- if ty::type_needs_infer(t2) {
- // This prevents this special case from going off when casting
- // to a type that isn't fully specified; e.g. `as *_`. (Issue
- // #14893.)
- return false
- }
- let el = ty::sequence_element_type(fcx.tcx(), t1);
- infer::mk_eqty(fcx.infcx(),
- false,
- infer::Misc(sp),
- el,
- t2).is_ok()
+ // vtable kinds must match
+ match (unsize_kind(fcx, m_cast.ty), unsize_kind(fcx, m_expr.ty)) {
+ (Some(a), Some(b)) if a == b => Ok(CastKind::PtrPtrCast),
+ _ => Err(CastError::DifferingKinds)
}
+ }
- // Due to the limitations of LLVM global constants,
- // region pointers end up pointing at copies of
- // vector elements instead of the original values.
- // To allow unsafe pointers to work correctly, we
- // need to special-case obtaining an unsafe pointer
- // from a region pointer to a vector.
-
- /* this cast is only allowed from &[T, ..n] to *T or
- &T to *T. */
- match (&t_e.sty, &t_1.sty) {
- (&ty::ty_rptr(_, ty::mt { ty: mt1, mutbl: ast::MutImmutable }),
- &ty::ty_ptr(ty::mt { ty: mt2, mutbl: ast::MutImmutable }))
- if types_compatible(fcx, e.span, mt1, mt2) => {
- /* this case is allowed */
- }
- _ => {
- demand::coerce(fcx, e.span, t_1, &e);
+ fn check_fptr_ptr_cast<'a>(&self,
+ fcx: &FnCtxt<'a, 'tcx>,
+ m_cast: &'tcx ty::mt<'tcx>)
+ -> Result<CastKind, CastError>
+ {
+ // fptr-ptr cast. must be to sized ptr
+
+ if fcx.type_is_known_to_be_sized(m_cast.ty, self.span) {
+ Ok(CastKind::FnPtrPtrCast)
+ } else {
+ Err(CastError::IllegalCast)
+ }
+ }
+
+ fn check_ptr_addr_cast<'a>(&self,
+ fcx: &FnCtxt<'a, 'tcx>,
+ m_expr: &'tcx ty::mt<'tcx>)
+ -> Result<CastKind, CastError>
+ {
+ // ptr-addr cast. must be from sized ptr
+
+ if fcx.type_is_known_to_be_sized(m_expr.ty, self.span) {
+ Ok(CastKind::PtrAddrCast)
+ } else {
+ Err(CastError::NeedViaPtr)
+ }
+ }
+
+ fn check_ref_cast<'a>(&self,
+ fcx: &FnCtxt<'a, 'tcx>,
+ m_expr: &'tcx ty::mt<'tcx>,
+ m_cast: &'tcx ty::mt<'tcx>)
+ -> Result<CastKind, CastError>
+ {
+ // array-ptr-cast.
+
+ if m_expr.mutbl == ast::MutImmutable && m_cast.mutbl == ast::MutImmutable {
+ if let ty::TyArray(ety, _) = m_expr.ty.sty {
+ // Due to the limitations of LLVM global constants,
+ // region pointers end up pointing at copies of
+ // vector elements instead of the original values.
+ // To allow raw pointers to work correctly, we
+ // need to special-case obtaining a raw pointer
+ // from a region pointer to a vector.
+
+ // this will report a type mismatch if needed
+ demand::eqtype(fcx, self.span, ety, m_cast.ty);
+ return Ok(CastKind::ArrayPtrCast);
}
}
- } else if t1_is_fat_ptr {
- // FIXME This should be allowed where the lefthandside is also a fat
- // pointer and is the same kind of fat pointer, i.e., array to array,
- // trait object to trait object. That is a bit looser than the current
- // rquirement that they are pointers to the same type.
- if !(fcx.type_is_fat_ptr(t_e, span) &&
- ty::deref(t_1, true).unwrap().ty == ty::deref(t_e, true).unwrap().ty) {
- fcx.type_error_message(span, |actual| {
- format!("cast to fat pointer: `{}` as `{}`",
- actual,
- fcx.infcx().ty_to_string(t_1))
- }, t_e, None);
+
+ Err(CastError::IllegalCast)
+ }
+
+ fn check_addr_ptr_cast<'a>(&self,
+ fcx: &FnCtxt<'a, 'tcx>,
+ m_cast: &'tcx ty::mt<'tcx>)
+ -> Result<CastKind, CastError>
+ {
+ // ptr-addr cast. pointer must be thin.
+ if fcx.type_is_known_to_be_sized(m_cast.ty, self.span) {
+ Ok(CastKind::AddrPtrCast)
+ } else {
+ Err(CastError::IllegalCast)
}
- } else if !(t_e_is_scalar && t_1_is_trivial) {
- fcx.type_error_message(span, |actual| {
- format!("non-scalar cast: `{}` as `{}`",
- actual,
- fcx.infcx().ty_to_string(t_1))
- }, t_e, None);
}
+
+ fn try_coercion_cast<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) -> bool {
+ if let Ok(()) = coercion::mk_assignty(fcx,
+ &self.expr,
+ self.expr_ty,
+ self.cast_ty) {
+ true
+ } else {
+ false
+ }
+ }
+
}
use syntax::abi;
use syntax::ast;
use syntax::ast_util;
-use util::ppaux::Repr;
pub fn check_expr_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
expr: &ast::Expr,
decl: &'tcx ast::FnDecl,
body: &'tcx ast::Block,
expected: Expectation<'tcx>) {
- debug!("check_expr_closure(expr={},expected={})",
- expr.repr(fcx.tcx()),
- expected.repr(fcx.tcx()));
+ debug!("check_expr_closure(expr={:?},expected={:?})",
+ expr,
+ expected);
// It's always helpful for inference if we know the kind of
// closure sooner rather than later, so first examine the expected
expected_sig: Option<ty::FnSig<'tcx>>) {
let expr_def_id = ast_util::local_def(expr.id);
- debug!("check_closure opt_kind={:?} expected_sig={}",
+ debug!("check_closure opt_kind={:?} expected_sig={:?}",
opt_kind,
- expected_sig.repr(fcx.tcx()));
+ expected_sig);
let mut fn_ty = astconv::ty_of_closure(
fcx,
// the `closures` table.
fn_ty.sig.0.inputs = vec![ty::mk_tup(fcx.tcx(), fn_ty.sig.0.inputs)];
- debug!("closure for {} --> sig={} opt_kind={:?}",
- expr_def_id.repr(fcx.tcx()),
- fn_ty.sig.repr(fcx.tcx()),
+ debug!("closure for {:?} --> sig={:?} opt_kind={:?}",
+ expr_def_id,
+ fn_ty.sig,
opt_kind);
fcx.inh.closure_tys.borrow_mut().insert(expr_def_id, fn_ty);
expected_ty: Ty<'tcx>)
-> (Option<ty::FnSig<'tcx>>,Option<ty::ClosureKind>)
{
- debug!("deduce_expectations_from_expected_type(expected_ty={})",
- expected_ty.repr(fcx.tcx()));
+ debug!("deduce_expectations_from_expected_type(expected_ty={:?})",
+ expected_ty);
match expected_ty.sty {
- ty::ty_trait(ref object_type) => {
+ ty::TyTrait(ref object_type) => {
let proj_bounds = object_type.projection_bounds_with_self_ty(fcx.tcx(),
fcx.tcx().types.err);
let sig = proj_bounds.iter()
let kind = fcx.tcx().lang_items.fn_trait_kind(object_type.principal_def_id());
(sig, kind)
}
- ty::ty_infer(ty::TyVar(vid)) => {
+ ty::TyInfer(ty::TyVar(vid)) => {
deduce_expectations_from_obligations(fcx, vid)
}
_ => {
.pending_obligations()
.iter()
.filter_map(|obligation| {
- debug!("deduce_expectations_from_obligations: obligation.predicate={}",
- obligation.predicate.repr(fcx.tcx()));
+ debug!("deduce_expectations_from_obligations: obligation.predicate={:?}",
+ obligation.predicate);
match obligation.predicate {
// Given a Projection predicate, we can potentially infer
{
let tcx = fcx.tcx();
- debug!("deduce_sig_from_projection({})",
- projection.repr(tcx));
+ debug!("deduce_sig_from_projection({:?})",
+ projection);
let trait_ref = projection.to_poly_trait_ref();
let arg_param_ty = *trait_ref.substs().types.get(subst::TypeSpace, 0);
let arg_param_ty = fcx.infcx().resolve_type_vars_if_possible(&arg_param_ty);
- debug!("deduce_sig_from_projection: arg_param_ty {}", arg_param_ty.repr(tcx));
+ debug!("deduce_sig_from_projection: arg_param_ty {:?}", arg_param_ty);
let input_tys = match arg_param_ty.sty {
- ty::ty_tup(ref tys) => { (*tys).clone() }
+ ty::TyTuple(ref tys) => { (*tys).clone() }
_ => { return None; }
};
- debug!("deduce_sig_from_projection: input_tys {}", input_tys.repr(tcx));
+ debug!("deduce_sig_from_projection: input_tys {:?}", input_tys);
let ret_param_ty = projection.0.ty;
let ret_param_ty = fcx.infcx().resolve_type_vars_if_possible(&ret_param_ty);
- debug!("deduce_sig_from_projection: ret_param_ty {}", ret_param_ty.repr(tcx));
+ debug!("deduce_sig_from_projection: ret_param_ty {:?}", ret_param_ty);
let fn_sig = ty::FnSig {
inputs: input_tys,
output: ty::FnConverging(ret_param_ty),
variadic: false
};
- debug!("deduce_sig_from_projection: fn_sig {}", fn_sig.repr(tcx));
+ debug!("deduce_sig_from_projection: fn_sig {:?}", fn_sig);
Some(fn_sig)
}
-> Option<ty::PolyTraitRef<'tcx>>
{
let self_ty = fcx.infcx().shallow_resolve(trait_ref.self_ty());
- debug!("self_type_matches_expected_vid(trait_ref={}, self_ty={})",
- trait_ref.repr(fcx.tcx()),
- self_ty.repr(fcx.tcx()));
+ debug!("self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?})",
+ trait_ref,
+ self_ty);
match self_ty.sty {
- ty::ty_infer(ty::TyVar(v)) if expected_vid == v => Some(trait_ref),
+ ty::TyInfer(ty::TyVar(v)) if expected_vid == v => Some(trait_ref),
_ => None,
}
}
//! sort of a minor point so I've opted to leave it for later---after all
//! we may want to adjust precisely when coercions occur.
-use check::{autoderef, FnCtxt, NoPreference, PreferMutLvalue, UnresolvedTypeAction};
+use check::{autoderef, FnCtxt, LvaluePreference, UnresolvedTypeAction};
use middle::infer::{self, Coercion};
use middle::traits::{self, ObligationCause};
use middle::ty::{self, mt, Ty};
use middle::ty_relate::RelateResult;
use util::common::indent;
-use util::ppaux::Repr;
use std::cell::RefCell;
use std::collections::VecDeque;
a: Ty<'tcx>,
b: Ty<'tcx>)
-> CoerceResult<'tcx> {
- debug!("Coerce.tys({} => {})",
- a.repr(self.tcx()),
- b.repr(self.tcx()));
+ debug!("Coerce.tys({:?} => {:?})",
+ a,
+ b);
// Consider coercing the subtype to a DST
let unsize = self.unpack_actual_value(a, |a| {
// Note: does not attempt to resolve type variables we encounter.
// See above for details.
match b.sty {
- ty::ty_ptr(mt_b) => {
+ ty::TyRawPtr(mt_b) => {
return self.unpack_actual_value(a, |a| {
self.coerce_unsafe_ptr(a, b, mt_b.mutbl)
});
}
- ty::ty_rptr(_, mt_b) => {
+ ty::TyRef(_, mt_b) => {
return self.unpack_actual_value(a, |a| {
self.coerce_borrowed_pointer(expr_a, a, b, mt_b.mutbl)
});
self.unpack_actual_value(a, |a| {
match a.sty {
- ty::ty_bare_fn(Some(_), a_f) => {
+ ty::TyBareFn(Some(_), a_f) => {
// Function items are coercible to any closure
// type; function pointers are not (that would
// require double indirection).
self.coerce_from_fn_item(a, a_f, b)
}
- ty::ty_bare_fn(None, a_f) => {
+ ty::TyBareFn(None, a_f) => {
// We permit coercion of fn pointers to drop the
// unsafe qualifier.
self.coerce_from_fn_pointer(a, a_f, b)
b: Ty<'tcx>,
mutbl_b: ast::Mutability)
-> CoerceResult<'tcx> {
- debug!("coerce_borrowed_pointer(a={}, b={})",
- a.repr(self.tcx()),
- b.repr(self.tcx()));
+ debug!("coerce_borrowed_pointer(a={:?}, b={:?})",
+ a,
+ b);
// If we have a parameter of type `&M T_a` and the value
// provided is `expr`, we will be adding an implicit borrow,
// yield.
match a.sty {
- ty::ty_rptr(_, mt_a) => {
+ ty::TyRef(_, mt_a) => {
try!(coerce_mutbls(mt_a.mutbl, mutbl_b));
}
_ => return self.subtype(a, b)
let r_borrow = self.tcx().mk_region(r_borrow);
let autoref = Some(ty::AutoPtr(r_borrow, mutbl_b));
- let lvalue_pref = match mutbl_b {
- ast::MutMutable => PreferMutLvalue,
- ast::MutImmutable => NoPreference
- };
+ let lvalue_pref = LvaluePreference::from_mutbl(mutbl_b);
let mut first_error = None;
let (_, autoderefs, success) = autoderef(self.fcx,
expr_a.span,
}
- // &[T, ..n] or &mut [T, ..n] -> &[T]
- // or &mut [T, ..n] -> &mut [T]
+ // &[T; n] or &mut [T; n] -> &[T]
+ // or &mut [T; n] -> &mut [T]
// or &Concrete -> &Trait, etc.
fn coerce_unsized(&self,
source: Ty<'tcx>,
target: Ty<'tcx>)
-> CoerceResult<'tcx> {
- debug!("coerce_unsized(source={}, target={})",
- source.repr(self.tcx()),
- target.repr(self.tcx()));
+ debug!("coerce_unsized(source={:?}, target={:?})",
+ source,
+ target);
let traits = (self.tcx().lang_items.unsize_trait(),
self.tcx().lang_items.coerce_unsized_trait());
// Handle reborrows before selecting `Source: CoerceUnsized<Target>`.
let (source, reborrow) = match (&source.sty, &target.sty) {
- (&ty::ty_rptr(_, mt_a), &ty::ty_rptr(_, mt_b)) => {
+ (&ty::TyRef(_, mt_a), &ty::TyRef(_, mt_b)) => {
try!(coerce_mutbls(mt_a.mutbl, mt_b.mutbl));
let coercion = Coercion(self.origin.span());
let region = self.tcx().mk_region(r_borrow);
(mt_a.ty, Some(ty::AutoPtr(region, mt_b.mutbl)))
}
- (&ty::ty_rptr(_, mt_a), &ty::ty_ptr(mt_b)) => {
+ (&ty::TyRef(_, mt_a), &ty::TyRawPtr(mt_b)) => {
try!(coerce_mutbls(mt_a.mutbl, mt_b.mutbl));
(mt_a.ty, Some(ty::AutoUnsafe(mt_b.mutbl)))
}
// inference might unify those two inner type variables later.
let traits = [coerce_unsized_did, unsize_did];
while let Some(obligation) = queue.pop_front() {
- debug!("coerce_unsized resolve step: {}", obligation.repr(self.tcx()));
+ debug!("coerce_unsized resolve step: {:?}", obligation);
let trait_ref = match obligation.predicate {
ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => {
tr.clone()
}
Ok(Some(vtable)) => {
- vtable.map_move_nested(|o| queue.push_back(o));
+ for obligation in vtable.nested_obligations() {
+ queue.push_back(obligation);
+ }
}
}
}
autoref: reborrow,
unsize: Some(target)
};
- debug!("Success, coerced with {}", adjustment.repr(self.tcx()));
+ debug!("Success, coerced with {:?}", adjustment);
Ok(Some(AdjustDerefRef(adjustment)))
}
*/
self.unpack_actual_value(b, |b| {
- debug!("coerce_from_fn_pointer(a={}, b={})",
- a.repr(self.tcx()), b.repr(self.tcx()));
+ debug!("coerce_from_fn_pointer(a={:?}, b={:?})",
+ a, b);
- if let ty::ty_bare_fn(None, fn_ty_b) = b.sty {
+ if let ty::TyBareFn(None, fn_ty_b) = b.sty {
match (fn_ty_a.unsafety, fn_ty_b.unsafety) {
(ast::Unsafety::Normal, ast::Unsafety::Unsafe) => {
let unsafe_a = self.tcx().safe_to_unsafe_fn_ty(fn_ty_a);
*/
self.unpack_actual_value(b, |b| {
- debug!("coerce_from_fn_item(a={}, b={})",
- a.repr(self.tcx()), b.repr(self.tcx()));
+ debug!("coerce_from_fn_item(a={:?}, b={:?})",
+ a, b);
match b.sty {
- ty::ty_bare_fn(None, _) => {
+ ty::TyBareFn(None, _) => {
let a_fn_pointer = ty::mk_bare_fn(self.tcx(), None, fn_ty_a);
try!(self.subtype(a_fn_pointer, b));
Ok(Some(ty::AdjustReifyFnPointer))
b: Ty<'tcx>,
mutbl_b: ast::Mutability)
-> CoerceResult<'tcx> {
- debug!("coerce_unsafe_ptr(a={}, b={})",
- a.repr(self.tcx()),
- b.repr(self.tcx()));
+ debug!("coerce_unsafe_ptr(a={:?}, b={:?})",
+ a,
+ b);
- let mt_a = match a.sty {
- ty::ty_rptr(_, mt) | ty::ty_ptr(mt) => mt,
+ let (is_ref, mt_a) = match a.sty {
+ ty::TyRef(_, mt) => (true, mt),
+ ty::TyRawPtr(mt) => (false, mt),
_ => {
return self.subtype(a, b);
}
// Although references and unsafe ptrs have the same
// representation, we still register an AutoDerefRef so that
// regionck knows that the region for `a` must be valid here.
- Ok(Some(AdjustDerefRef(AutoDerefRef {
- autoderefs: 1,
- autoref: Some(ty::AutoUnsafe(mutbl_b)),
- unsize: None
- })))
+ if is_ref {
+ Ok(Some(AdjustDerefRef(AutoDerefRef {
+ autoderefs: 1,
+ autoref: Some(ty::AutoUnsafe(mutbl_b)),
+ unsize: None
+ })))
+ } else {
+ Ok(None)
+ }
}
}
a: Ty<'tcx>,
b: Ty<'tcx>)
-> RelateResult<'tcx, ()> {
- debug!("mk_assignty({} -> {})", a.repr(fcx.tcx()), b.repr(fcx.tcx()));
+ debug!("mk_assignty({:?} -> {:?})", a, b);
let mut unsizing_obligations = vec![];
let adjustment = try!(indent(|| {
fcx.infcx().commit_if_ok(|_| {
}
if let Some(adjustment) = adjustment {
- debug!("Success, coerced with {}", adjustment.repr(fcx.tcx()));
+ debug!("Success, coerced with {:?}", adjustment);
fcx.write_adjustment(expr.id, adjustment);
}
Ok(())
use middle::traits;
use middle::ty::{self};
use middle::subst::{self, Subst, Substs, VecPerParamSpace};
-use util::ppaux::{self, Repr};
use syntax::ast;
use syntax::codemap::Span;
impl_m_body_id: ast::NodeId,
trait_m: &ty::Method<'tcx>,
impl_trait_ref: &ty::TraitRef<'tcx>) {
- debug!("compare_impl_method(impl_trait_ref={})",
- impl_trait_ref.repr(tcx));
+ debug!("compare_impl_method(impl_trait_ref={:?})",
+ impl_trait_ref);
- debug!("compare_impl_method: impl_trait_ref (liberated) = {}",
- impl_trait_ref.repr(tcx));
+ debug!("compare_impl_method: impl_trait_ref (liberated) = {:?}",
+ impl_trait_ref);
let infcx = infer::new_infer_ctxt(tcx);
- let mut fulfillment_cx = traits::FulfillmentContext::new();
+ let mut fulfillment_cx = traits::FulfillmentContext::new(true);
let trait_to_impl_substs = &impl_trait_ref.substs;
span_err!(tcx.sess, impl_m_span, E0185,
"method `{}` has a `{}` declaration in the impl, \
but not in the trait",
- token::get_name(trait_m.name),
- ppaux::explicit_self_category_to_str(
- &impl_m.explicit_self));
+ trait_m.name,
+ impl_m.explicit_self);
return;
}
(_, &ty::StaticExplicitSelfCategory) => {
span_err!(tcx.sess, impl_m_span, E0186,
"method `{}` has a `{}` declaration in the trait, \
but not in the impl",
- token::get_name(trait_m.name),
- ppaux::explicit_self_category_to_str(
- &trait_m.explicit_self));
+ trait_m.name,
+ trait_m.explicit_self);
return;
}
_ => {
.subst(tcx, impl_to_skol_substs)
.with_method(impl_to_skol_substs.types.get_slice(subst::FnSpace).to_vec(),
impl_to_skol_substs.regions().get_slice(subst::FnSpace).to_vec());
- debug!("compare_impl_method: trait_to_skol_substs={}",
- trait_to_skol_substs.repr(tcx));
+ debug!("compare_impl_method: trait_to_skol_substs={:?}",
+ trait_to_skol_substs);
// Check region bounds. FIXME(@jroesch) refactor this away when removing
// ParamBounds.
impl_m_span,
infer::HigherRankedType,
&ty::Binder(impl_bounds));
- debug!("compare_impl_method: impl_bounds={}",
- impl_bounds.repr(tcx));
+ debug!("compare_impl_method: impl_bounds={:?}",
+ impl_bounds);
// Normalize the associated types in the trait_bounds.
let trait_bounds = trait_m.predicates.instantiate(tcx, &trait_to_skol_substs);
let trait_param_env = traits::normalize_param_env_or_error(trait_param_env,
normalize_cause.clone());
- debug!("compare_impl_method: trait_bounds={}",
- trait_param_env.caller_bounds.repr(tcx));
+ debug!("compare_impl_method: trait_bounds={:?}",
+ trait_param_env.caller_bounds);
let mut selcx = traits::SelectionContext::new(&infcx, &trait_param_env);
tcx.mk_bare_fn(ty::BareFnTy { unsafety: impl_m.fty.unsafety,
abi: impl_m.fty.abi,
sig: ty::Binder(impl_sig) }));
- debug!("compare_impl_method: impl_fty={}",
- impl_fty.repr(tcx));
+ debug!("compare_impl_method: impl_fty={:?}",
+ impl_fty);
let (trait_sig, skol_map) =
infcx.skolemize_late_bound_regions(&trait_m.fty.sig, snapshot);
abi: trait_m.fty.abi,
sig: ty::Binder(trait_sig) }));
- debug!("compare_impl_method: trait_fty={}",
- trait_fty.repr(tcx));
+ debug!("compare_impl_method: trait_fty={:?}",
+ trait_fty);
try!(infer::mk_subty(&infcx, false, origin, impl_fty, trait_fty));
match err {
Ok(()) => { }
Err(terr) => {
- debug!("checking trait method for compatibility: impl ty {}, trait ty {}",
- impl_fty.repr(tcx),
- trait_fty.repr(tcx));
+ debug!("checking trait method for compatibility: impl ty {:?}, trait ty {:?}",
+ impl_fty,
+ trait_fty);
span_err!(tcx.sess, impl_m_span, E0053,
"method `{}` has an incompatible type for trait: {}",
token::get_name(trait_m.name),
- ty::type_err_to_str(tcx, &terr));
+ terr);
return;
}
}
let impl_params = impl_generics.regions.get_slice(subst::FnSpace);
debug!("check_region_bounds_on_impl_method: \
- trait_generics={} \
- impl_generics={} \
- trait_to_skol_substs={} \
- impl_to_skol_substs={}",
- trait_generics.repr(tcx),
- impl_generics.repr(tcx),
- trait_to_skol_substs.repr(tcx),
- impl_to_skol_substs.repr(tcx));
+ trait_generics={:?} \
+ impl_generics={:?} \
+ trait_to_skol_substs={:?} \
+ impl_to_skol_substs={:?}",
+ trait_generics,
+ impl_generics,
+ trait_to_skol_substs,
+ impl_to_skol_substs);
// Must have same number of early-bound lifetime parameters.
// Unfortunately, if the user screws up the bounds, then this
impl_c_span: Span,
trait_c: &ty::AssociatedConst<'tcx>,
impl_trait_ref: &ty::TraitRef<'tcx>) {
- debug!("compare_const_impl(impl_trait_ref={})",
- impl_trait_ref.repr(tcx));
+ debug!("compare_const_impl(impl_trait_ref={:?})",
+ impl_trait_ref);
let infcx = infer::new_infer_ctxt(tcx);
- let mut fulfillment_cx = traits::FulfillmentContext::new();
+ let mut fulfillment_cx = traits::FulfillmentContext::new(true);
// The below is for the most part highly similar to the procedure
// for methods above. It is simpler in many respects, especially
.subst(tcx, impl_to_skol_substs)
.with_method(impl_to_skol_substs.types.get_slice(subst::FnSpace).to_vec(),
impl_to_skol_substs.regions().get_slice(subst::FnSpace).to_vec());
- debug!("compare_const_impl: trait_to_skol_substs={}",
- trait_to_skol_substs.repr(tcx));
+ debug!("compare_const_impl: trait_to_skol_substs={:?}",
+ trait_to_skol_substs);
// Compute skolemized form of impl and trait const tys.
let impl_ty = impl_c.ty.subst(tcx, impl_to_skol_substs);
impl_c_span,
0,
&impl_ty);
- debug!("compare_const_impl: impl_ty={}",
- impl_ty.repr(tcx));
+ debug!("compare_const_impl: impl_ty={:?}",
+ impl_ty);
let trait_ty =
assoc::normalize_associated_types_in(&infcx,
impl_c_span,
0,
&trait_ty);
- debug!("compare_const_impl: trait_ty={}",
- trait_ty.repr(tcx));
+ debug!("compare_const_impl: trait_ty={:?}",
+ trait_ty);
infer::mk_subty(&infcx, false, origin, impl_ty, trait_ty)
});
match err {
Ok(()) => { }
Err(terr) => {
- debug!("checking associated const for compatibility: impl ty {}, trait ty {}",
- impl_ty.repr(tcx),
- trait_ty.repr(tcx));
+ debug!("checking associated const for compatibility: impl ty {:?}, trait ty {:?}",
+ impl_ty,
+ trait_ty);
span_err!(tcx.sess, impl_c_span, E0326,
"implemented const `{}` has an incompatible type for \
trait: {}",
token::get_name(trait_c.name),
- ty::type_err_to_str(tcx, &terr));
+ terr);
return;
}
}
use std::result::Result::{Err, Ok};
use syntax::ast;
use syntax::codemap::Span;
-use util::ppaux::Repr;
// Requires that the two types unify, and prints an error message if
// they don't.
expected: Ty<'tcx>,
expr: &ast::Expr) {
let expr_ty = fcx.expr_ty(expr);
- debug!("demand::coerce(expected = {}, expr_ty = {})",
- expected.repr(fcx.ccx.tcx),
- expr_ty.repr(fcx.ccx.tcx));
+ debug!("demand::coerce(expected = {:?}, expr_ty = {:?})",
+ expected,
+ expr_ty);
let expr_ty = fcx.resolve_type_vars_if_possible(expr_ty);
let expected = fcx.resolve_type_vars_if_possible(expected);
match coercion::mk_assignty(fcx, expr, expr_ty, expected) {
use middle::region;
use middle::subst::{self, Subst};
use middle::ty::{self, Ty};
-use util::ppaux::{Repr, UserString};
use syntax::ast;
use syntax::codemap::{self, Span};
///
pub fn check_drop_impl(tcx: &ty::ctxt, drop_impl_did: ast::DefId) -> Result<(), ()> {
let ty::TypeScheme { generics: ref dtor_generics,
- ty: ref dtor_self_type } = ty::lookup_item_type(tcx, drop_impl_did);
+ ty: dtor_self_type } = ty::lookup_item_type(tcx, drop_impl_did);
let dtor_predicates = ty::lookup_predicates(tcx, drop_impl_did);
match dtor_self_type.sty {
- ty::ty_enum(self_type_did, self_to_impl_substs) |
- ty::ty_struct(self_type_did, self_to_impl_substs) |
- ty::ty_closure(self_type_did, self_to_impl_substs) => {
+ ty::TyEnum(self_type_did, self_to_impl_substs) |
+ ty::TyStruct(self_type_did, self_to_impl_substs) |
+ ty::TyClosure(self_type_did, self_to_impl_substs) => {
try!(ensure_drop_params_and_item_params_correspond(tcx,
drop_impl_did,
dtor_generics,
- dtor_self_type,
+ &dtor_self_type,
self_type_did));
ensure_drop_predicates_are_implied_by_item_defn(tcx,
let span = tcx.map.def_id_span(drop_impl_did, codemap::DUMMY_SP);
tcx.sess.span_bug(
span, &format!("should have been rejected by coherence check: {}",
- dtor_self_type.repr(tcx)));
+ dtor_self_type));
}
}
}
if !assumptions_in_impl_context.contains(&predicate) {
let item_span = tcx.map.span(self_type_did.node);
- let req = predicate.user_string(tcx);
span_err!(tcx.sess, drop_impl_span, E0367,
- "The requirement `{}` is added only by the Drop impl.", req);
+ "The requirement `{}` is added only by the Drop impl.", predicate);
tcx.sess.span_note(item_span,
"The same requirement must be part of \
the struct/enum definition");
/// Let `v` be some value (either temporary or named) and 'a be some
/// lifetime (scope). If the type of `v` owns data of type `D`, where
///
-/// (1.) `D` has a lifetime- or type-parametric Drop implementation, and
-/// (2.) the structure of `D` can reach a reference of type `&'a _`, and
-/// (3.) either:
-///
-/// (A.) the Drop impl for `D` instantiates `D` at 'a directly,
+/// * (1.) `D` has a lifetime- or type-parametric Drop implementation, and
+/// * (2.) the structure of `D` can reach a reference of type `&'a _`, and
+/// * (3.) either:
+/// * (A.) the Drop impl for `D` instantiates `D` at 'a directly,
/// i.e. `D<'a>`, or,
-///
-/// (B.) the Drop impl for `D` has some type parameter with a
+/// * (B.) the Drop impl for `D` has some type parameter with a
/// trait bound `T` where `T` is a trait that has at least
/// one method,
///
typ: ty::Ty<'tcx>,
span: Span,
scope: region::CodeExtent) {
- debug!("check_safety_of_destructor_if_necessary typ: {} scope: {:?}",
- typ.repr(rcx.tcx()), scope);
+ debug!("check_safety_of_destructor_if_necessary typ: {:?} scope: {:?}",
+ typ, scope);
// types that have been traversed so far by `traverse_type_if_unseen`
let mut breadcrumbs: Vec<Ty<'tcx>> = Vec::new();
Err(Error::Overflow(ref ctxt, ref detected_on_typ)) => {
let tcx = rcx.tcx();
span_err!(tcx.sess, span, E0320,
- "overflow while adding drop-check rules for {}",
- typ.user_string(rcx.tcx()));
+ "overflow while adding drop-check rules for {}", typ);
match *ctxt {
TypeContext::Root => {
// no need for an additional note if the overflow
ty::item_path_str(tcx, def_id),
variant,
arg_index,
- detected_on_typ.user_string(rcx.tcx()));
+ detected_on_typ);
}
TypeContext::Struct { def_id, field } => {
span_note!(
"overflowed on struct {} field {} type: {}",
ty::item_path_str(tcx, def_id),
field,
- detected_on_typ.user_string(rcx.tcx()));
+ detected_on_typ);
}
}
}
// with `T`, the type it represents as owned by the
// surrounding context, before doing further analysis.
let (typ, xref_depth) = match typ.sty {
- ty::ty_struct(struct_did, substs) => {
+ ty::TyStruct(struct_did, substs) => {
if opt_phantom_data_def_id == Some(struct_did) {
let item_type = ty::lookup_item_type(rcx.tcx(), struct_did);
let tp_def = item_type.generics.types
.opt_get(subst::TypeSpace, 0).unwrap();
let new_typ = substs.type_for_def(tp_def);
- debug!("replacing phantom {} with {}",
- typ.repr(rcx.tcx()), new_typ.repr(rcx.tcx()));
+ debug!("replacing phantom {:?} with {:?}",
+ typ, new_typ);
(new_typ, xref_depth_orig + 1)
} else {
(typ, xref_depth_orig)
}
}
- // Note: When ty_uniq is removed from compiler, the
+ // Note: When TyBox is removed from compiler, the
// definition of `Box<T>` must carry a PhantomData that
// puts us into the previous case.
- ty::ty_uniq(new_typ) => {
- debug!("replacing ty_uniq {} with {}",
- typ.repr(rcx.tcx()), new_typ.repr(rcx.tcx()));
+ ty::TyBox(new_typ) => {
+ debug!("replacing TyBox {:?} with {:?}",
+ typ, new_typ);
(new_typ, xref_depth_orig + 1)
}
};
let dtor_kind = match typ.sty {
- ty::ty_enum(def_id, _) |
- ty::ty_struct(def_id, _) => {
+ ty::TyEnum(def_id, _) |
+ ty::TyStruct(def_id, _) => {
match destructor_for_type.get(&def_id) {
Some(def_id) => DtorKind::KnownDropMethod(*def_id),
None => DtorKind::PureRecur,
}
}
- ty::ty_trait(ref ty_trait) => {
+ ty::TyTrait(ref ty_trait) => {
DtorKind::Unknown(ty_trait.bounds.clone())
}
_ => DtorKind::PureRecur,
debug!("iterate_over_potentially_unsafe_regions_in_type \
{}typ: {} scope: {:?} xref: {}",
(0..depth).map(|_| ' ').collect::<String>(),
- typ.repr(rcx.tcx()), scope, xref_depth);
+ typ, scope, xref_depth);
// If `typ` has a destructor, then we must ensure that all
// borrowed data reachable via `typ` must outlive the parent
// destructor.
match typ.sty {
- ty::ty_struct(struct_did, substs) => {
- debug!("typ: {} is struct; traverse structure and not type-expression",
- typ.repr(rcx.tcx()));
+ ty::TyStruct(struct_did, substs) => {
+ debug!("typ: {:?} is struct; traverse structure and not type-expression",
+ typ);
// Don't recurse; we extract type's substructure,
// so do not process subparts of type expression.
walker.skip_current_subtree();
let fields =
ty::lookup_struct_fields(rcx.tcx(), struct_did);
- for field in fields.iter() {
+ for field in &fields {
let field_type =
ty::lookup_field_type(rcx.tcx(),
struct_did,
}
}
- ty::ty_enum(enum_did, substs) => {
- debug!("typ: {} is enum; traverse structure and not type-expression",
- typ.repr(rcx.tcx()));
+ ty::TyEnum(enum_did, substs) => {
+ debug!("typ: {:?} is enum; traverse structure and not type-expression",
+ typ);
// Don't recurse; we extract type's substructure,
// so do not process subparts of type expression.
walker.skip_current_subtree();
ty::substd_enum_variants(rcx.tcx(),
enum_did,
substs);
- for variant_info in all_variant_info.iter() {
+ for variant_info in &all_variant_info {
for (i, arg_type) in variant_info.args.iter().enumerate() {
try!(iterate_over_potentially_unsafe_regions_in_type(
rcx,
}
}
- ty::ty_rptr(..) | ty::ty_ptr(_) | ty::ty_bare_fn(..) => {
+ ty::TyRef(..) | ty::TyRawPtr(_) | ty::TyBareFn(..) => {
// Don't recurse, since references, pointers,
// and bare functions don't own instances
// of the types appearing within them.
match dtor_kind {
DtorKind::PureRecur => {
has_dtor_of_interest = false;
- debug!("typ: {} has no dtor, and thus is uninteresting",
- typ.repr(tcx));
+ debug!("typ: {:?} has no dtor, and thus is uninteresting",
+ typ);
}
DtorKind::Unknown(bounds) => {
match bounds.region_bound {
ty::ReStatic => {
- debug!("trait: {} has 'static bound, and thus is uninteresting",
- typ.repr(tcx));
+ debug!("trait: {:?} has 'static bound, and thus is uninteresting",
+ typ);
has_dtor_of_interest = false;
}
ty::ReEmpty => {
- debug!("trait: {} has empty region bound, and thus is uninteresting",
- typ.repr(tcx));
+ debug!("trait: {:?} has empty region bound, and thus is uninteresting",
+ typ);
has_dtor_of_interest = false;
}
r => {
- debug!("trait: {} has non-static bound: {}; assumed interesting",
- typ.repr(tcx), r.repr(tcx));
+ debug!("trait: {:?} has non-static bound: {:?}; assumed interesting",
+ typ, r);
has_dtor_of_interest = true;
}
}
if result {
has_pred_of_interest = true;
- debug!("typ: {} has interesting dtor due to generic preds, e.g. {}",
- typ.repr(tcx), pred.repr(tcx));
+ debug!("typ: {:?} has interesting dtor due to generic preds, e.g. {:?}",
+ typ, pred);
break 'items;
}
}
has_pred_of_interest;
if has_dtor_of_interest {
- debug!("typ: {} has interesting dtor, due to \
+ debug!("typ: {:?} has interesting dtor, due to \
region params: {} or pred: {}",
- typ.repr(tcx),
+ typ,
has_region_param_of_interest,
has_pred_of_interest);
} else {
- debug!("typ: {} has dtor, but it is uninteresting",
- typ.repr(tcx));
+ debug!("typ: {:?} has dtor, but it is uninteresting",
+ typ);
}
}
}
Here `ADJ` is some kind of adjustment, which is typically a series of
autoderefs and then possibly an autoref (e.g., `&**receiver`). However
we sometimes do other adjustments and coercions along the way, in
-particular unsizing (e.g., converting from `[T, ..n]` to `[T]`).
+particular unsizing (e.g., converting from `[T; n]` to `[T]`).
## The Two Phases
use syntax::ast;
use syntax::codemap::Span;
use std::iter::repeat;
-use util::ppaux::Repr;
struct ConfirmContext<'a, 'tcx:'a> {
fcx: &'a FnCtxt<'a, 'tcx>,
supplied_method_types: Vec<Ty<'tcx>>)
-> MethodCallee<'tcx>
{
- debug!("confirm(unadjusted_self_ty={}, pick={}, supplied_method_types={})",
- unadjusted_self_ty.repr(fcx.tcx()),
- pick.repr(fcx.tcx()),
- supplied_method_types.repr(fcx.tcx()));
+ debug!("confirm(unadjusted_self_ty={:?}, pick={:?}, supplied_method_types={:?})",
+ unadjusted_self_ty,
+ pick,
+ supplied_method_types);
let mut confirm_cx = ConfirmContext::new(fcx, span, self_expr, call_expr);
confirm_cx.confirm(unadjusted_self_ty, pick, supplied_method_types)
let (method_types, method_regions) =
self.instantiate_method_substs(&pick, supplied_method_types);
let all_substs = rcvr_substs.with_method(method_types, method_regions);
- debug!("all_substs={}", all_substs.repr(self.tcx()));
+ debug!("all_substs={:?}", all_substs);
// Create the final signature for the method, replacing late-bound regions.
let InstantiatedMethodSig {
this.upcast(original_poly_trait_ref.clone(), trait_def_id);
let upcast_trait_ref =
this.replace_late_bound_regions_with_fresh_var(&upcast_poly_trait_ref);
- debug!("original_poly_trait_ref={} upcast_trait_ref={} target_trait={}",
- original_poly_trait_ref.repr(this.tcx()),
- upcast_trait_ref.repr(this.tcx()),
- trait_def_id.repr(this.tcx()));
+ debug!("original_poly_trait_ref={:?} upcast_trait_ref={:?} target_trait={:?}",
+ original_poly_trait_ref,
+ upcast_trait_ref,
+ trait_def_id);
let substs = upcast_trait_ref.substs.clone();
let origin = MethodTraitObject(MethodObject {
trait_ref: upcast_trait_ref,
}
fn extract_trait_ref<R, F>(&mut self, self_ty: Ty<'tcx>, mut closure: F) -> R where
- F: FnMut(&mut ConfirmContext<'a, 'tcx>, Ty<'tcx>, &ty::TyTrait<'tcx>) -> R,
+ F: FnMut(&mut ConfirmContext<'a, 'tcx>, Ty<'tcx>, &ty::TraitTy<'tcx>) -> R,
{
// If we specified that this is an object method, then the
// self-type ought to be something that can be dereferenced to
NoPreference,
|ty, _| {
match ty.sty {
- ty::ty_trait(ref data) => Some(closure(self, ty, &**data)),
+ ty::TyTrait(ref data) => Some(closure(self, ty, &**data)),
_ => None,
}
});
self.tcx().sess.span_bug(
self.span,
&format!("self-type `{}` for ObjectPick never dereferenced to an object",
- self_ty.repr(self.tcx())))
+ self_ty))
}
}
}
Err(_) => {
self.tcx().sess.span_bug(
self.span,
- &format!(
- "{} was a subtype of {} but now is not?",
- self_ty.repr(self.tcx()),
- method_self_ty.repr(self.tcx())));
+ &format!("{} was a subtype of {} but now is not?",
+ self_ty, method_self_ty));
}
}
}
all_substs: subst::Substs<'tcx>)
-> InstantiatedMethodSig<'tcx>
{
- debug!("instantiate_method_sig(pick={}, all_substs={})",
- pick.repr(self.tcx()),
- all_substs.repr(self.tcx()));
+ debug!("instantiate_method_sig(pick={:?}, all_substs={:?})",
+ pick,
+ all_substs);
// Instantiate the bounds on the method with the
// type/early-bound-regions substitutions performed. There can
let method_predicates = self.fcx.normalize_associated_types_in(self.span,
&method_predicates);
- debug!("method_predicates after subst = {}",
- method_predicates.repr(self.tcx()));
+ debug!("method_predicates after subst = {:?}",
+ method_predicates);
// Instantiate late-bound regions and substitute the trait
// parameters into the method type to get the actual method type.
// may reference those regions.
let method_sig = self.replace_late_bound_regions_with_fresh_var(
&pick.item.as_opt_method().unwrap().fty.sig);
- debug!("late-bound lifetimes from method instantiated, method_sig={}",
- method_sig.repr(self.tcx()));
+ debug!("late-bound lifetimes from method instantiated, method_sig={:?}",
+ method_sig);
let method_sig = self.fcx.instantiate_type_scheme(self.span, &all_substs, &method_sig);
- debug!("type scheme substituted, method_sig={}",
- method_sig.repr(self.tcx()));
+ debug!("type scheme substituted, method_sig={:?}",
+ method_sig);
InstantiatedMethodSig {
method_sig: method_sig,
pick: &probe::Pick<'tcx>,
all_substs: &subst::Substs<'tcx>,
method_predicates: &ty::InstantiatedPredicates<'tcx>) {
- debug!("add_obligations: pick={} all_substs={} method_predicates={}",
- pick.repr(self.tcx()),
- all_substs.repr(self.tcx()),
- method_predicates.repr(self.tcx()));
+ debug!("add_obligations: pick={:?} all_substs={:?} method_predicates={:?}",
+ pick,
+ all_substs,
+ method_predicates);
self.fcx.add_obligations_for_parameters(
traits::ObligationCause::misc(self.span, self.fcx.body_id),
fn fixup_derefs_on_method_receiver_if_necessary(&self,
method_callee: &MethodCallee) {
let sig = match method_callee.ty.sty {
- ty::ty_bare_fn(_, ref f) => f.sig.clone(),
+ ty::TyBareFn(_, ref f) => f.sig.clone(),
_ => return,
};
match sig.0.inputs[0].sty {
- ty::ty_rptr(_, ty::mt {
+ ty::TyRef(_, ty::mt {
ty: _,
mutbl: ast::MutMutable,
}) => {}
}
}
- debug!("fixup_derefs_on_method_receiver_if_necessary: exprs={}",
- exprs.repr(self.tcx()));
+ debug!("fixup_derefs_on_method_receiver_if_necessary: exprs={:?}",
+ exprs);
// Fix up autoderefs and derefs.
for (i, &expr) in exprs.iter().rev().enumerate() {
Some(_) | None => 0,
};
- debug!("fixup_derefs_on_method_receiver_if_necessary: i={} expr={} autoderef_count={}",
- i, expr.repr(self.tcx()), autoderef_count);
+ debug!("fixup_derefs_on_method_receiver_if_necessary: i={} expr={:?} \
+ autoderef_count={}",
+ i, expr, autoderef_count);
if autoderef_count > 0 {
check::autoderef(self.fcx,
Some(_) => {
self.tcx().sess.span_bug(
base_expr.span,
- &format!("unexpected adjustment autoref {}",
- adr.repr(self.tcx())));
+ &format!("unexpected adjustment autoref {:?}",
+ adr));
}
},
None => (0, None),
if upcast_trait_refs.len() != 1 {
self.tcx().sess.span_bug(
self.span,
- &format!("cannot uniquely upcast `{}` to `{}`: `{}`",
- source_trait_ref.repr(self.tcx()),
- target_trait_def_id.repr(self.tcx()),
- upcast_trait_refs.repr(self.tcx())));
+ &format!("cannot uniquely upcast `{:?}` to `{:?}`: `{:?}`",
+ source_trait_ref,
+ target_trait_def_id,
+ upcast_trait_refs));
}
upcast_trait_refs.into_iter().next().unwrap()
}
fn replace_late_bound_regions_with_fresh_var<T>(&self, value: &ty::Binder<T>) -> T
- where T : TypeFoldable<'tcx> + Repr<'tcx>
+ where T : TypeFoldable<'tcx>
{
self.infcx().replace_late_bound_regions_with_fresh_var(
self.span, infer::FnCall, value).0
use middle::privacy::{AllPublic, DependsOn, LastPrivate, LastMod};
use middle::subst;
use middle::traits;
-use middle::ty::{self, AsPredicate, ToPolyTraitRef};
+use middle::ty::{self, AsPredicate, ToPolyTraitRef, TraitRef};
use middle::infer;
-use util::ppaux::Repr;
use syntax::ast::DefId;
use syntax::ast;
mod probe;
mod suggest;
-pub enum MethodError {
- // Did not find an applicable method, but we did find various
- // static methods that may apply, as well as a list of
- // not-in-scope traits which may work.
- NoMatch(Vec<CandidateSource>, Vec<ast::DefId>, probe::Mode),
+pub enum MethodError<'tcx> {
+ // Did not find an applicable method, but we did find various near-misses that may work.
+ NoMatch(NoMatchData<'tcx>),
// Multiple methods might apply.
Ambiguity(Vec<CandidateSource>),
ClosureAmbiguity(/* DefId of fn trait */ ast::DefId),
}
+// Contains a list of static methods that may apply, a list of unsatisfied trait predicates which
+// could lead to matches if satisfied, and a list of not-in-scope traits which may work.
+pub struct NoMatchData<'tcx> {
+ pub static_candidates: Vec<CandidateSource>,
+ pub unsatisfied_predicates: Vec<TraitRef<'tcx>>,
+ pub out_of_scope_traits: Vec<ast::DefId>,
+ pub mode: probe::Mode
+}
+
+impl<'tcx> NoMatchData<'tcx> {
+ pub fn new(static_candidates: Vec<CandidateSource>,
+ unsatisfied_predicates: Vec<TraitRef<'tcx>>,
+ out_of_scope_traits: Vec<ast::DefId>,
+ mode: probe::Mode) -> Self {
+ NoMatchData {
+ static_candidates: static_candidates,
+ unsatisfied_predicates: unsatisfied_predicates,
+ out_of_scope_traits: out_of_scope_traits,
+ mode: mode
+ }
+ }
+}
+
// A pared down enum describing just the places from which a method
// candidate can arise. Used for error reporting only.
-#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
+#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub enum CandidateSource {
ImplSource(ast::DefId),
TraitSource(/* trait id */ ast::DefId),
supplied_method_types: Vec<ty::Ty<'tcx>>,
call_expr: &'tcx ast::Expr,
self_expr: &'tcx ast::Expr)
- -> Result<ty::MethodCallee<'tcx>, MethodError>
+ -> Result<ty::MethodCallee<'tcx>, MethodError<'tcx>>
{
- debug!("lookup(method_name={}, self_ty={}, call_expr={}, self_expr={})",
- method_name.repr(fcx.tcx()),
- self_ty.repr(fcx.tcx()),
- call_expr.repr(fcx.tcx()),
- self_expr.repr(fcx.tcx()));
+ debug!("lookup(method_name={}, self_ty={:?}, call_expr={:?}, self_expr={:?})",
+ method_name,
+ self_ty,
+ call_expr,
+ self_expr);
let mode = probe::Mode::MethodCall;
let self_ty = fcx.infcx().resolve_type_vars_if_possible(&self_ty);
opt_input_types: Option<Vec<ty::Ty<'tcx>>>)
-> Option<ty::MethodCallee<'tcx>>
{
- debug!("lookup_in_trait_adjusted(self_ty={}, self_expr={}, m_name={}, trait_def_id={})",
- self_ty.repr(fcx.tcx()),
- self_expr.repr(fcx.tcx()),
- m_name.repr(fcx.tcx()),
- trait_def_id.repr(fcx.tcx()));
+ debug!("lookup_in_trait_adjusted(self_ty={:?}, self_expr={:?}, m_name={}, trait_def_id={:?})",
+ self_ty,
+ self_expr,
+ m_name,
+ trait_def_id);
let trait_def = ty::lookup_trait_def(fcx.tcx(), trait_def_id);
assert_eq!(method_ty.generics.types.len(subst::FnSpace), 0);
assert_eq!(method_ty.generics.regions.len(subst::FnSpace), 0);
- debug!("lookup_in_trait_adjusted: method_num={} method_ty={}",
- method_num, method_ty.repr(fcx.tcx()));
+ debug!("lookup_in_trait_adjusted: method_num={} method_ty={:?}",
+ method_num, method_ty);
// Instantiate late-bound regions and substitute the trait
// parameters into the method type to get the actual method type.
abi: method_ty.fty.abi.clone(),
}));
- debug!("lookup_in_trait_adjusted: matched method fty={} obligation={}",
- fty.repr(fcx.tcx()),
- obligation.repr(fcx.tcx()));
+ debug!("lookup_in_trait_adjusted: matched method fty={:?} obligation={:?}",
+ fty,
+ obligation);
// Register obligations for the parameters. This will include the
// `Self` parameter, which in turn has a bound of the main trait,
// Trait method is fn(&self) or fn(&mut self), need an
// autoref. Pull the region etc out of the type of first argument.
match transformed_self_ty.sty {
- ty::ty_rptr(region, ty::mt { mutbl, ty: _ }) => {
+ ty::TyRef(region, ty::mt { mutbl, ty: _ }) => {
fcx.write_adjustment(self_expr.id,
ty::AdjustDerefRef(ty::AutoDerefRef {
autoderefs: autoderefs,
span,
&format!(
"trait method is &self but first arg is: {}",
- transformed_self_ty.repr(fcx.tcx())));
+ transformed_self_ty));
}
}
}
substs: trait_ref.substs.clone()
};
- debug!("callee = {}", callee.repr(fcx.tcx()));
+ debug!("callee = {:?}", callee);
Some(callee)
}
method_name: ast::Name,
self_ty: ty::Ty<'tcx>,
expr_id: ast::NodeId)
- -> Result<(def::Def, LastPrivate), MethodError>
+ -> Result<(def::Def, LastPrivate), MethodError<'tcx>>
{
let mode = probe::Mode::Path;
let pick = try!(probe::probe(fcx, span, mode, method_name, self_ty, expr_id));
// except according to those terms.
use super::MethodError;
+use super::NoMatchData;
use super::ItemIndex;
-use super::{CandidateSource,ImplSource,TraitSource};
+use super::{CandidateSource, ImplSource, TraitSource};
use super::suggest;
use check;
use middle::subst;
use middle::subst::Subst;
use middle::traits;
-use middle::ty::{self, RegionEscape, Ty, ToPolyTraitRef};
+use middle::ty::{self, RegionEscape, Ty, ToPolyTraitRef, TraitRef};
use middle::ty_fold::TypeFoldable;
use middle::infer;
use middle::infer::InferCtxt;
use std::collections::HashSet;
use std::mem;
use std::rc::Rc;
-use util::ppaux::Repr;
use self::CandidateKind::*;
pub use self::PickKind::*;
inherent_candidates: Vec<Candidate<'tcx>>,
extension_candidates: Vec<Candidate<'tcx>>,
impl_dups: HashSet<ast::DefId>,
+
+ /// Collects near misses when the candidate functions are missing a `self` keyword and is only
+ /// used for error reporting
static_candidates: Vec<CandidateSource>,
+
+ /// Collects near misses when trait bounds for type parameters are unsatisfied and is only used
+ /// for error reporting
+ unsatisfied_predicates: Vec<TraitRef<'tcx>>
}
+#[derive(Debug)]
struct CandidateStep<'tcx> {
self_ty: Ty<'tcx>,
autoderefs: usize,
unsize: bool
}
+#[derive(Debug)]
struct Candidate<'tcx> {
xform_self_ty: Ty<'tcx>,
item: ty::ImplOrTraitItem<'tcx>,
kind: CandidateKind<'tcx>,
}
+#[derive(Debug)]
enum CandidateKind<'tcx> {
- InherentImplCandidate(/* Impl */ ast::DefId, subst::Substs<'tcx>),
+ InherentImplCandidate(/* Impl */ ast::DefId, subst::Substs<'tcx>,
+ /* Normalize obligations */ Vec<traits::PredicateObligation<'tcx>>),
ObjectCandidate(/* Trait */ ast::DefId, /* method_num */ usize, /* vtable index */ usize),
ExtensionImplCandidate(/* Impl */ ast::DefId, ty::TraitRef<'tcx>,
- subst::Substs<'tcx>, ItemIndex),
+ subst::Substs<'tcx>, ItemIndex,
+ /* Normalize obligations */ Vec<traits::PredicateObligation<'tcx>>),
ClosureCandidate(/* Trait */ ast::DefId, ItemIndex),
WhereClauseCandidate(ty::PolyTraitRef<'tcx>, ItemIndex),
ProjectionCandidate(ast::DefId, ItemIndex),
}
+#[derive(Debug)]
pub struct Pick<'tcx> {
pub item: ty::ImplOrTraitItem<'tcx>,
pub kind: PickKind<'tcx>,
WhereClausePick(/* Trait */ ty::PolyTraitRef<'tcx>, ItemIndex),
}
-pub type PickResult<'tcx> = Result<Pick<'tcx>, MethodError>;
+pub type PickResult<'tcx> = Result<Pick<'tcx>, MethodError<'tcx>>;
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub enum Mode {
scope_expr_id: ast::NodeId)
-> PickResult<'tcx>
{
- debug!("probe(self_ty={}, item_name={}, scope_expr_id={})",
- self_ty.repr(fcx.tcx()),
+ debug!("probe(self_ty={:?}, item_name={}, scope_expr_id={})",
+ self_ty,
item_name,
scope_expr_id);
let steps = if mode == Mode::MethodCall {
match create_steps(fcx, span, self_ty) {
Some(steps) => steps,
- None => return Err(MethodError::NoMatch(Vec::new(), Vec::new(), mode)),
+ None =>return Err(MethodError::NoMatch(NoMatchData::new(Vec::new(), Vec::new(),
+ Vec::new(), mode))),
}
} else {
vec![CandidateStep {
Some(simplified_steps)
};
- debug!("ProbeContext: steps for self_ty={} are {}",
- self_ty.repr(fcx.tcx()),
- steps.repr(fcx.tcx()));
+ debug!("ProbeContext: steps for self_ty={:?} are {:?}",
+ self_ty,
+ steps);
// this creates one big transaction so that all type variables etc
// that we create during the probe process are removed later
});
match final_ty.sty {
- ty::ty_vec(elem_ty, Some(_)) => {
+ ty::TyArray(elem_ty, _) => {
let slice_ty = ty::mk_vec(fcx.tcx(), elem_ty, None);
steps.push(CandidateStep {
self_ty: slice_ty,
unsize: true
});
}
- ty::ty_err => return None,
+ ty::TyError => return None,
_ => (),
}
steps: Rc::new(steps),
opt_simplified_steps: opt_simplified_steps,
static_candidates: Vec::new(),
+ unsatisfied_predicates: Vec::new(),
}
}
fn assemble_inherent_candidates(&mut self) {
let steps = self.steps.clone();
- for step in &*steps {
+ for step in steps.iter() {
self.assemble_probe(step.self_ty);
}
}
fn assemble_probe(&mut self, self_ty: Ty<'tcx>) {
- debug!("assemble_probe: self_ty={}",
- self_ty.repr(self.tcx()));
+ debug!("assemble_probe: self_ty={:?}",
+ self_ty);
match self_ty.sty {
- ty::ty_trait(box ref data) => {
+ ty::TyTrait(box ref data) => {
self.assemble_inherent_candidates_from_object(self_ty, data);
self.assemble_inherent_impl_candidates_for_type(data.principal_def_id());
}
- ty::ty_enum(did, _) |
- ty::ty_struct(did, _) |
- ty::ty_closure(did, _) => {
+ ty::TyEnum(did, _) |
+ ty::TyStruct(did, _) |
+ ty::TyClosure(did, _) => {
self.assemble_inherent_impl_candidates_for_type(did);
}
- ty::ty_uniq(_) => {
+ ty::TyBox(_) => {
if let Some(box_did) = self.tcx().lang_items.owned_box() {
self.assemble_inherent_impl_candidates_for_type(box_did);
}
}
- ty::ty_param(p) => {
+ ty::TyParam(p) => {
self.assemble_inherent_candidates_from_param(self_ty, p);
}
- ty::ty_char => {
+ ty::TyChar => {
let lang_def_id = self.tcx().lang_items.char_impl();
self.assemble_inherent_impl_for_primitive(lang_def_id);
}
- ty::ty_str => {
+ ty::TyStr => {
let lang_def_id = self.tcx().lang_items.str_impl();
self.assemble_inherent_impl_for_primitive(lang_def_id);
}
- ty::ty_vec(_, None) => {
+ ty::TySlice(_) => {
let lang_def_id = self.tcx().lang_items.slice_impl();
self.assemble_inherent_impl_for_primitive(lang_def_id);
}
- ty::ty_ptr(ty::mt { ty: _, mutbl: ast::MutImmutable }) => {
+ ty::TyRawPtr(ty::mt { ty: _, mutbl: ast::MutImmutable }) => {
let lang_def_id = self.tcx().lang_items.const_ptr_impl();
self.assemble_inherent_impl_for_primitive(lang_def_id);
}
- ty::ty_ptr(ty::mt { ty: _, mutbl: ast::MutMutable }) => {
+ ty::TyRawPtr(ty::mt { ty: _, mutbl: ast::MutMutable }) => {
let lang_def_id = self.tcx().lang_items.mut_ptr_impl();
self.assemble_inherent_impl_for_primitive(lang_def_id);
}
- ty::ty_int(ast::TyI8) => {
+ ty::TyInt(ast::TyI8) => {
let lang_def_id = self.tcx().lang_items.i8_impl();
self.assemble_inherent_impl_for_primitive(lang_def_id);
}
- ty::ty_int(ast::TyI16) => {
+ ty::TyInt(ast::TyI16) => {
let lang_def_id = self.tcx().lang_items.i16_impl();
self.assemble_inherent_impl_for_primitive(lang_def_id);
}
- ty::ty_int(ast::TyI32) => {
+ ty::TyInt(ast::TyI32) => {
let lang_def_id = self.tcx().lang_items.i32_impl();
self.assemble_inherent_impl_for_primitive(lang_def_id);
}
- ty::ty_int(ast::TyI64) => {
+ ty::TyInt(ast::TyI64) => {
let lang_def_id = self.tcx().lang_items.i64_impl();
self.assemble_inherent_impl_for_primitive(lang_def_id);
}
- ty::ty_int(ast::TyIs) => {
+ ty::TyInt(ast::TyIs) => {
let lang_def_id = self.tcx().lang_items.isize_impl();
self.assemble_inherent_impl_for_primitive(lang_def_id);
}
- ty::ty_uint(ast::TyU8) => {
+ ty::TyUint(ast::TyU8) => {
let lang_def_id = self.tcx().lang_items.u8_impl();
self.assemble_inherent_impl_for_primitive(lang_def_id);
}
- ty::ty_uint(ast::TyU16) => {
+ ty::TyUint(ast::TyU16) => {
let lang_def_id = self.tcx().lang_items.u16_impl();
self.assemble_inherent_impl_for_primitive(lang_def_id);
}
- ty::ty_uint(ast::TyU32) => {
+ ty::TyUint(ast::TyU32) => {
let lang_def_id = self.tcx().lang_items.u32_impl();
self.assemble_inherent_impl_for_primitive(lang_def_id);
}
- ty::ty_uint(ast::TyU64) => {
+ ty::TyUint(ast::TyU64) => {
let lang_def_id = self.tcx().lang_items.u64_impl();
self.assemble_inherent_impl_for_primitive(lang_def_id);
}
- ty::ty_uint(ast::TyUs) => {
+ ty::TyUint(ast::TyUs) => {
let lang_def_id = self.tcx().lang_items.usize_impl();
self.assemble_inherent_impl_for_primitive(lang_def_id);
}
- ty::ty_float(ast::TyF32) => {
+ ty::TyFloat(ast::TyF32) => {
let lang_def_id = self.tcx().lang_items.f32_impl();
self.assemble_inherent_impl_for_primitive(lang_def_id);
}
- ty::ty_float(ast::TyF64) => {
+ ty::TyFloat(ast::TyF64) => {
let lang_def_id = self.tcx().lang_items.f64_impl();
self.assemble_inherent_impl_for_primitive(lang_def_id);
}
ty::populate_inherent_implementations_for_type_if_necessary(self.tcx(), def_id);
if let Some(impl_infos) = self.tcx().inherent_impls.borrow().get(&def_id) {
- for &impl_def_id in &***impl_infos {
+ for &impl_def_id in impl_infos.iter() {
self.assemble_inherent_impl_probe(impl_def_id);
}
}
}
let (impl_ty, impl_substs) = self.impl_ty_and_substs(impl_def_id);
- let impl_ty = self.fcx.instantiate_type_scheme(self.span, &impl_substs, &impl_ty);
+ let impl_ty = impl_ty.subst(self.tcx(), &impl_substs);
// Determine the receiver type that the method itself expects.
- let xform_self_ty =
- self.xform_self_ty(&item, impl_ty, &impl_substs);
+ let xform_self_ty = self.xform_self_ty(&item, impl_ty, &impl_substs);
+
+ // We can't use normalize_associated_types_in as it will pollute the
+ // fcx's fulfillment context after this probe is over.
+ let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id);
+ let mut selcx = &mut traits::SelectionContext::new(self.fcx.infcx(), self.fcx);
+ let traits::Normalized { value: xform_self_ty, obligations } =
+ traits::normalize(selcx, cause, &xform_self_ty);
+ debug!("assemble_inherent_impl_probe: xform_self_ty = {:?}",
+ xform_self_ty);
self.inherent_candidates.push(Candidate {
xform_self_ty: xform_self_ty,
item: item,
- kind: InherentImplCandidate(impl_def_id, impl_substs)
+ kind: InherentImplCandidate(impl_def_id, impl_substs, obligations)
});
}
fn assemble_inherent_candidates_from_object(&mut self,
self_ty: Ty<'tcx>,
- data: &ty::TyTrait<'tcx>) {
- debug!("assemble_inherent_candidates_from_object(self_ty={})",
- self_ty.repr(self.tcx()));
+ data: &ty::TraitTy<'tcx>) {
+ debug!("assemble_inherent_candidates_from_object(self_ty={:?})",
+ self_ty);
let tcx = self.tcx();
match *predicate {
ty::Predicate::Trait(ref trait_predicate) => {
match trait_predicate.0.trait_ref.self_ty().sty {
- ty::ty_param(ref p) if *p == param_ty => {
+ ty::TyParam(ref p) if *p == param_ty => {
Some(trait_predicate.to_poly_trait_ref())
}
_ => None
trait_ref.substs);
if let Some(ref m) = item.as_opt_method() {
- debug!("found match: trait_ref={} substs={} m={}",
- trait_ref.repr(this.tcx()),
- trait_ref.substs.repr(this.tcx()),
- m.repr(this.tcx()));
+ debug!("found match: trait_ref={:?} substs={:?} m={:?}",
+ trait_ref,
+ trait_ref.substs,
+ m);
assert_eq!(m.generics.types.get_slice(subst::TypeSpace).len(),
trait_ref.substs.types.get_slice(subst::TypeSpace).len());
assert_eq!(m.generics.regions.get_slice(subst::TypeSpace).len(),
usize,
),
{
- debug!("elaborate_bounds(bounds={})", bounds.repr(self.tcx()));
+ debug!("elaborate_bounds(bounds={:?})", bounds);
let tcx = self.tcx();
for bound_trait_ref in traits::transitive_bounds(tcx, bounds) {
fn assemble_extension_candidates_for_traits_in_scope(&mut self,
expr_id: ast::NodeId)
- -> Result<(),MethodError>
+ -> Result<(), MethodError<'tcx>>
{
let mut duplicates = HashSet::new();
let opt_applicable_traits = self.fcx.ccx.trait_map.get(&expr_id);
Ok(())
}
- fn assemble_extension_candidates_for_all_traits(&mut self) -> Result<(),MethodError> {
+ fn assemble_extension_candidates_for_all_traits(&mut self) -> Result<(), MethodError<'tcx>> {
let mut duplicates = HashSet::new();
for trait_info in suggest::all_traits(self.fcx.ccx) {
if duplicates.insert(trait_info.def_id) {
fn assemble_extension_candidates_for_trait(&mut self,
trait_def_id: ast::DefId)
- -> Result<(),MethodError>
+ -> Result<(), MethodError<'tcx>>
{
- debug!("assemble_extension_candidates_for_trait(trait_def_id={})",
- trait_def_id.repr(self.tcx()));
+ debug!("assemble_extension_candidates_for_trait(trait_def_id={:?})",
+ trait_def_id);
// Check whether `trait_def_id` defines a method with suitable name:
let trait_items =
// FIXME(arielb1): can we use for_each_relevant_impl here?
trait_def.for_each_impl(self.tcx(), |impl_def_id| {
- debug!("assemble_extension_candidates_for_trait_impl: trait_def_id={} impl_def_id={}",
- trait_def_id.repr(self.tcx()),
- impl_def_id.repr(self.tcx()));
+ debug!("assemble_extension_candidates_for_trait_impl: trait_def_id={:?} \
+ impl_def_id={:?}",
+ trait_def_id,
+ impl_def_id);
if !self.impl_can_possibly_match(impl_def_id) {
return;
let (_, impl_substs) = self.impl_ty_and_substs(impl_def_id);
- debug!("impl_substs={}", impl_substs.repr(self.tcx()));
+ debug!("impl_substs={:?}", impl_substs);
let impl_trait_ref =
ty::impl_trait_ref(self.tcx(), impl_def_id)
.unwrap() // we know this is a trait impl
.subst(self.tcx(), &impl_substs);
- debug!("impl_trait_ref={}", impl_trait_ref.repr(self.tcx()));
+ debug!("impl_trait_ref={:?}", impl_trait_ref);
// Determine the receiver type that the method itself expects.
let xform_self_ty =
impl_trait_ref.self_ty(),
impl_trait_ref.substs);
- debug!("xform_self_ty={}", xform_self_ty.repr(self.tcx()));
+ // Normalize the receiver. We can't use normalize_associated_types_in
+ // as it will pollute the fcx's fulfillment context after this probe
+ // is over.
+ let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id);
+ let mut selcx = &mut traits::SelectionContext::new(self.fcx.infcx(), self.fcx);
+ let traits::Normalized { value: xform_self_ty, obligations } =
+ traits::normalize(selcx, cause, &xform_self_ty);
+
+ debug!("xform_self_ty={:?}", xform_self_ty);
self.extension_candidates.push(Candidate {
xform_self_ty: xform_self_ty,
item: item.clone(),
- kind: ExtensionImplCandidate(impl_def_id, impl_trait_ref, impl_substs, item_index)
+ kind: ExtensionImplCandidate(impl_def_id,
+ impl_trait_ref,
+ impl_substs,
+ item_index,
+ obligations)
});
});
}
trait_def_id: ast::DefId,
item: ty::ImplOrTraitItem<'tcx>,
item_index: usize)
- -> Result<(),MethodError>
+ -> Result<(), MethodError<'tcx>>
{
// Check if this is one of the Fn,FnMut,FnOnce traits.
let tcx = self.tcx();
// Check if there is an unboxed-closure self-type in the list of receivers.
// If so, add "synthetic impls".
let steps = self.steps.clone();
- for step in &*steps {
+ for step in steps.iter() {
let closure_def_id = match step.self_ty.sty {
- ty::ty_closure(a, _) => a,
+ ty::TyClosure(a, _) => a,
_ => continue,
};
item_index: usize)
{
debug!("assemble_projection_candidates(\
- trait_def_id={}, \
- item={}, \
+ trait_def_id={:?}, \
+ item={:?}, \
item_index={})",
- trait_def_id.repr(self.tcx()),
- item.repr(self.tcx()),
+ trait_def_id,
+ item,
item_index);
- for step in &*self.steps {
- debug!("assemble_projection_candidates: step={}",
- step.repr(self.tcx()));
+ for step in self.steps.iter() {
+ debug!("assemble_projection_candidates: step={:?}",
+ step);
let projection_trait_ref = match step.self_ty.sty {
- ty::ty_projection(ref data) => &data.trait_ref,
+ ty::TyProjection(ref data) => &data.trait_ref,
_ => continue,
};
- debug!("assemble_projection_candidates: projection_trait_ref={}",
- projection_trait_ref.repr(self.tcx()));
+ debug!("assemble_projection_candidates: projection_trait_ref={:?}",
+ projection_trait_ref);
let trait_predicates = ty::lookup_predicates(self.tcx(),
projection_trait_ref.def_id);
let bounds = trait_predicates.instantiate(self.tcx(), projection_trait_ref.substs);
let predicates = bounds.predicates.into_vec();
- debug!("assemble_projection_candidates: predicates={}",
- predicates.repr(self.tcx()));
+ debug!("assemble_projection_candidates: predicates={:?}",
+ predicates);
for poly_bound in
traits::elaborate_predicates(self.tcx(), predicates)
.filter_map(|p| p.to_opt_poly_trait_ref())
{
let bound = self.erase_late_bound_regions(&poly_bound);
- debug!("assemble_projection_candidates: projection_trait_ref={} bound={}",
- projection_trait_ref.repr(self.tcx()),
- bound.repr(self.tcx()));
+ debug!("assemble_projection_candidates: projection_trait_ref={:?} bound={:?}",
+ projection_trait_ref,
+ bound);
if self.infcx().can_equate(&step.self_ty, &bound.self_ty()).is_ok() {
let xform_self_ty = self.xform_self_ty(&item,
bound.self_ty(),
bound.substs);
- debug!("assemble_projection_candidates: bound={} xform_self_ty={}",
- bound.repr(self.tcx()),
- xform_self_ty.repr(self.tcx()));
+ debug!("assemble_projection_candidates: bound={:?} xform_self_ty={:?}",
+ bound,
+ xform_self_ty);
self.extension_candidates.push(Candidate {
xform_self_ty: xform_self_ty,
item: ty::ImplOrTraitItem<'tcx>,
item_index: usize)
{
- debug!("assemble_where_clause_candidates(trait_def_id={})",
- trait_def_id.repr(self.tcx()));
+ debug!("assemble_where_clause_candidates(trait_def_id={:?})",
+ trait_def_id);
let caller_predicates = self.fcx.inh.param_env.caller_bounds.clone();
for poly_bound in traits::elaborate_predicates(self.tcx(), caller_predicates)
bound.self_ty(),
bound.substs);
- debug!("assemble_where_clause_candidates: bound={} xform_self_ty={}",
- bound.repr(self.tcx()),
- xform_self_ty.repr(self.tcx()));
+ debug!("assemble_where_clause_candidates: bound={:?} xform_self_ty={:?}",
+ bound,
+ xform_self_ty);
self.extension_candidates.push(Candidate {
xform_self_ty: xform_self_ty,
}
let static_candidates = mem::replace(&mut self.static_candidates, vec![]);
+ let unsatisfied_predicates = mem::replace(&mut self.unsatisfied_predicates, vec![]);
// things failed, so lets look at all traits, for diagnostic purposes now:
self.reset();
}
}
}).collect(),
- Some(Err(MethodError::NoMatch(_, others, _))) => {
+ Some(Err(MethodError::NoMatch(NoMatchData { out_of_scope_traits: others, .. }))) => {
assert!(others.is_empty());
vec![]
}
None => vec![],
};
- Err(MethodError::NoMatch(static_candidates, out_of_scope_traits, self.mode))
+ Err(MethodError::NoMatch(NoMatchData::new(static_candidates, unsatisfied_predicates,
+ out_of_scope_traits, self.mode)))
}
fn pick_core(&mut self) -> Option<PickResult<'tcx>> {
}
fn pick_step(&mut self, step: &CandidateStep<'tcx>) -> Option<PickResult<'tcx>> {
- debug!("pick_step: step={}", step.repr(self.tcx()));
+ debug!("pick_step: step={:?}", step);
if ty::type_is_error(step.self_ty) {
return None;
pick.autoderefs = step.autoderefs;
// Insert a `&*` or `&mut *` if this is a reference type:
- if let ty::ty_rptr(_, mt) = step.self_ty.sty {
+ if let ty::TyRef(_, mt) = step.self_ty.sty {
pick.autoderefs += 1;
pick.autoref = Some(mt.mutbl);
}
fn pick_method(&mut self, self_ty: Ty<'tcx>) -> Option<PickResult<'tcx>> {
debug!("pick_method(self_ty={})", self.infcx().ty_to_string(self_ty));
+ let mut possibly_unsatisfied_predicates = Vec::new();
+
debug!("searching inherent candidates");
- match self.consider_candidates(self_ty, &self.inherent_candidates) {
+ match self.consider_candidates(self_ty, &self.inherent_candidates,
+ &mut possibly_unsatisfied_predicates) {
None => {}
Some(pick) => {
return Some(pick);
}
debug!("searching extension candidates");
- self.consider_candidates(self_ty, &self.extension_candidates)
+ let res = self.consider_candidates(self_ty, &self.extension_candidates,
+ &mut possibly_unsatisfied_predicates);
+ if let None = res {
+ self.unsatisfied_predicates.extend(possibly_unsatisfied_predicates);
+ }
+ res
}
fn consider_candidates(&self,
self_ty: Ty<'tcx>,
- probes: &[Candidate<'tcx>])
+ probes: &[Candidate<'tcx>],
+ possibly_unsatisfied_predicates: &mut Vec<TraitRef<'tcx>>)
-> Option<PickResult<'tcx>> {
let mut applicable_candidates: Vec<_> =
probes.iter()
- .filter(|&probe| self.consider_probe(self_ty, probe))
+ .filter(|&probe| self.consider_probe(self_ty,
+ probe,possibly_unsatisfied_predicates))
.collect();
- debug!("applicable_candidates: {}", applicable_candidates.repr(self.tcx()));
+ debug!("applicable_candidates: {:?}", applicable_candidates);
if applicable_candidates.len() > 1 {
match self.collapse_candidates_to_trait_pick(&applicable_candidates[..]) {
})
}
- fn consider_probe(&self, self_ty: Ty<'tcx>, probe: &Candidate<'tcx>) -> bool {
- debug!("consider_probe: self_ty={} probe={}",
- self_ty.repr(self.tcx()),
- probe.repr(self.tcx()));
+ fn consider_probe(&self, self_ty: Ty<'tcx>, probe: &Candidate<'tcx>,
+ possibly_unsatisfied_predicates: &mut Vec<TraitRef<'tcx>>) -> bool {
+ debug!("consider_probe: self_ty={:?} probe={:?}",
+ self_ty,
+ probe);
self.infcx().probe(|_| {
// First check that the self type can be related.
// match as well (or at least may match, sometimes we
// don't have enough information to fully evaluate).
match probe.kind {
- InherentImplCandidate(impl_def_id, ref substs) |
- ExtensionImplCandidate(impl_def_id, _, ref substs, _) => {
+ InherentImplCandidate(impl_def_id, ref substs, ref ref_obligations) |
+ ExtensionImplCandidate(impl_def_id, _, ref substs, _, ref ref_obligations) => {
let selcx = &mut traits::SelectionContext::new(self.infcx(), self.fcx);
let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id);
// Convert the bounds into obligations.
let obligations =
- traits::predicates_for_generics(self.tcx(),
- cause.clone(),
+ traits::predicates_for_generics(cause.clone(),
&impl_bounds);
- debug!("impl_obligations={}", obligations.repr(self.tcx()));
+ debug!("impl_obligations={:?}", obligations);
// Evaluate those obligations to see if they might possibly hold.
- obligations.all(|o| selcx.evaluate_obligation(o)) &&
- norm_obligations.iter().all(|o| selcx.evaluate_obligation(o))
+ let mut all_true = true;
+ for o in obligations.iter()
+ .chain(norm_obligations.iter())
+ .chain(ref_obligations.iter()) {
+ if !selcx.evaluate_obligation(o) {
+ all_true = false;
+ if let &ty::Predicate::Trait(ref pred) = &o.predicate {
+ possibly_unsatisfied_predicates.push(pred.0.trait_ref);
+ }
+ }
+ }
+ all_true
}
ProjectionCandidate(..) |
substs: &subst::Substs<'tcx>)
-> Ty<'tcx>
{
- debug!("xform_self_ty(impl_ty={}, self_ty={}, substs={})",
- impl_ty.repr(self.tcx()),
- method.fty.sig.0.inputs.get(0).repr(self.tcx()),
- substs.repr(self.tcx()));
+ debug!("xform_self_ty(impl_ty={:?}, self_ty={:?}, substs={:?})",
+ impl_ty,
+ method.fty.sig.0.inputs.get(0),
+ substs);
assert!(!substs.has_escaping_regions());
/// and/or tracking the substitution and
/// so forth.
fn erase_late_bound_regions<T>(&self, value: &ty::Binder<T>) -> T
- where T : TypeFoldable<'tcx> + Repr<'tcx>
+ where T : TypeFoldable<'tcx>
{
ty::erase_late_bound_regions(self.tcx(), value)
}
Pick {
item: self.item.clone(),
kind: match self.kind {
- InherentImplCandidate(def_id, _) => {
+ InherentImplCandidate(def_id, _, _) => {
InherentImplPick(def_id)
}
ObjectCandidate(def_id, item_num, real_index) => {
ObjectPick(def_id, item_num, real_index)
}
- ExtensionImplCandidate(def_id, _, _, index) => {
+ ExtensionImplCandidate(def_id, _, _, index, _) => {
ExtensionImplPick(def_id, index)
}
ClosureCandidate(trait_def_id, index) => {
fn to_source(&self) -> CandidateSource {
match self.kind {
- InherentImplCandidate(def_id, _) => ImplSource(def_id),
+ InherentImplCandidate(def_id, _, _) => ImplSource(def_id),
ObjectCandidate(def_id, _, _) => TraitSource(def_id),
- ExtensionImplCandidate(def_id, _, _, _) => ImplSource(def_id),
+ ExtensionImplCandidate(def_id, _, _, _, _) => ImplSource(def_id),
ClosureCandidate(trait_def_id, _) => TraitSource(trait_def_id),
WhereClauseCandidate(ref trait_ref, _) => TraitSource(trait_ref.def_id()),
ProjectionCandidate(trait_def_id, _) => TraitSource(trait_def_id),
ClosureCandidate(trait_def_id, item_num) => {
Some((trait_def_id, item_num))
}
- ExtensionImplCandidate(_, ref trait_ref, _, item_num) => {
+ ExtensionImplCandidate(_, ref trait_ref, _, item_num, _) => {
Some((trait_ref.def_id, item_num))
}
WhereClauseCandidate(ref trait_ref, item_num) => {
}
}
}
-
-impl<'tcx> Repr<'tcx> for Candidate<'tcx> {
- fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
- format!("Candidate(xform_self_ty={}, kind={})",
- self.xform_self_ty.repr(tcx),
- self.kind.repr(tcx))
- }
-}
-
-impl<'tcx> Repr<'tcx> for CandidateKind<'tcx> {
- fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
- match *self {
- InherentImplCandidate(ref a, ref b) =>
- format!("InherentImplCandidate({},{})", a.repr(tcx), b.repr(tcx)),
- ObjectCandidate(a, b, c) =>
- format!("ObjectCandidate({},{},{})", a.repr(tcx), b, c),
- ExtensionImplCandidate(ref a, ref b, ref c, ref d) =>
- format!("ExtensionImplCandidate({},{},{},{})", a.repr(tcx), b.repr(tcx),
- c.repr(tcx), d),
- ClosureCandidate(ref a, ref b) =>
- format!("ClosureCandidate({},{})", a.repr(tcx), b),
- WhereClauseCandidate(ref a, ref b) =>
- format!("WhereClauseCandidate({},{})", a.repr(tcx), b),
- ProjectionCandidate(ref a, ref b) =>
- format!("ProjectionCandidate({},{})", a.repr(tcx), b),
- }
- }
-}
-
-impl<'tcx> Repr<'tcx> for CandidateStep<'tcx> {
- fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
- format!("CandidateStep({}, autoderefs={}, unsize={})",
- self.self_ty.repr(tcx),
- self.autoderefs,
- self.unsize)
- }
-}
-
-impl<'tcx> Repr<'tcx> for PickKind<'tcx> {
- fn repr(&self, _tcx: &ty::ctxt) -> String {
- format!("{:?}", self)
- }
-}
-
-impl<'tcx> Repr<'tcx> for Pick<'tcx> {
- fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
- format!("Pick(item={}, autoderefs={},
- autoref={}, unsize={}, kind={:?})",
- self.item.repr(tcx),
- self.autoderefs,
- self.autoref.repr(tcx),
- self.unsize.repr(tcx),
- self.kind)
- }
-}
use astconv::AstConv;
use check::{self, FnCtxt};
-use middle::ty::{self, Ty};
+use middle::ty::{self, Ty, ToPolyTraitRef, AsPredicate};
use middle::def;
+use middle::lang_items::FnOnceTraitLangItem;
+use middle::subst::Substs;
+use middle::traits::{Obligation, SelectionContext};
use metadata::{csearch, cstore, decoder};
-use util::ppaux::UserString;
use syntax::{ast, ast_util};
use syntax::codemap::Span;
use std::cell;
use std::cmp::Ordering;
-use super::{MethodError, CandidateSource, impl_item, trait_item};
+use super::{MethodError, NoMatchData, CandidateSource, impl_item, trait_item};
use super::probe::Mode;
pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
rcvr_ty: Ty<'tcx>,
item_name: ast::Name,
rcvr_expr: Option<&ast::Expr>,
- error: MethodError)
+ error: MethodError<'tcx>)
{
// avoid suggestions when we don't know what's going on.
if ty::type_is_error(rcvr_ty) {
}
match error {
- MethodError::NoMatch(static_sources, out_of_scope_traits, mode) => {
+ MethodError::NoMatch(NoMatchData { static_candidates: static_sources,
+ unsatisfied_predicates,
+ out_of_scope_traits,
+ mode }) => {
let cx = fcx.tcx();
- let item_ustring = item_name.user_string(cx);
fcx.type_error_message(
span,
in the current scope",
if mode == Mode::MethodCall { "method" }
else { "associated item" },
- item_ustring,
+ item_name,
actual)
},
rcvr_ty,
None);
// If the item has the name of a field, give a help note
- if let (&ty::ty_struct(did, _), Some(_)) = (&rcvr_ty.sty, rcvr_expr) {
+ if let (&ty::TyStruct(did, substs), Some(expr)) = (&rcvr_ty.sty, rcvr_expr) {
let fields = ty::lookup_struct_fields(cx, did);
- if fields.iter().any(|f| f.name == item_name) {
- cx.sess.span_note(span,
- &format!("use `(s.{0})(...)` if you meant to call the \
- function stored in the `{0}` field", item_ustring));
+
+ if let Some(field) = fields.iter().find(|f| f.name == item_name) {
+ let expr_string = match cx.sess.codemap().span_to_snippet(expr.span) {
+ Ok(expr_string) => expr_string,
+ _ => "s".into() // Default to a generic placeholder for the
+ // expression when we can't generate a string
+ // snippet
+ };
+
+ let span_stored_function = || {
+ cx.sess.span_note(span,
+ &format!("use `({0}.{1})(...)` if you meant to call \
+ the function stored in the `{1}` field",
+ expr_string, item_name));
+ };
+
+ let span_did_you_mean = || {
+ cx.sess.span_note(span, &format!("did you mean to write `{0}.{1}`?",
+ expr_string, item_name));
+ };
+
+ // Determine if the field can be used as a function in some way
+ let field_ty = ty::lookup_field_type(cx, did, field.id, substs);
+ if let Ok(fn_once_trait_did) = cx.lang_items.require(FnOnceTraitLangItem) {
+ let infcx = fcx.infcx();
+ infcx.probe(|_| {
+ let fn_once_substs = Substs::new_trait(vec![infcx.next_ty_var()],
+ Vec::new(),
+ field_ty);
+ let trait_ref = ty::TraitRef::new(fn_once_trait_did,
+ cx.mk_substs(fn_once_substs));
+ let poly_trait_ref = trait_ref.to_poly_trait_ref();
+ let obligation = Obligation::misc(span,
+ fcx.body_id,
+ poly_trait_ref.as_predicate());
+ let mut selcx = SelectionContext::new(infcx, fcx);
+
+ if selcx.evaluate_obligation(&obligation) {
+ span_stored_function();
+ } else {
+ span_did_you_mean();
+ }
+ });
+ } else {
+ match field_ty.sty {
+ // fallback to matching a closure or function pointer
+ ty::TyClosure(..) | ty::TyBareFn(..) => span_stored_function(),
+ _ => span_did_you_mean(),
+ }
+ }
}
}
if !static_sources.is_empty() {
- fcx.tcx().sess.fileline_note(
+ cx.sess.fileline_note(
span,
"found defined static methods, maybe a `self` is missing?");
report_candidates(fcx, span, item_name, static_sources);
}
+ if !unsatisfied_predicates.is_empty() {
+ let bound_list = unsatisfied_predicates.iter()
+ .map(|p| format!("`{} : {}`",
+ p.self_ty(),
+ p))
+ .collect::<Vec<_>>()
+ .connect(", ");
+ cx.sess.fileline_note(
+ span,
+ &format!("the method `{}` exists but the \
+ following trait bounds were not satisfied: {}",
+ item_name,
+ bound_list));
+ }
+
suggest_traits_to_import(fcx, span, rcvr_ty, item_name,
rcvr_expr, out_of_scope_traits)
}
let msg = format!("the `{}` method from the `{}` trait cannot be explicitly \
invoked on this closure as we have not yet inferred what \
kind of closure it is",
- item_name.user_string(fcx.tcx()),
+ item_name,
ty::item_path_str(fcx.tcx(), trait_def_id));
let msg = if let Some(callee) = rcvr_expr {
format!("{}; use overloaded call notation instead (e.g., `{}()`)",
"candidate #{} is defined in an impl{} for the type `{}`",
idx + 1,
insertion,
- impl_ty.user_string(fcx.tcx()));
+ impl_ty);
}
CandidateSource::TraitSource(trait_did) => {
let (_, item) = trait_item(fcx.tcx(), trait_did, item_name).unwrap();
valid_out_of_scope_traits: Vec<ast::DefId>)
{
let tcx = fcx.tcx();
- let item_ustring = item_name.user_string(tcx);
if !valid_out_of_scope_traits.is_empty() {
let mut candidates = valid_out_of_scope_traits;
perhaps you need to implement {one_of_them}:",
traits_define = if candidates.len() == 1 {"trait defines"} else {"traits define"},
one_of_them = if candidates.len() == 1 {"it"} else {"one of them"},
- name = item_ustring);
+ name = item_name);
fcx.sess().fileline_help(span, &msg[..]);
rcvr_expr: Option<&ast::Expr>) -> bool {
fn is_local(ty: Ty) -> bool {
match ty.sty {
- ty::ty_enum(did, _) | ty::ty_struct(did, _) => ast_util::is_local(did),
+ ty::TyEnum(did, _) | ty::TyStruct(did, _) => ast_util::is_local(did),
- ty::ty_trait(ref tr) => ast_util::is_local(tr.principal_def_id()),
+ ty::TyTrait(ref tr) => ast_util::is_local(tr.principal_def_id()),
- ty::ty_param(_) => true,
+ ty::TyParam(_) => true,
// everything else (primitive types etc.) is effectively
// non-local (there are "edge" cases, e.g. (LocalType,), but
use middle::ty::{Disr, ParamTy, ParameterEnvironment};
use middle::ty::{self, HasProjectionTypes, RegionEscape, ToPolyTraitRef, Ty};
use middle::ty::liberate_late_bound_regions;
-use middle::ty::{MethodCall, MethodCallee, MethodMap, ObjectCastMap};
+use middle::ty::{MethodCall, MethodCallee, MethodMap};
use middle::ty_fold::{TypeFolder, TypeFoldable};
use rscope::RegionScope;
use session::Session;
use TypeAndSubsts;
use lint;
use util::common::{block_query, ErrorReported, indenter, loop_query};
-use util::ppaux::{self, Repr};
use util::nodemap::{DefIdMap, FnvHashMap, NodeMap};
use util::lev_distance::lev_distance;
upvar_capture_map: RefCell<ty::UpvarCaptureMap>,
closure_tys: RefCell<DefIdMap<ty::ClosureTy<'tcx>>>,
closure_kinds: RefCell<DefIdMap<ty::ClosureKind>>,
- object_cast_map: ObjectCastMap<'tcx>,
// A mapping from each fn's id to its signature, with all bound
// regions replaced with free ones. Unlike the other tables, this
/// When type-checking an expression, we propagate downward
/// whatever type hint we are able in the form of an `Expectation`.
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug)]
pub enum Expectation<'tcx> {
/// We know nothing about what type this expression should have.
NoExpectation,
item_substs: RefCell::new(NodeMap()),
adjustments: RefCell::new(NodeMap()),
method_map: RefCell::new(FnvHashMap()),
- object_cast_map: RefCell::new(NodeMap()),
upvar_capture_map: RefCell::new(FnvHashMap()),
closure_tys: RefCell::new(DefIdMap()),
closure_kinds: RefCell::new(DefIdMap()),
fn_sig_map: RefCell::new(NodeMap()),
- fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()),
+ fulfillment_cx: RefCell::new(traits::FulfillmentContext::new(true)),
deferred_call_resolutions: RefCell::new(DefIdMap()),
deferred_cast_checks: RefCell::new(Vec::new()),
}
body_id: ast::NodeId,
value: &T)
-> T
- where T : TypeFoldable<'tcx> + Clone + HasProjectionTypes + Repr<'tcx>
+ where T : TypeFoldable<'tcx> + HasProjectionTypes
{
let mut fulfillment_cx = self.fulfillment_cx.borrow_mut();
assoc::normalize_associated_types_in(&self.infcx,
param_env: ty::ParameterEnvironment<'a, 'tcx>)
{
match raw_fty.sty {
- ty::ty_bare_fn(_, ref fn_ty) => {
+ ty::TyBareFn(_, ref fn_ty) => {
let inh = Inherited::new(ccx.tcx, param_env);
// Compute the fty from point of view of inside fn.
upvar::closure_analyze_fn(&fcx, fn_id, decl, body);
fcx.select_all_obligations_or_error();
fcx.check_casts();
+
+ fcx.select_all_obligations_or_error(); // Casts can introduce new obligations.
+
regionck::regionck_fn(&fcx, fn_id, fn_span, decl, body);
writeback::resolve_type_vars_in_fn(&fcx, decl, body);
}
None => None
};
self.assign(local.span, local.id, o_ty);
- debug!("Local variable {} is assigned type {}",
- self.fcx.pat_to_string(&*local.pat),
+ debug!("Local variable {:?} is assigned type {}",
+ local.pat,
self.fcx.infcx().ty_to_string(
self.fcx.inh.locals.borrow().get(&local.id).unwrap().clone()));
visit::walk_local(self, local);
self.fcx.require_type_is_sized(var_ty, p.span,
traits::VariableType(p.id));
- debug!("Pattern binding {} is assigned to {} with type {}",
+ debug!("Pattern binding {} is assigned to {} with type {:?}",
token::get_ident(path1.node),
self.fcx.infcx().ty_to_string(
self.fcx.inh.locals.borrow().get(&p.id).unwrap().clone()),
- var_ty.repr(self.fcx.tcx()));
+ var_ty);
}
}
visit::walk_pat(self, p);
let arg_tys = &fn_sig.inputs;
let ret_ty = fn_sig.output;
- debug!("check_fn(arg_tys={}, ret_ty={}, fn_id={})",
- arg_tys.repr(tcx),
- ret_ty.repr(tcx),
+ debug!("check_fn(arg_tys={:?}, ret_ty={:?}, fn_id={})",
+ arg_tys,
+ ret_ty,
fn_id);
// Create the function context. This is either derived from scratch or,
fn_sig_tys.push(ret_ty);
}
- debug!("fn-sig-map: fn_id={} fn_sig_tys={}",
+ debug!("fn-sig-map: fn_id={} fn_sig_tys={:?}",
fn_id,
- fn_sig_tys.repr(tcx));
+ fn_sig_tys);
inherited.fn_sig_map.borrow_mut().insert(fn_id, fn_sig_tys);
let mut visit = GatherLocalsVisitor { fcx: &fcx, };
// Add formal parameters.
- for (arg_ty, input) in arg_tys.iter().zip(decl.inputs.iter()) {
+ for (arg_ty, input) in arg_tys.iter().zip(&decl.inputs) {
// Create type variables for each argument.
pat_util::pat_bindings(
&tcx.def_map,
ty::FnDiverging => NoExpectation
});
- for (input, arg) in decl.inputs.iter().zip(arg_tys.iter()) {
- fcx.write_ty(input.id, *arg);
+ for (input, arg) in decl.inputs.iter().zip(arg_tys) {
+ fcx.write_ty(input.id, arg);
}
fcx
&enum_definition.variants,
it.id);
}
- ast::ItemFn(_, _, _, _, _) => {} // entirely within check_item_body
+ ast::ItemFn(..) => {} // entirely within check_item_body
ast::ItemImpl(_, _, _, _, _, ref impl_items) => {
debug!("ItemImpl {} with id {}", token::get_ident(it.ident), it.id);
match ty::impl_trait_ref(ccx.tcx, local_def(it.id)) {
ty::item_path_str(ccx.tcx, local_def(it.id)));
let _indenter = indenter();
match it.node {
- ast::ItemFn(ref decl, _, _, _, ref body) => {
+ ast::ItemFn(ref decl, _, _, _, _, ref body) => {
let fn_pty = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id));
let param_env = ParameterEnvironment::for_item(ccx.tcx, it.id);
check_bare_fn(ccx, &**decl, &**body, it.id, it.span, fn_pty.ty, param_env);
check_const(ccx, trait_item.span, &*expr, trait_item.id)
}
ast::MethodTraitItem(ref sig, Some(ref body)) => {
+ check_trait_fn_not_const(ccx, trait_item.span, sig.constness);
+
check_method_body(ccx, &trait_def.generics, sig, body,
trait_item.id, trait_item.span);
}
+ ast::MethodTraitItem(ref sig, None) => {
+ check_trait_fn_not_const(ccx, trait_item.span, sig.constness);
+ }
ast::ConstTraitItem(_, None) |
- ast::MethodTraitItem(_, None) |
ast::TypeTraitItem(..) => {
// Nothing to do.
}
}
}
+fn check_trait_fn_not_const<'a,'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+ span: Span,
+ constness: ast::Constness)
+{
+ match constness {
+ ast::Constness::NotConst => {
+ // good
+ }
+ ast::Constness::Const => {
+ span_err!(ccx.tcx.sess, span, E0379, "trait fns cannot be declared const");
+ }
+ }
+}
+
fn check_trait_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
generics: &ast::Generics,
item: &ast::Item) {
sig: &'tcx ast::MethodSig,
body: &'tcx ast::Block,
id: ast::NodeId, span: Span) {
- debug!("check_method_body(item_generics={}, id={})",
- item_generics.repr(ccx.tcx), id);
+ debug!("check_method_body(item_generics={:?}, id={})",
+ item_generics, id);
let param_env = ParameterEnvironment::for_item(ccx.tcx, id);
let fty = ty::node_id_to_type(ccx.tcx, id);
- debug!("check_method_body: fty={}", fty.repr(ccx.tcx));
+ debug!("check_method_body: fty={:?}", fty);
check_bare_fn(ccx, &sig.decl, body, id, span, fty, param_env);
}
_ => {
span_err!(tcx.sess, impl_item.span, E0323,
"item `{}` is an associated const, \
- which doesn't match its trait `{}`",
+ which doesn't match its trait `{:?}`",
token::get_name(impl_const_ty.name()),
- impl_trait_ref.repr(tcx))
+ impl_trait_ref)
}
}
}
impl_item.span,
&format!(
"associated const `{}` is not a member of \
- trait `{}`",
+ trait `{:?}`",
token::get_name(impl_const_ty.name()),
- impl_trait_ref.repr(tcx)));
+ impl_trait_ref));
}
}
}
- ast::MethodImplItem(_, ref body) => {
+ ast::MethodImplItem(ref sig, ref body) => {
+ check_trait_fn_not_const(ccx, impl_item.span, sig.constness);
+
let impl_method_def_id = local_def(impl_item.id);
let impl_item_ty = ty::impl_or_trait_item(ccx.tcx,
impl_method_def_id);
_ => {
span_err!(tcx.sess, impl_item.span, E0324,
"item `{}` is an associated method, \
- which doesn't match its trait `{}`",
+ which doesn't match its trait `{:?}`",
token::get_name(impl_item_ty.name()),
- impl_trait_ref.repr(tcx))
+ impl_trait_ref)
}
}
}
// caught in resolve.
tcx.sess.span_bug(
impl_item.span,
- &format!("method `{}` is not a member of trait `{}`",
+ &format!("method `{}` is not a member of trait `{:?}`",
token::get_name(impl_item_ty.name()),
- impl_trait_ref.repr(tcx)));
+ impl_trait_ref));
}
}
}
_ => {
span_err!(tcx.sess, impl_item.span, E0325,
"item `{}` is an associated type, \
- which doesn't match its trait `{}`",
+ which doesn't match its trait `{:?}`",
token::get_name(typedef_ty.name()),
- impl_trait_ref.repr(tcx))
+ impl_trait_ref)
}
}
}
impl_item.span,
&format!(
"associated type `{}` is not a member of \
- trait `{}`",
+ trait `{:?}`",
token::get_name(typedef_ty.name()),
- impl_trait_ref.repr(tcx)));
+ impl_trait_ref));
}
}
}
// Check for missing items from trait
let provided_methods = ty::provided_trait_methods(tcx, impl_trait_ref.def_id);
let associated_consts = ty::associated_consts(tcx, impl_trait_ref.def_id);
- let mut missing_methods = Vec::new();
- for trait_item in &*trait_items {
+ let mut missing_items = Vec::new();
+ for trait_item in trait_items.iter() {
match *trait_item {
ty::ConstTraitItem(ref associated_const) => {
let is_implemented = impl_items.iter().any(|ii| {
associated_consts.iter().any(|ac| ac.default.is_some() &&
ac.name == associated_const.name);
if !is_implemented && !is_provided {
- missing_methods.push(format!("`{}`",
- token::get_name(associated_const.name)));
+ missing_items.push(format!("`{}`",
+ token::get_name(associated_const.name)));
}
}
ty::MethodTraitItem(ref trait_method) => {
let is_provided =
provided_methods.iter().any(|m| m.name == trait_method.name);
if !is_implemented && !is_provided {
- missing_methods.push(format!("`{}`", token::get_name(trait_method.name)));
+ missing_items.push(format!("`{}`", token::get_name(trait_method.name)));
}
}
ty::TypeTraitItem(ref associated_type) => {
_ => false,
}
});
- if !is_implemented {
- missing_methods.push(format!("`{}`", token::get_name(associated_type.name)));
+ let is_provided = associated_type.ty.is_some();
+ if !is_implemented && !is_provided {
+ missing_items.push(format!("`{}`", token::get_name(associated_type.name)));
}
}
}
}
- if !missing_methods.is_empty() {
+ if !missing_items.is_empty() {
span_err!(tcx.sess, impl_span, E0046,
"not all trait items implemented, missing: {}",
- missing_methods.connect(", "));
+ missing_items.connect(", "));
}
}
span: Span,
t_span: Span,
e_span: Span,
- t_1: Ty<'tcx>,
- t_e: Ty<'tcx>,
+ t_cast: Ty<'tcx>,
+ t_expr: Ty<'tcx>,
id: ast::NodeId) {
- let tstr = fcx.infcx().ty_to_string(t_1);
+ let tstr = fcx.infcx().ty_to_string(t_cast);
fcx.type_error_message(span, |actual| {
format!("cast to unsized type: `{}` as `{}`", actual, tstr)
- }, t_e, None);
- match t_e.sty {
- ty::ty_rptr(_, ty::mt { mutbl: mt, .. }) => {
+ }, t_expr, None);
+ match t_expr.sty {
+ ty::TyRef(_, ty::mt { mutbl: mt, .. }) => {
let mtstr = match mt {
ast::MutMutable => "mut ",
ast::MutImmutable => ""
};
- if ty::type_is_trait(t_1) {
+ if ty::type_is_trait(t_cast) {
match fcx.tcx().sess.codemap().span_to_snippet(t_span) {
Ok(s) => {
fcx.tcx().sess.span_suggestion(t_span,
mtstr, tstr);
}
}
- ty::ty_uniq(..) => {
+ ty::TyBox(..) => {
match fcx.tcx().sess.codemap().span_to_snippet(t_span) {
Ok(s) => {
fcx.tcx().sess.span_suggestion(t_span,
/// version, this version will also select obligations if it seems
/// useful, in an effort to get more type information.
fn resolve_type_vars_if_possible(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> {
- debug!("resolve_type_vars_if_possible(ty={})", ty.repr(self.tcx()));
+ debug!("resolve_type_vars_if_possible(ty={:?})", ty);
// No ty::infer()? Nothing needs doing.
if !ty::type_has_ty_infer(ty) {
- debug!("resolve_type_vars_if_possible: ty={}", ty.repr(self.tcx()));
+ debug!("resolve_type_vars_if_possible: ty={:?}", ty);
return ty;
}
// If `ty` is a type variable, see whether we already know what it is.
ty = self.infcx().resolve_type_vars_if_possible(&ty);
if !ty::type_has_ty_infer(ty) {
- debug!("resolve_type_vars_if_possible: ty={}", ty.repr(self.tcx()));
+ debug!("resolve_type_vars_if_possible: ty={:?}", ty);
return ty;
}
self.select_new_obligations();
ty = self.infcx().resolve_type_vars_if_possible(&ty);
if !ty::type_has_ty_infer(ty) {
- debug!("resolve_type_vars_if_possible: ty={}", ty.repr(self.tcx()));
+ debug!("resolve_type_vars_if_possible: ty={:?}", ty);
return ty;
}
self.select_obligations_where_possible();
ty = self.infcx().resolve_type_vars_if_possible(&ty);
- debug!("resolve_type_vars_if_possible: ty={}", ty.repr(self.tcx()));
+ debug!("resolve_type_vars_if_possible: ty={:?}", ty);
ty
}
#[inline]
pub fn write_ty(&self, node_id: ast::NodeId, ty: Ty<'tcx>) {
- debug!("write_ty({}, {}) in fcx {}",
- node_id, ppaux::ty_to_string(self.tcx(), ty), self.tag());
+ debug!("write_ty({}, {:?}) in fcx {}",
+ node_id, ty, self.tag());
self.inh.node_types.borrow_mut().insert(node_id, ty);
}
pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::ItemSubsts<'tcx>) {
if !substs.substs.is_noop() {
- debug!("write_substs({}, {}) in fcx {}",
+ debug!("write_substs({}, {:?}) in fcx {}",
node_id,
- substs.repr(self.tcx()),
+ substs,
self.tag());
self.inh.item_substs.borrow_mut().insert(node_id, substs);
pub fn write_adjustment(&self,
node_id: ast::NodeId,
adj: ty::AutoAdjustment<'tcx>) {
- debug!("write_adjustment(node_id={}, adj={})", node_id, adj.repr(self.tcx()));
+ debug!("write_adjustment(node_id={}, adj={:?})", node_id, adj);
if adj.is_identity() {
return;
substs: &Substs<'tcx>,
value: &T)
-> T
- where T : TypeFoldable<'tcx> + Clone + HasProjectionTypes + Repr<'tcx>
+ where T : TypeFoldable<'tcx> + HasProjectionTypes
{
let value = value.subst(self.tcx(), substs);
let result = self.normalize_associated_types_in(span, &value);
- debug!("instantiate_type_scheme(value={}, substs={}) = {}",
- value.repr(self.tcx()),
- substs.repr(self.tcx()),
- result.repr(self.tcx()));
+ debug!("instantiate_type_scheme(value={:?}, substs={:?}) = {:?}",
+ value,
+ substs,
+ result);
result
}
fn normalize_associated_types_in<T>(&self, span: Span, value: &T) -> T
- where T : TypeFoldable<'tcx> + Clone + HasProjectionTypes + Repr<'tcx>
+ where T : TypeFoldable<'tcx> + HasProjectionTypes
{
self.inh.normalize_associated_types_in(self, span, self.body_id, value)
}
span)
}
- pub fn type_is_fat_ptr(&self, ty: Ty<'tcx>, span: Span) -> bool {
- if let Some(mt) = ty::deref(ty, true) {
- return !self.type_is_known_to_be_sized(mt.ty, span);
- }
- false
- }
-
pub fn register_builtin_bound(&self,
ty: Ty<'tcx>,
builtin_bound: ty::BuiltinBound,
pub fn register_predicate(&self,
obligation: traits::PredicateObligation<'tcx>)
{
- debug!("register_predicate({})",
- obligation.repr(self.tcx()));
+ debug!("register_predicate({:?})",
+ obligation);
self.inh.fulfillment_cx
.borrow_mut()
.register_predicate_obligation(self.infcx(), obligation);
let t = ast_ty_to_ty(self, self, ast_t);
let mut bounds_checker = wf::BoundsChecker::new(self,
- ast_t.span,
self.body_id,
None);
- bounds_checker.check_ty(t);
+ bounds_checker.check_ty(t, ast_t.span);
t
}
- pub fn pat_to_string(&self, pat: &ast::Pat) -> String {
- pat.repr(self.tcx())
- }
-
pub fn expr_ty(&self, ex: &ast::Expr) -> Ty<'tcx> {
match self.inh.node_types.borrow().get(&ex.id) {
Some(&t) => t,
cause: traits::ObligationCause<'tcx>)
{
let mut fulfillment_cx = self.inh.fulfillment_cx.borrow_mut();
- fulfillment_cx.register_region_obligation(self.infcx(), ty, region, cause);
+ fulfillment_cx.register_region_obligation(ty, region, cause);
}
pub fn add_default_region_param_bounds(&self,
substs: &Substs<'tcx>,
expr: &ast::Expr)
{
- for &ty in substs.types.iter() {
+ for &ty in &substs.types {
let default_bound = ty::ReScope(CodeExtent::from_node_id(expr.id));
let cause = traits::ObligationCause::new(expr.span, self.body_id,
traits::MiscObligation);
{
assert!(!predicates.has_escaping_regions());
- debug!("add_obligations_for_parameters(predicates={})",
- predicates.repr(self.tcx()));
-
- let obligations = traits::predicates_for_generics(self.tcx(),
- cause,
- predicates);
+ debug!("add_obligations_for_parameters(predicates={:?})",
+ predicates);
- obligations.map_move(|o| self.register_predicate(o));
+ for obligation in traits::predicates_for_generics(cause, predicates) {
+ self.register_predicate(obligation);
+ }
}
// Only for fields! Returns <none> for methods>
fn check_casts(&self) {
let mut deferred_cast_checks = self.inh.deferred_cast_checks.borrow_mut();
- for check in deferred_cast_checks.iter() {
- cast::check_cast(self, check);
+ for cast in deferred_cast_checks.drain(..) {
+ cast.check(self);
}
-
- deferred_cast_checks.clear();
}
fn select_all_obligations_and_apply_defaults(&self) {
impl<'a, 'tcx> RegionScope for FnCtxt<'a, 'tcx> {
fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
+ Some(self.base_object_lifetime_default(span))
+ }
+
+ fn base_object_lifetime_default(&self, span: Span) -> ty::Region {
// RFC #599 specifies that object lifetime defaults take
// precedence over other defaults. But within a fn body we
// don't have a *default* region, rather we use inference to
// (and anyway, within a fn body the right region may not even
// be something the user can write explicitly, since it might
// be some expression).
- Some(self.infcx().next_region_var(infer::MiscVariable(span)))
+ self.infcx().next_region_var(infer::MiscVariable(span))
}
fn anon_regions(&self, span: Span, count: usize)
NoPreference
}
+impl LvaluePreference {
+ pub fn from_mutbl(m: ast::Mutability) -> Self {
+ match m {
+ ast::MutMutable => PreferMutLvalue,
+ ast::MutImmutable => NoPreference,
+ }
+ }
+}
+
/// Whether `autoderef` requires types to resolve.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum UnresolvedTypeAction {
- /// Produce an error and return `ty_err` whenever a type cannot
- /// be resolved (i.e. it is `ty_infer`).
+ /// Produce an error and return `TyError` whenever a type cannot
+ /// be resolved (i.e. it is `TyInfer`).
Error,
/// Go on without emitting any errors, and return the unresolved
/// type. Useful for probing, e.g. in coercions.
-> (Ty<'tcx>, usize, Option<T>)
where F: FnMut(Ty<'tcx>, usize) -> Option<T>,
{
- debug!("autoderef(base_ty={}, opt_expr={}, lvalue_pref={:?})",
- base_ty.repr(fcx.tcx()),
- opt_expr.repr(fcx.tcx()),
+ debug!("autoderef(base_ty={:?}, opt_expr={:?}, lvalue_pref={:?})",
+ base_ty,
+ opt_expr,
lvalue_pref);
let mut t = base_ty;
// We've reached the recursion limit, error gracefully.
span_err!(fcx.tcx().sess, sp, E0055,
- "reached the recursion limit while auto-dereferencing {}",
- base_ty.repr(fcx.tcx()));
+ "reached the recursion limit while auto-dereferencing {:?}",
+ base_ty);
(fcx.tcx().types.err, 0, None)
}
return final_mt;
}
- // After we have fully autoderef'd, if the resulting type is [T, ..n], then
+ // After we have fully autoderef'd, if the resulting type is [T; n], then
// do a final unsized coercion to yield [T].
- if let ty::ty_vec(element_ty, Some(_)) = ty.sty {
+ if let ty::TyArray(element_ty, _) = ty.sty {
let adjusted_ty = ty::mk_vec(fcx.tcx(), element_ty, None);
try_index_step(fcx, MethodCall::expr(expr.id), expr, base_expr,
adjusted_ty, autoderefs, true, lvalue_pref, idx_ty)
-> Option<(/*index type*/ Ty<'tcx>, /*element type*/ Ty<'tcx>)>
{
let tcx = fcx.tcx();
- debug!("try_index_step(expr={}, base_expr.id={}, adjusted_ty={}, \
- autoderefs={}, unsize={}, index_ty={})",
- expr.repr(tcx),
- base_expr.repr(tcx),
- adjusted_ty.repr(tcx),
+ debug!("try_index_step(expr={:?}, base_expr.id={:?}, adjusted_ty={:?}, \
+ autoderefs={}, unsize={}, index_ty={:?})",
+ expr,
+ base_expr,
+ adjusted_ty,
autoderefs,
unsize,
- index_ty.repr(tcx));
+ index_ty);
let input_ty = fcx.infcx().next_ty_var();
// First, try built-in indexing.
match (ty::index(adjusted_ty), &index_ty.sty) {
- (Some(ty), &ty::ty_uint(ast::TyUs)) | (Some(ty), &ty::ty_infer(ty::IntVar(_))) => {
+ (Some(ty), &ty::TyUint(ast::TyUs)) | (Some(ty), &ty::TyInfer(ty::IntVar(_))) => {
debug!("try_index_step: success, using built-in indexing");
// If we had `[T; N]`, we should've caught it before unsizing to `[T]`.
assert!(!unsize);
ty::FnConverging(fcx.tcx().types.err)
} else {
match method_fn_ty.sty {
- ty::ty_bare_fn(_, ref fty) => {
+ ty::TyBareFn(_, ref fty) => {
// HACK(eddyb) ignore self in the definition (see above).
let expected_arg_tys = expected_types_for_fn_args(fcx,
sp,
let formal_tys = if tuple_arguments == TupleArguments {
let tuple_type = structurally_resolved_type(fcx, sp, fn_inputs[0]);
match tuple_type.sty {
- ty::ty_tup(ref arg_types) => {
+ ty::TyTuple(ref arg_types) => {
if arg_types.len() != args.len() {
span_err!(tcx.sess, sp, E0057,
"this function takes {} parameter{} but {} parameter{} supplied",
} else {
expected_arg_tys = match expected_arg_tys.get(0) {
Some(&ty) => match ty.sty {
- ty::ty_tup(ref tys) => &**tys,
+ ty::TyTuple(ref tys) => &**tys,
_ => &[]
},
None => &[]
let arg_ty = structurally_resolved_type(fcx, arg.span,
fcx.expr_ty(&**arg));
match arg_ty.sty {
- ty::ty_float(ast::TyF32) => {
+ ty::TyFloat(ast::TyF32) => {
fcx.type_error_message(arg.span,
|t| {
format!("can't pass an {} to variadic \
function, cast to c_double", t)
}, arg_ty, None);
}
- ty::ty_int(ast::TyI8) | ty::ty_int(ast::TyI16) | ty::ty_bool => {
+ ty::TyInt(ast::TyI8) | ty::TyInt(ast::TyI16) | ty::TyBool => {
fcx.type_error_message(arg.span, |t| {
format!("can't pass {} to variadic \
function, cast to c_int",
t)
}, arg_ty, None);
}
- ty::ty_uint(ast::TyU8) | ty::ty_uint(ast::TyU16) => {
+ ty::TyUint(ast::TyU8) | ty::TyUint(ast::TyU16) => {
fcx.type_error_message(arg.span, |t| {
format!("can't pass {} to variadic \
function, cast to c_uint",
ast::LitInt(_, ast::UnsuffixedIntLit(_)) => {
let opt_ty = expected.to_option(fcx).and_then(|ty| {
match ty.sty {
- ty::ty_int(_) | ty::ty_uint(_) => Some(ty),
- ty::ty_char => Some(tcx.types.u8),
- ty::ty_ptr(..) => Some(tcx.types.usize),
- ty::ty_bare_fn(..) => Some(tcx.types.usize),
+ ty::TyInt(_) | ty::TyUint(_) => Some(ty),
+ ty::TyChar => Some(tcx.types.u8),
+ ty::TyRawPtr(..) => Some(tcx.types.usize),
+ ty::TyBareFn(..) => Some(tcx.types.usize),
_ => None
}
});
ast::LitFloatUnsuffixed(_) => {
let opt_ty = expected.to_option(fcx).and_then(|ty| {
match ty.sty {
- ty::ty_float(_) => Some(ty),
+ ty::TyFloat(_) => Some(ty),
_ => None
}
});
None
}
}).unwrap_or(vec![]);
- debug!("expected_types_for_fn_args(formal={} -> {}, expected={} -> {})",
- formal_args.repr(fcx.tcx()), formal_ret.repr(fcx.tcx()),
- expected_args.repr(fcx.tcx()), expected_ret.repr(fcx.tcx()));
+ debug!("expected_types_for_fn_args(formal={:?} -> {:?}, expected={:?} -> {:?})",
+ formal_args, formal_ret,
+ expected_args, expected_ret);
expected_args
}
/// strict, _|_ can appear in the type of an expression that does not,
/// itself, diverge: for example, fn() -> _|_.)
/// Note that inspecting a type's structure *directly* may expose the fact
-/// that there are actually multiple representations for `ty_err`, so avoid
+/// that there are actually multiple representations for `TyError`, so avoid
/// that when err needs to be handled differently.
fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
expr: &'tcx ast::Expr,
unifier: F) where
F: FnOnce(),
{
- debug!(">> typechecking: expr={} expected={}",
- expr.repr(fcx.tcx()), expected.repr(fcx.tcx()));
+ debug!(">> typechecking: expr={:?} expected={:?}",
+ expr, expected);
// Checks a method call.
fn check_method_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
lvalue_pref,
|base_t, _| {
match base_t.sty {
- ty::ty_struct(base_id, substs) => {
- debug!("struct named {}", ppaux::ty_to_string(tcx, base_t));
+ ty::TyStruct(base_id, substs) => {
+ debug!("struct named {:?}", base_t);
let fields = ty::lookup_struct_fields(tcx, base_id);
fcx.lookup_field_ty(expr.span, base_id, &fields[..],
field.node.name, &(*substs))
actual)
},
expr_t, None);
- if let ty::ty_struct(did, _) = expr_t.sty {
+ if let ty::TyStruct(did, _) = expr_t.sty {
suggest_field_names(did, field, tcx, vec![]);
}
}
lvalue_pref,
|base_t, _| {
match base_t.sty {
- ty::ty_struct(base_id, substs) => {
+ ty::TyStruct(base_id, substs) => {
tuple_like = ty::is_tuple_struct(tcx, base_id);
if tuple_like {
- debug!("tuple struct named {}", ppaux::ty_to_string(tcx, base_t));
+ debug!("tuple struct named {:?}", base_t);
let fields = ty::lookup_struct_fields(tcx, base_id);
fcx.lookup_tup_field_ty(expr.span, base_id, &fields[..],
idx.node, &(*substs))
None
}
}
- ty::ty_tup(ref v) => {
+ ty::TyTuple(ref v) => {
tuple_like = true;
if idx.node < v.len() { Some(v[idx.node]) } else { None }
}
let expected_inner = expected.to_option(fcx).map_or(NoExpectation, |ty| {
match unop {
ast::UnUniq => match ty.sty {
- ty::ty_uniq(ty) => {
+ ty::TyBox(ty) => {
Expectation::rvalue_hint(ty)
}
_ => {
Some(&**oprnd), oprnd_t, lvalue_pref) {
Some(mt) => mt.ty,
None => {
- let is_newtype = match oprnd_t.sty {
- ty::ty_struct(did, substs) => {
- let fields = ty::struct_fields(fcx.tcx(), did, substs);
- fields.len() == 1
- && fields[0].name ==
- token::special_idents::unnamed_field.name
- }
- _ => false
- };
- if is_newtype {
- // This is an obsolete struct deref
- span_err!(tcx.sess, expr.span, E0068,
- "single-field tuple-structs can \
- no longer be dereferenced");
- } else {
- fcx.type_error_message(expr.span, |actual| {
- format!("type `{}` cannot be \
- dereferenced", actual)
- }, oprnd_t, None);
- }
+ fcx.type_error_message(expr.span, |actual| {
+ format!("type `{}` cannot be \
+ dereferenced", actual)
+ }, oprnd_t, None);
tcx.types.err
}
}
oprnd_t = structurally_resolved_type(fcx, oprnd.span,
oprnd_t);
if !(ty::type_is_integral(oprnd_t) ||
- oprnd_t.sty == ty::ty_bool) {
+ oprnd_t.sty == ty::TyBool) {
oprnd_t = op::check_user_unop(fcx, "!", "not",
tcx.lang_items.not_trait(),
expr, &**oprnd, oprnd_t, unop);
tcx.lang_items.neg_trait(),
expr, &**oprnd, oprnd_t, unop);
}
- if let ty::ty_uint(_) = oprnd_t.sty {
+ if let ty::TyUint(_) = oprnd_t.sty {
if !tcx.sess.features.borrow().negate_unsigned {
feature_gate::emit_feature_err(
&tcx.sess.parse_sess.span_diagnostic,
ast::ExprAddrOf(mutbl, ref oprnd) => {
let hint = expected.only_has_type(fcx).map_or(NoExpectation, |ty| {
match ty.sty {
- ty::ty_rptr(_, ref mt) | ty::ty_ptr(ref mt) => {
+ ty::TyRef(_, ref mt) | ty::TyRawPtr(ref mt) => {
if ty::expr_is_lval(fcx.tcx(), &**oprnd) {
// Lvalues may legitimately have unsized types.
// For example, dereferences of a fat pointer and
_ => NoExpectation
}
});
- let lvalue_pref = match mutbl {
- ast::MutMutable => PreferMutLvalue,
- ast::MutImmutable => NoPreference
- };
+ let lvalue_pref = LvaluePreference::from_mutbl(mutbl);
check_expr_with_expectation_and_lvalue_pref(fcx,
&**oprnd,
hint,
}
} else {
tcx.sess.span_bug(expr.span,
- &format!("unbound path {}", expr.repr(tcx)))
+ &format!("unbound path {:?}", expr))
};
if let Some((opt_ty, segments, def)) =
// Find the type of `e`. Supply hints based on the type we are casting to,
// if appropriate.
- let t_1 = fcx.to_ty(t);
- let t_1 = structurally_resolved_type(fcx, expr.span, t_1);
- check_expr_with_expectation(fcx, e, ExpectCastableToType(t_1));
- let t_e = fcx.expr_ty(e);
+ let t_cast = fcx.to_ty(t);
+ let t_cast = structurally_resolved_type(fcx, expr.span, t_cast);
+ check_expr_with_expectation(fcx, e, ExpectCastableToType(t_cast));
+ let t_expr = fcx.expr_ty(e);
// Eagerly check for some obvious errors.
- if ty::type_is_error(t_e) {
+ if ty::type_is_error(t_expr) {
fcx.write_error(id);
- } else if !fcx.type_is_known_to_be_sized(t_1, expr.span) {
- report_cast_to_unsized_type(fcx, expr.span, t.span, e.span, t_1, t_e, id);
+ } else if !fcx.type_is_known_to_be_sized(t_cast, expr.span) {
+ report_cast_to_unsized_type(fcx, expr.span, t.span, e.span, t_cast, t_expr, id);
} else {
// Write a type for the whole expression, assuming everything is going
// to work out Ok.
- fcx.write_ty(id, t_1);
+ fcx.write_ty(id, t_cast);
// Defer other checks until we're done type checking.
let mut deferred_cast_checks = fcx.inh.deferred_cast_checks.borrow_mut();
- let cast_check = cast::CastCheck::new((**e).clone(), t_e, t_1, expr.span);
+ let cast_check = cast::CastCheck::new((**e).clone(), t_expr, t_cast, expr.span);
deferred_cast_checks.push(cast_check);
}
}
ast::ExprVec(ref args) => {
let uty = expected.to_option(fcx).and_then(|uty| {
match uty.sty {
- ty::ty_vec(ty, _) => Some(ty),
+ ty::TyArray(ty, _) | ty::TySlice(ty) => Some(ty),
_ => None
}
});
let uty = match expected {
ExpectHasType(uty) => {
match uty.sty {
- ty::ty_vec(ty, _) => Some(ty),
+ ty::TyArray(ty, _) | ty::TySlice(ty) => Some(ty),
_ => None
}
}
ast::ExprTup(ref elts) => {
let flds = expected.only_has_type(fcx).and_then(|ty| {
match ty.sty {
- ty::ty_tup(ref flds) => Some(&flds[..]),
+ ty::TyTuple(ref flds) => Some(&flds[..]),
_ => None
}
});
// Verify that this was actually a struct.
let typ = ty::lookup_item_type(fcx.ccx.tcx, def.def_id());
match typ.ty.sty {
- ty::ty_struct(struct_did, _) => {
+ ty::TyStruct(struct_did, _) => {
check_struct_constructor(fcx,
id,
expr.span,
type_and_substs.ty) {
Ok(()) => {}
Err(type_error) => {
- let type_error_description =
- ty::type_err_to_str(tcx, &type_error);
span_err!(fcx.tcx().sess, path.span, E0235,
"structure constructor specifies a \
structure of type `{}`, but this \
fcx.infcx()
.ty_to_string(
actual_structure_type),
- type_error_description);
+ type_error);
ty::note_and_explain_type_err(tcx, &type_error, path.span);
}
}
debug!("type of expr({}) {} is...", expr.id,
syntax::print::pprust::expr_to_string(expr));
- debug!("... {}, expected is {}",
- ppaux::ty_to_string(tcx, fcx.expr_ty(expr)),
- expected.repr(tcx));
+ debug!("... {:?}, expected is {:?}",
+ fcx.expr_ty(expr),
+ expected);
unifier();
}
&'a [ast::PathSegment],
def::Def)>
{
+
+ // Associated constants can't depend on generic types.
+ fn have_disallowed_generic_consts<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
+ def: def::Def,
+ ty: Ty<'tcx>,
+ span: Span,
+ node_id: ast::NodeId) -> bool {
+ match def {
+ def::DefAssociatedConst(..) => {
+ if ty::type_has_params(ty) || ty::type_has_self(ty) {
+ span_err!(fcx.sess(), span, E0329,
+ "Associated consts cannot depend \
+ on type parameters or Self.");
+ fcx.write_error(node_id);
+ return true;
+ }
+ }
+ _ => {}
+ }
+ false
+ }
+
// If fully resolved already, we don't have to do anything.
if path_res.depth == 0 {
+ if let Some(ty) = opt_self_ty {
+ if have_disallowed_generic_consts(fcx, path_res.full_def(), ty,
+ span, node_id) {
+ return None;
+ }
+ }
Some((opt_self_ty, &path.segments, path_res.base_def))
} else {
let mut def = path_res.base_def;
let item_name = item_segment.identifier.name;
match method::resolve_ufcs(fcx, span, item_name, ty, node_id) {
Ok((def, lp)) => {
+ if have_disallowed_generic_consts(fcx, def, ty, span, node_id) {
+ return None;
+ }
// Write back the new resolution.
fcx.ccx.tcx.def_map.borrow_mut()
.insert(node_id, def::PathResolution {
/// for examples of where this comes up,.
fn rvalue_hint(ty: Ty<'tcx>) -> Expectation<'tcx> {
match ty.sty {
- ty::ty_vec(_, None) | ty::ty_trait(..) => {
+ ty::TySlice(_) | ty::TyTrait(..) => {
ExpectRvalueLikeUnsized(ty)
}
_ => ExpectHasType(ty)
}
}
-impl<'tcx> Repr<'tcx> for Expectation<'tcx> {
- fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
- match *self {
- NoExpectation => format!("NoExpectation"),
- ExpectHasType(t) => format!("ExpectHasType({})",
- t.repr(tcx)),
- ExpectCastableToType(t) => format!("ExpectCastableToType({})",
- t.repr(tcx)),
- ExpectRvalueLikeUnsized(t) => format!("ExpectRvalueLikeUnsized({})",
- t.repr(tcx)),
- }
- }
-}
-
pub fn check_decl_initializer<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
local: &'tcx ast::Local,
init: &'tcx ast::Expr)
let ref_bindings = fcx.tcx().pat_contains_ref_binding(&local.pat);
let local_ty = fcx.local_ty(init.span, local.id);
- if !ref_bindings {
- check_expr_coercable_to_type(fcx, init, local_ty)
- } else {
+ if let Some(m) = ref_bindings {
// Somewhat subtle: if we have a `ref` binding in the pattern,
// we want to avoid introducing coercions for the RHS. This is
// both because it helps preserve sanity and, in the case of
// referent for the reference that results is *equal to* the
// type of the lvalue it is referencing, and not some
// supertype thereof.
- check_expr(fcx, init);
+ check_expr_with_lvalue_pref(fcx, init, LvaluePreference::from_mutbl(m));
let init_ty = fcx.expr_ty(init);
demand::eqtype(fcx, init.span, init_ty, local_ty);
+ } else {
+ check_expr_coercable_to_type(fcx, init, local_ty)
};
}
span_err!(tcx.sess, sp, E0073,
"this type cannot be instantiated without an \
instance of itself");
- fileline_help!(tcx.sess, sp, "consider using `Option<{}>`",
- ppaux::ty_to_string(tcx, item_ty));
+ fileline_help!(tcx.sess, sp, "consider using `Option<{:?}>`",
+ item_ty);
false
} else {
true
return;
}
match t.sty {
- ty::ty_struct(did, substs) => {
+ ty::TyStruct(did, substs) => {
let fields = ty::lookup_struct_fields(tcx, did);
if fields.is_empty() {
span_err!(tcx.sess, sp, E0075, "SIMD vector cannot be empty");
def: def::Def,
span: Span,
node_id: ast::NodeId) {
- debug!("instantiate_path(path={:?}, def={}, node_id={}, type_scheme={})",
+ debug!("instantiate_path(path={:?}, def={:?}, node_id={}, type_scheme={:?})",
segments,
- def.repr(fcx.tcx()),
+ def,
node_id,
- type_scheme.repr(fcx.tcx()));
+ type_scheme);
// We need to extract the type parameters supplied by the user in
// the path `path`. Due to the current setup, this is a bit of a
// provided (if any) into their appropriate spaces. We'll also report
// errors if type parameters are provided in an inappropriate place.
let mut substs = Substs::empty();
- for (opt_space, segment) in segment_spaces.iter().zip(segments.iter()) {
+ for (opt_space, segment) in segment_spaces.iter().zip(segments) {
match *opt_space {
None => {
check_path_args(fcx.tcx(), slice::ref_slice(segment),
if fcx.mk_subty(false, infer::Misc(span), self_ty, impl_ty).is_err() {
fcx.tcx().sess.span_bug(span,
&format!(
- "instantiate_path: (UFCS) {} was a subtype of {} but now is not?",
- self_ty.repr(fcx.tcx()),
- impl_ty.repr(fcx.tcx())));
+ "instantiate_path: (UFCS) {:?} was a subtype of {:?} but now is not?",
+ self_ty,
+ impl_ty));
}
}
} else if i == type_count {
span_err!(fcx.tcx().sess, typ.span, E0087,
"too many type parameters provided: \
- expected at most {} parameter(s), \
- found {} parameter(s)",
- type_count, data.types.len());
+ expected at most {} parameter{}, \
+ found {} parameter{}",
+ type_count,
+ if type_count == 1 {""} else {"s"},
+ data.types.len(),
+ if data.types.len() == 1 {""} else {"s"});
substs.types.truncate(space, 0);
break;
}
} else if i == region_count {
span_err!(fcx.tcx().sess, lifetime.span, E0088,
"too many lifetime parameters provided: \
- expected {} parameter(s), found {} parameter(s)",
+ expected {} parameter{}, found {} parameter{}",
region_count,
- data.lifetimes.len());
+ if region_count == 1 {""} else {"s"},
+ data.lifetimes.len(),
+ if data.lifetimes.len() == 1 {""} else {"s"});
substs.mut_regions().truncate(space, 0);
break;
}
let qualifier =
if desired.len() != required_len { "at least " } else { "" };
span_err!(fcx.tcx().sess, span, E0089,
- "too few type parameters provided: expected {}{} parameter(s) \
- , found {} parameter(s)",
- qualifier, required_len, provided_len);
+ "too few type parameters provided: expected {}{} parameter{}, \
+ found {} parameter{}",
+ qualifier, required_len,
+ if required_len == 1 {""} else {"s"},
+ provided_len,
+ if provided_len == 1 {""} else {"s"});
substs.types.replace(space, repeat(fcx.tcx().types.err).take(desired.len()).collect());
return;
}
}
assert_eq!(substs.types.len(space), desired.len());
- debug!("Final substs: {}", substs.repr(fcx.tcx()));
+ debug!("Final substs: {:?}", substs);
}
fn adjust_region_parameters(
// Otherwise, too few were provided. Report an error and then
// use inference variables.
span_err!(fcx.tcx().sess, span, E0090,
- "too few lifetime parameters provided: expected {} parameter(s), \
- found {} parameter(s)",
- desired.len(), provided_len);
+ "too few lifetime parameters provided: expected {} parameter{}, \
+ found {} parameter{}",
+ desired.len(),
+ if desired.len() == 1 {""} else {"s"},
+ provided_len,
+ if provided_len == 1 {""} else {"s"});
substs.mut_regions().replace(
space,
span: Span,
tps: &OwnedSlice<ast::TyParam>,
ty: Ty<'tcx>) {
- debug!("check_bounds_are_used(n_tps={}, ty={})",
- tps.len(), ppaux::ty_to_string(ccx.tcx, ty));
+ debug!("check_bounds_are_used(n_tps={}, ty={:?})",
+ tps.len(), ty);
// make a vector of booleans initially false, set to true when used
if tps.is_empty() { return; }
ty::walk_ty(ty, |t| {
match t.sty {
- ty::ty_param(ParamTy {idx, ..}) => {
+ ty::TyParam(ParamTy {idx, ..}) => {
debug!("Found use of ty param num {}", idx);
tps_used[idx as usize] = true;
}
"type_name" => (1, Vec::new(), ty::mk_str_slice(tcx, tcx.mk_region(ty::ReStatic),
ast::MutImmutable)),
"type_id" => (1, Vec::new(), ccx.tcx.types.u64),
- "offset" => {
+ "offset" | "arith_offset" => {
(1,
vec!(
ty::mk_ptr(tcx, ty::mt {
fty,
|| {
format!("intrinsic has wrong type: expected `{}`",
- ppaux::ty_to_string(ccx.tcx, fty))
+ fty)
});
}
}
use syntax::ast;
use syntax::ast_util;
use syntax::parse::token;
-use util::ppaux::{Repr, UserString};
/// Check a `a <op>= b`
pub fn check_binop_assign<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
span_err!(tcx.sess, lhs_expr.span, E0368,
"binary assignment operation `{}=` cannot be applied to types `{}` and `{}`",
ast_util::binop_to_string(op.node),
- lhs_ty.user_string(fcx.tcx()),
- rhs_ty.user_string(fcx.tcx()));
+ lhs_ty,
+ rhs_ty);
fcx.write_error(expr.id);
}
{
let tcx = fcx.ccx.tcx;
- debug!("check_binop(expr.id={}, expr={}, op={:?}, lhs_expr={}, rhs_expr={})",
+ debug!("check_binop(expr.id={}, expr={:?}, op={:?}, lhs_expr={:?}, rhs_expr={:?})",
expr.id,
- expr.repr(tcx),
+ expr,
op,
- lhs_expr.repr(tcx),
- rhs_expr.repr(tcx));
+ lhs_expr,
+ rhs_expr);
check_expr(fcx, lhs_expr);
let lhs_ty = fcx.resolve_type_vars_if_possible(fcx.expr_ty(lhs_expr));
// if this is simd, result is same as lhs, else bool
if ty::type_is_simd(tcx, lhs_ty) {
let unit_ty = ty::simd_type(tcx, lhs_ty);
- debug!("enforce_builtin_binop_types: lhs_ty={} unit_ty={}",
- lhs_ty.repr(tcx),
- unit_ty.repr(tcx));
+ debug!("enforce_builtin_binop_types: lhs_ty={:?} unit_ty={:?}",
+ lhs_ty,
+ unit_ty);
if !ty::type_is_integral(unit_ty) {
tcx.sess.span_err(
lhs_expr.span,
&format!("binary comparison operation `{}` not supported \
for floating point SIMD vector `{}`",
ast_util::binop_to_string(op.node),
- lhs_ty.user_string(tcx)));
+ lhs_ty));
tcx.types.err
} else {
lhs_ty
op: ast::BinOp)
-> (Ty<'tcx>, Ty<'tcx>)
{
- debug!("check_overloaded_binop(expr.id={}, lhs_ty={})",
+ debug!("check_overloaded_binop(expr.id={}, lhs_ty={:?})",
expr.id,
- lhs_ty.repr(fcx.tcx()));
+ lhs_ty);
let (name, trait_def_id) = name_and_trait_def_id(fcx, op);
span_err!(fcx.tcx().sess, lhs_expr.span, E0369,
"binary operation `{}` cannot be applied to type `{}`",
ast_util::binop_to_string(op.node),
- lhs_ty.user_string(fcx.tcx()));
+ lhs_ty);
}
fcx.tcx().types.err
}
lhs_expr: &'a ast::Expr)
-> Result<Ty<'tcx>,()>
{
- debug!("lookup_op_method(expr={}, lhs_ty={}, opname={:?}, trait_did={}, lhs_expr={})",
- expr.repr(fcx.tcx()),
- lhs_ty.repr(fcx.tcx()),
+ debug!("lookup_op_method(expr={:?}, lhs_ty={:?}, opname={:?}, trait_did={:?}, lhs_expr={:?})",
+ expr,
+ lhs_ty,
opname,
- trait_did.repr(fcx.tcx()),
- lhs_expr.repr(fcx.tcx()));
+ trait_did,
+ lhs_expr);
let method = match trait_did {
Some(trait_did) => {
//! the borrow itself (L2). What do I mean by "guaranteed" by a
//! borrowed pointer? I mean any data that is reached by first
//! dereferencing a borrowed pointer and then either traversing
-//! interior offsets or owned pointers. We say that the guarantor
+//! interior offsets or boxes. We say that the guarantor
//! of such data it the region of the borrowed pointer that was
//! traversed. This is essentially the same as the ownership
//! relation, except that a borrowed pointer never owns its
use middle::ty::{self, ClosureTyper, ReScope, Ty, MethodCall};
use middle::infer::{self, GenericKind};
use middle::pat_util;
-use util::ppaux::{ty_to_string, Repr};
use std::mem;
use syntax::{ast, ast_util};
.to_vec();
for r_o in ®ion_obligations {
- debug!("visit_region_obligations: r_o={}",
- r_o.repr(self.tcx()));
+ debug!("visit_region_obligations: r_o={:?}",
+ r_o);
let sup_type = self.resolve_type(r_o.sup_type);
let origin = infer::RelateParamBound(r_o.cause.span, sup_type);
type_must_outlive(self, origin, sup_type, r_o.sub_region);
body_id: ast::NodeId,
span: Span) {
debug!("relate_free_regions >>");
- let tcx = self.tcx();
for &ty in fn_sig_tys {
let ty = self.resolve_type(ty);
- debug!("relate_free_regions(t={})", ty.repr(tcx));
+ debug!("relate_free_regions(t={:?})", ty);
let body_scope = CodeExtent::from_node_id(body_id);
let body_scope = ty::ReScope(body_scope);
let implications = implicator::implications(self.fcx.infcx(), self.fcx, body_id,
ty, body_scope, span);
// Record any relations between free regions that we observe into the free-region-map.
- self.free_region_map.relate_free_regions_from_implications(tcx, &implications);
+ self.free_region_map.relate_free_regions_from_implications(&implications);
// But also record other relationships, such as `T:'x`,
// that don't go into the free-region-map but which we use
// here.
for implication in implications {
- debug!("implication: {}", implication.repr(tcx));
+ debug!("implication: {:?}", implication);
match implication {
implicator::Implication::RegionSubRegion(_,
ty::ReFree(free_a),
self.fcx.inh.infcx.add_given(free_a, vid_b);
}
implicator::Implication::RegionSubGeneric(_, r_a, ref generic_b) => {
- debug!("RegionSubGeneric: {} <= {}",
- r_a.repr(tcx), generic_b.repr(tcx));
+ debug!("RegionSubGeneric: {:?} <= {:?}",
+ r_a, generic_b);
self.region_bound_pairs.push((r_a, generic_b.clone()));
}
fn constrain_bindings_in_pat(pat: &ast::Pat, rcx: &mut Rcx) {
let tcx = rcx.fcx.tcx();
- debug!("regionck::visit_pat(pat={})", pat.repr(tcx));
+ debug!("regionck::visit_pat(pat={:?})", pat);
pat_util::pat_bindings(&tcx.def_map, pat, |_, id, span, _| {
// If we have a variable that contains region'd data, that
// data will be accessible from anywhere that the variable is
}
fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
- debug!("regionck::visit_expr(e={}, repeating_scope={})",
- expr.repr(rcx.fcx.tcx()), rcx.repeating_scope);
+ debug!("regionck::visit_expr(e={:?}, repeating_scope={})",
+ expr, rcx.repeating_scope);
// No matter what, the type of each expression must outlive the
// scope of that expression. This also guarantees basic WF.
// outlive the operation you are performing.
let lhs_ty = rcx.resolve_expr_type_adjusted(&**lhs);
let rhs_ty = rcx.resolve_expr_type_adjusted(&**rhs);
- for &ty in [lhs_ty, rhs_ty].iter() {
+ for &ty in &[lhs_ty, rhs_ty] {
type_must_outlive(rcx,
infer::Operand(expr.span),
ty,
}
None => rcx.resolve_node_type(base.id)
};
- if let ty::ty_rptr(r_ptr, _) = base_ty.sty {
+ if let ty::TyRef(r_ptr, _) = base_ty.sty {
mk_subregion_due_to_dereference(
rcx, expr.span, ty::ReScope(CodeExtent::from_node_id(expr.id)), *r_ptr);
}
cast_expr: &ast::Expr,
source_expr: &ast::Expr)
{
- debug!("constrain_cast(cast_expr={}, source_expr={})",
- cast_expr.repr(rcx.tcx()),
- source_expr.repr(rcx.tcx()));
+ debug!("constrain_cast(cast_expr={:?}, source_expr={:?})",
+ cast_expr,
+ source_expr);
let source_ty = rcx.resolve_node_type(source_expr.id);
let target_ty = rcx.resolve_node_type(cast_expr.id);
cast_expr: &ast::Expr,
from_ty: Ty<'tcx>,
to_ty: Ty<'tcx>) {
- debug!("walk_cast(from_ty={}, to_ty={})",
- from_ty.repr(rcx.tcx()),
- to_ty.repr(rcx.tcx()));
+ debug!("walk_cast(from_ty={:?}, to_ty={:?})",
+ from_ty,
+ to_ty);
match (&from_ty.sty, &to_ty.sty) {
- /*From:*/ (&ty::ty_rptr(from_r, ref from_mt),
- /*To: */ &ty::ty_rptr(to_r, ref to_mt)) => {
+ /*From:*/ (&ty::TyRef(from_r, ref from_mt),
+ /*To: */ &ty::TyRef(to_r, ref to_mt)) => {
// Target cannot outlive source, naturally.
rcx.fcx.mk_subr(infer::Reborrow(cast_expr.span), *to_r, *from_r);
walk_cast(rcx, cast_expr, from_mt.ty, to_mt.ty);
}
/*From:*/ (_,
- /*To: */ &ty::ty_trait(box ty::TyTrait { ref bounds, .. })) => {
+ /*To: */ &ty::TyTrait(box ty::TraitTy { ref bounds, .. })) => {
// When T is existentially quantified as a trait
// `Foo+'to`, it must outlive the region bound `'to`.
type_must_outlive(rcx, infer::RelateObjectBound(cast_expr.span),
from_ty, bounds.region_bound);
}
- /*From:*/ (&ty::ty_uniq(from_referent_ty),
- /*To: */ &ty::ty_uniq(to_referent_ty)) => {
+ /*From:*/ (&ty::TyBox(from_referent_ty),
+ /*To: */ &ty::TyBox(to_referent_ty)) => {
walk_cast(rcx, cast_expr, from_referent_ty, to_referent_ty);
}
_callee_expr: &ast::Expr) {
let callee_ty = rcx.resolve_node_type(callee_id);
match callee_ty.sty {
- ty::ty_bare_fn(..) => { }
+ ty::TyBareFn(..) => { }
_ => {
// this should not happen, but it does if the program is
// erroneous
//
// tcx.sess.span_bug(
// callee_expr.span,
- // format!("Calling non-function: {}", callee_ty.repr(tcx)));
+ // format!("Calling non-function: {}", callee_ty));
}
}
}
//! in the type of the function. Also constrains the regions that
//! appear in the arguments appropriately.
- let tcx = rcx.fcx.tcx();
- debug!("constrain_call(call_expr={}, \
- receiver={}, \
+ debug!("constrain_call(call_expr={:?}, \
+ receiver={:?}, \
implicitly_ref_args={})",
- call_expr.repr(tcx),
- receiver.repr(tcx),
+ call_expr,
+ receiver,
implicitly_ref_args);
// `callee_region` is the scope representing the time in which the
let callee_scope = CodeExtent::from_node_id(call_expr.id);
let callee_region = ty::ReScope(callee_scope);
- debug!("callee_region={}", callee_region.repr(tcx));
+ debug!("callee_region={:?}", callee_region);
for arg_expr in arg_exprs {
- debug!("Argument: {}", arg_expr.repr(tcx));
+ debug!("Argument: {:?}", arg_expr);
// ensure that any regions appearing in the argument type are
// valid for at least the lifetime of the function:
// as loop above, but for receiver
if let Some(r) = receiver {
- debug!("receiver: {}", r.repr(tcx));
+ debug!("receiver: {:?}", r);
type_of_node_must_outlive(
rcx, infer::CallRcvr(r.span),
r.id, callee_region);
derefs: usize,
mut derefd_ty: Ty<'tcx>)
{
- debug!("constrain_autoderefs(deref_expr={}, derefs={}, derefd_ty={})",
- deref_expr.repr(rcx.tcx()),
+ debug!("constrain_autoderefs(deref_expr={:?}, derefs={}, derefd_ty={:?})",
+ deref_expr,
derefs,
- derefd_ty.repr(rcx.tcx()));
+ derefd_ty);
let r_deref_expr = ty::ReScope(CodeExtent::from_node_id(deref_expr.id));
for i in 0..derefs {
derefd_ty = match rcx.fcx.inh.method_map.borrow().get(&method_call) {
Some(method) => {
- debug!("constrain_autoderefs: #{} is overloaded, method={}",
- i, method.repr(rcx.tcx()));
+ debug!("constrain_autoderefs: #{} is overloaded, method={:?}",
+ i, method);
// Treat overloaded autoderefs as if an AutoRef adjustment
// was applied on the base type, as that is always the case.
ty::no_late_bound_regions(rcx.tcx(), fn_sig).unwrap();
let self_ty = fn_sig.inputs[0];
let (m, r) = match self_ty.sty {
- ty::ty_rptr(r, ref m) => (m.mutbl, r),
+ ty::TyRef(r, ref m) => (m.mutbl, r),
_ => {
rcx.tcx().sess.span_bug(
deref_expr.span,
- &format!("bad overloaded deref type {}",
- method.ty.repr(rcx.tcx())))
+ &format!("bad overloaded deref type {:?}",
+ method.ty))
}
};
debug!("constrain_autoderefs: receiver r={:?} m={:?}",
- r.repr(rcx.tcx()), m);
+ r, m);
{
let mc = mc::MemCategorizationContext::new(rcx.fcx);
let self_cmt = ignore_err!(mc.cat_expr_autoderefd(deref_expr, i));
debug!("constrain_autoderefs: self_cmt={:?}",
- self_cmt.repr(rcx.tcx()));
+ self_cmt);
link_region(rcx, deref_expr.span, r,
ty::BorrowKind::from_mutbl(m), self_cmt);
}
None => derefd_ty
};
- if let ty::ty_rptr(r_ptr, _) = derefd_ty.sty {
+ if let ty::TyRef(r_ptr, _) = derefd_ty.sty {
mk_subregion_due_to_dereference(rcx, deref_expr.span,
r_deref_expr, *r_ptr);
}
.sess
.span_bug(span,
&format!("unexpected rvalue region in rvalue \
- destructor safety checking: `{}`",
- region.repr(rcx.tcx())));
+ destructor safety checking: `{:?}`",
+ region));
}
}
}
rcx.fcx.infcx().ty_to_string(indexed_ty));
let r_index_expr = ty::ReScope(CodeExtent::from_node_id(index_expr.id));
- if let ty::ty_rptr(r_ptr, mt) = indexed_ty.sty {
+ if let ty::TyRef(r_ptr, mt) = indexed_ty.sty {
match mt.ty.sty {
- ty::ty_vec(_, None) | ty::ty_str => {
+ ty::TySlice(_) | ty::TyStr => {
rcx.fcx.mk_subr(infer::IndexSlice(index_expr.span),
r_index_expr, *r_ptr);
}
|method_call| rcx.resolve_method_type(method_call));
debug!("constrain_regions_in_type_of_node(\
ty={}, ty0={}, id={}, minimum_lifetime={:?})",
- ty_to_string(tcx, ty), ty_to_string(tcx, ty0),
+ ty, ty0,
id, minimum_lifetime);
type_must_outlive(rcx, origin, ty, minimum_lifetime);
}
/// resulting pointer is linked to the lifetime of its guarantor (if any).
fn link_addr_of(rcx: &mut Rcx, expr: &ast::Expr,
mutability: ast::Mutability, base: &ast::Expr) {
- debug!("link_addr_of(expr={}, base={})", expr.repr(rcx.tcx()), base.repr(rcx.tcx()));
+ debug!("link_addr_of(expr={:?}, base={:?})", expr, base);
let cmt = {
let mc = mc::MemCategorizationContext::new(rcx.fcx);
ignore_err!(mc.cat_expr(base))
};
- debug!("link_addr_of: cmt={}", cmt.repr(rcx.tcx()));
+ debug!("link_addr_of: cmt={:?}", cmt);
link_region_from_node_type(rcx, expr.span, expr.id, mutability, cmt);
}
debug!("regionck::for_match()");
let mc = mc::MemCategorizationContext::new(rcx.fcx);
let discr_cmt = ignore_err!(mc.cat_expr(discr));
- debug!("discr_cmt={}", discr_cmt.repr(rcx.tcx()));
+ debug!("discr_cmt={:?}", discr_cmt);
for arm in arms {
for root_pat in &arm.pats {
link_pattern(rcx, mc, discr_cmt.clone(), &**root_pat);
let arg_ty = rcx.fcx.node_ty(arg.id);
let re_scope = ty::ReScope(body_scope);
let arg_cmt = mc.cat_rvalue(arg.id, arg.ty.span, re_scope, arg_ty);
- debug!("arg_ty={} arg_cmt={}",
- arg_ty.repr(rcx.tcx()),
- arg_cmt.repr(rcx.tcx()));
+ debug!("arg_ty={:?} arg_cmt={:?}",
+ arg_ty,
+ arg_cmt);
link_pattern(rcx, mc, arg_cmt, &*arg.pat);
}
}
mc: mc::MemCategorizationContext<FnCtxt<'a, 'tcx>>,
discr_cmt: mc::cmt<'tcx>,
root_pat: &ast::Pat) {
- debug!("link_pattern(discr_cmt={}, root_pat={})",
- discr_cmt.repr(rcx.tcx()),
- root_pat.repr(rcx.tcx()));
+ debug!("link_pattern(discr_cmt={:?}, root_pat={:?})",
+ discr_cmt,
+ root_pat);
let _ = mc.cat_pattern(discr_cmt, root_pat, |mc, sub_cmt, sub_pat| {
match sub_pat.node {
// `ref x` pattern
debug!("link_autoref(autoref={:?})", autoref);
let mc = mc::MemCategorizationContext::new(rcx.fcx);
let expr_cmt = ignore_err!(mc.cat_expr_autoderefd(expr, autoderefs));
- debug!("expr_cmt={}", expr_cmt.repr(rcx.tcx()));
+ debug!("expr_cmt={:?}", expr_cmt);
match *autoref {
ty::AutoPtr(r, m) => {
fn link_by_ref(rcx: &Rcx,
expr: &ast::Expr,
callee_scope: CodeExtent) {
- let tcx = rcx.tcx();
- debug!("link_by_ref(expr={}, callee_scope={:?})",
- expr.repr(tcx), callee_scope);
+ debug!("link_by_ref(expr={:?}, callee_scope={:?})",
+ expr, callee_scope);
let mc = mc::MemCategorizationContext::new(rcx.fcx);
let expr_cmt = ignore_err!(mc.cat_expr(expr));
let borrow_region = ty::ReScope(callee_scope);
id: ast::NodeId,
mutbl: ast::Mutability,
cmt_borrowed: mc::cmt<'tcx>) {
- debug!("link_region_from_node_type(id={:?}, mutbl={:?}, cmt_borrowed={})",
- id, mutbl, cmt_borrowed.repr(rcx.tcx()));
+ debug!("link_region_from_node_type(id={:?}, mutbl={:?}, cmt_borrowed={:?})",
+ id, mutbl, cmt_borrowed);
let rptr_ty = rcx.resolve_node_type(id);
if !ty::type_is_error(rptr_ty) {
let tcx = rcx.fcx.ccx.tcx;
- debug!("rptr_ty={}", ty_to_string(tcx, rptr_ty));
+ debug!("rptr_ty={}", rptr_ty);
let r = ty::ty_region(tcx, span, rptr_ty);
link_region(rcx, span, &r, ty::BorrowKind::from_mutbl(mutbl),
cmt_borrowed);
let mut borrow_kind = borrow_kind;
loop {
- debug!("link_region(borrow_region={}, borrow_kind={}, borrow_cmt={})",
- borrow_region.repr(rcx.tcx()),
- borrow_kind.repr(rcx.tcx()),
- borrow_cmt.repr(rcx.tcx()));
+ debug!("link_region(borrow_region={:?}, borrow_kind={:?}, borrow_cmt={:?})",
+ borrow_region,
+ borrow_kind,
+ borrow_cmt);
match borrow_cmt.cat.clone() {
mc::cat_deref(ref_cmt, _,
mc::Implicit(ref_kind, ref_region)) |
_ => {
rcx.tcx().sess.span_bug(
span,
- &format!("Illegal upvar id: {}",
- upvar_id.repr(rcx.tcx())));
+ &format!("Illegal upvar id: {:?}",
+ upvar_id));
}
}
}
}
};
- debug!("link_reborrowed_region: {} <= {}",
- borrow_region.repr(rcx.tcx()),
- ref_region.repr(rcx.tcx()));
+ debug!("link_reborrowed_region: {:?} <= {:?}",
+ borrow_region,
+ ref_region);
rcx.fcx.mk_subr(cause, *borrow_region, ref_region);
// If we end up needing to recurse and establish a region link
ty: Ty<'tcx>,
region: ty::Region)
{
- debug!("type_must_outlive(ty={}, region={})",
- ty.repr(rcx.tcx()),
- region.repr(rcx.tcx()));
+ debug!("type_must_outlive(ty={:?}, region={:?})",
+ ty,
+ region);
let implications = implicator::implications(rcx.fcx.infcx(), rcx.fcx, rcx.body_id,
ty, region, origin.span());
for implication in implications {
- debug!("implication: {}", implication.repr(rcx.tcx()));
+ debug!("implication: {:?}", implication);
match implication {
implicator::Implication::RegionSubRegion(None, r_a, r_b) => {
rcx.fcx.mk_subr(origin.clone(), r_a, r_b);
region: ty::Region,
def_id: ast::DefId,
substs: &'tcx Substs<'tcx>) {
- debug!("closure_must_outlive(region={}, def_id={}, substs={})",
- region.repr(rcx.tcx()), def_id.repr(rcx.tcx()), substs.repr(rcx.tcx()));
+ debug!("closure_must_outlive(region={:?}, def_id={:?}, substs={:?})",
+ region, def_id, substs);
let upvars = rcx.fcx.closure_upvars(def_id, substs).unwrap();
for upvar in upvars {
generic: &GenericKind<'tcx>) {
let param_env = &rcx.fcx.inh.param_env;
- debug!("param_must_outlive(region={}, generic={})",
- region.repr(rcx.tcx()),
- generic.repr(rcx.tcx()));
+ debug!("param_must_outlive(region={:?}, generic={:?})",
+ region,
+ generic);
// To start, collect bounds from user:
let mut param_bounds =
// well-formed, then, A must be lower-generic by `'a`, but we
// don't know that this holds from first principles.
for &(ref r, ref p) in &rcx.region_bound_pairs {
- debug!("generic={} p={}",
- generic.repr(rcx.tcx()),
- p.repr(rcx.tcx()));
+ debug!("generic={:?} p={:?}",
+ generic,
+ p);
if generic == p {
param_bounds.push(*r);
}
let tcx = fcx.tcx();
let infcx = fcx.infcx();
- debug!("projection_bounds(projection_ty={})",
- projection_ty.repr(tcx));
+ debug!("projection_bounds(projection_ty={:?})",
+ projection_ty);
let ty = ty::mk_projection(tcx, projection_ty.trait_ref.clone(), projection_ty.item_name);
_ => { return None; }
};
- debug!("projection_bounds: outlives={} (1)",
- outlives.repr(tcx));
+ debug!("projection_bounds: outlives={:?} (1)",
+ outlives);
// apply the substitutions (and normalize any projected types)
let outlives = fcx.instantiate_type_scheme(span,
projection_ty.trait_ref.substs,
&outlives);
- debug!("projection_bounds: outlives={} (2)",
- outlives.repr(tcx));
+ debug!("projection_bounds: outlives={:?} (2)",
+ outlives);
let region_result = infcx.commit_if_ok(|_| {
let (outlives, _) =
infer::AssocTypeProjection(projection_ty.item_name),
&outlives);
- debug!("projection_bounds: outlives={} (3)",
- outlives.repr(tcx));
+ debug!("projection_bounds: outlives={:?} (3)",
+ outlives);
// check whether this predicate applies to our current projection
match infer::mk_eqty(infcx, false, infer::Misc(span), ty, outlives.0) {
}
});
- debug!("projection_bounds: region_result={}",
- region_result.repr(tcx));
+ debug!("projection_bounds: region_result={:?}",
+ region_result);
region_result.ok()
})
use syntax::ast_util;
use syntax::codemap::Span;
use syntax::visit::{self, Visitor};
-use util::ppaux::Repr;
///////////////////////////////////////////////////////////////////////////
// PUBLIC ENTRY POINTS
if !self.fcx.inh.closure_kinds.borrow().contains_key(&closure_def_id) {
self.closures_with_inferred_kinds.insert(expr.id);
self.fcx.inh.closure_kinds.borrow_mut().insert(closure_def_id, ty::FnClosureKind);
- debug!("check_closure: adding closure_id={} to closures_with_inferred_kinds",
- closure_def_id.repr(self.tcx()));
+ debug!("check_closure: adding closure_id={:?} to closures_with_inferred_kinds",
+ closure_def_id);
}
ty::with_freevars(self.tcx(), expr.id, |freevars| {
AdjustBorrowKind { fcx: fcx, closures_with_inferred_kinds: closures_with_inferred_kinds }
}
- fn tcx(&self) -> &'a ty::ctxt<'tcx> {
- self.fcx.tcx()
- }
-
fn analyze_closure(&mut self, id: ast::NodeId, decl: &ast::FnDecl, body: &ast::Block) {
/*!
* Analysis starting point.
if self.closures_with_inferred_kinds.contains(&id) {
let mut deferred_call_resolutions =
self.fcx.remove_deferred_call_resolutions(closure_def_id);
- for deferred_call_resolution in deferred_call_resolutions.iter_mut() {
+ for deferred_call_resolution in &mut deferred_call_resolutions {
deferred_call_resolution.resolve(self.fcx);
}
}
cmt: mc::cmt<'tcx>,
mode: euv::ConsumeMode)
{
- debug!("adjust_upvar_borrow_kind_for_consume(cmt={}, mode={:?})",
- cmt.repr(self.tcx()), mode);
+ debug!("adjust_upvar_borrow_kind_for_consume(cmt={:?}, mode={:?})",
+ cmt, mode);
// we only care about moves
match mode {
// for that to be legal, the upvar would have to be borrowed
// by value instead
let guarantor = cmt.guarantor();
- debug!("adjust_upvar_borrow_kind_for_consume: guarantor={}",
- guarantor.repr(self.tcx()));
+ debug!("adjust_upvar_borrow_kind_for_consume: guarantor={:?}",
+ guarantor);
match guarantor.cat {
mc::cat_deref(_, _, mc::BorrowedPtr(..)) |
mc::cat_deref(_, _, mc::Implicit(..)) => {
/// to). If cmt contains any by-ref upvars, this implies that
/// those upvars must be borrowed using an `&mut` borrow.
fn adjust_upvar_borrow_kind_for_mut(&mut self, cmt: mc::cmt<'tcx>) {
- debug!("adjust_upvar_borrow_kind_for_mut(cmt={})",
- cmt.repr(self.tcx()));
+ debug!("adjust_upvar_borrow_kind_for_mut(cmt={:?})",
+ cmt);
match cmt.cat.clone() {
mc::cat_deref(base, _, mc::Unique) |
}
fn adjust_upvar_borrow_kind_for_unique(&self, cmt: mc::cmt<'tcx>) {
- debug!("adjust_upvar_borrow_kind_for_unique(cmt={})",
- cmt.repr(self.tcx()));
+ debug!("adjust_upvar_borrow_kind_for_unique(cmt={:?})",
+ cmt);
match cmt.cat.clone() {
mc::cat_deref(base, _, mc::Unique) |
cmt: mc::cmt<'tcx>,
mode: euv::ConsumeMode)
{
- debug!("consume(cmt={},mode={:?})", cmt.repr(self.tcx()), mode);
+ debug!("consume(cmt={:?},mode={:?})", cmt, mode);
self.adjust_upvar_borrow_kind_for_consume(cmt, mode);
}
cmt: mc::cmt<'tcx>,
mode: euv::ConsumeMode)
{
- debug!("consume_pat(cmt={},mode={:?})", cmt.repr(self.tcx()), mode);
+ debug!("consume_pat(cmt={:?},mode={:?})", cmt, mode);
self.adjust_upvar_borrow_kind_for_consume(cmt, mode);
}
bk: ty::BorrowKind,
_loan_cause: euv::LoanCause)
{
- debug!("borrow(borrow_id={}, cmt={}, bk={:?})",
- borrow_id, cmt.repr(self.tcx()), bk);
+ debug!("borrow(borrow_id={}, cmt={:?}, bk={:?})",
+ borrow_id, cmt, bk);
match bk {
ty::ImmBorrow => { }
assignee_cmt: mc::cmt<'tcx>,
_mode: euv::MutateMode)
{
- debug!("mutate(assignee_cmt={})",
- assignee_cmt.repr(self.tcx()));
+ debug!("mutate(assignee_cmt={:?})",
+ assignee_cmt);
self.adjust_upvar_borrow_kind_for_mut(assignee_cmt);
}
use middle::ty::{self, Ty};
use middle::ty::liberate_late_bound_regions;
use middle::ty_fold::{TypeFolder, TypeFoldable, super_fold_ty};
-use util::ppaux::{Repr, UserString};
use std::collections::HashSet;
use syntax::ast;
use syntax::ast_util::local_def;
-use syntax::codemap::Span;
+use syntax::codemap::{DUMMY_SP, Span};
use syntax::parse::token::{self, special_idents};
use syntax::visit;
use syntax::visit::Visitor;
self.check_impl(item);
}
ast::ItemImpl(_, ast::ImplPolarity::Negative, _, Some(_), _, _) => {
- let trait_ref = ty::impl_id_to_trait_ref(ccx.tcx, item.id);
+ let trait_ref = ty::impl_trait_ref(ccx.tcx,
+ local_def(item.id)).unwrap();
ty::populate_implementations_for_trait_if_necessary(ccx.tcx, trait_ref.def_id);
match ccx.tcx.lang_items.to_builtin_kind(trait_ref.def_id) {
Some(ty::BoundSend) | Some(ty::BoundSync) => {}
reject_non_type_param_bounds(ccx.tcx, item.span, &trait_predicates);
if ty::trait_has_default_impl(ccx.tcx, local_def(item.id)) {
if !items.is_empty() {
- ccx.tcx.sess.span_err(
- item.span,
- "traits with default impls (`e.g. unsafe impl Trait for ..`) must \
- have no methods or associated items")
+ span_err!(ccx.tcx.sess, item.span, E0380,
+ "traits with default impls (`e.g. unsafe impl \
+ Trait for ..`) must have no methods or associated items")
}
}
}
self.with_fcx(item, |this, fcx| {
let variants = lookup_fields(fcx);
let mut bounds_checker = BoundsChecker::new(fcx,
- item.span,
item.id,
Some(&mut this.cache));
debug!("check_type_defn at bounds_checker.scope: {:?}", bounds_checker.scope);
- for variant in &variants {
+ for variant in &variants {
for field in &variant.fields {
// Regions are checked below.
- bounds_checker.check_traits_in_ty(field.ty);
+ bounds_checker.check_traits_in_ty(field.ty, field.span);
}
// For DST, all intermediate types must be sized.
{
self.with_fcx(item, |this, fcx| {
let mut bounds_checker = BoundsChecker::new(fcx,
- item.span,
item.id,
Some(&mut this.cache));
debug!("check_item_type at bounds_checker.scope: {:?}", bounds_checker.scope);
&fcx.inh.param_env.free_substs,
&type_scheme.ty);
- bounds_checker.check_traits_in_ty(item_ty);
+ bounds_checker.check_traits_in_ty(item_ty, item.span);
});
}
{
self.with_fcx(item, |this, fcx| {
let mut bounds_checker = BoundsChecker::new(fcx,
- item.span,
item.id,
Some(&mut this.cache));
debug!("check_impl at bounds_checker.scope: {:?}", bounds_checker.scope);
&fcx.inh.param_env.free_substs,
&self_ty);
- bounds_checker.check_traits_in_ty(self_ty);
+ bounds_checker.check_traits_in_ty(self_ty, item.span);
// Similarly, obtain an "inside" reference to the trait
// that the impl implements.
// trait reference. Instead, this is done at the impl site.
// Arguably this is wrong and we should treat the trait-reference
// the same way as we treat the self-type.
- bounds_checker.check_trait_ref(&trait_ref);
+ bounds_checker.check_trait_ref(&trait_ref, item.span);
let cause =
traits::ObligationCause::new(
span: Span,
param_name: ast::Name)
{
- self.tcx().sess.span_err(
- span,
- &format!("parameter `{}` is never used",
- param_name.user_string(self.tcx())));
+ span_err!(self.tcx().sess, span, E0392,
+ "parameter `{}` is never used", param_name);
let suggested_marker_id = self.tcx().lang_items.phantom_data();
match suggested_marker_id {
self.tcx().sess.fileline_help(
span,
&format!("consider removing `{}` or using a marker such as `{}`",
- param_name.user_string(self.tcx()),
+ param_name,
ty::item_path_str(self.tcx(), def_id)));
}
None => {
fn reject_non_type_param_bounds<'tcx>(tcx: &ty::ctxt<'tcx>,
span: Span,
predicates: &ty::GenericPredicates<'tcx>) {
- for predicate in predicates.predicates.iter() {
+ for predicate in &predicates.predicates {
match predicate {
&ty::Predicate::Trait(ty::Binder(ref tr)) => {
let found_param = tr.input_types().iter()
"cannot bound type `{}`, where clause \
bounds may only be attached to types involving \
type parameters",
- bounded_ty.repr(tcx))
+ bounded_ty)
}
fn is_ty_param(ty: ty::Ty) -> bool {
match &ty.sty {
- &ty::sty::ty_param(_) => true,
+ &ty::TyParam(_) => true,
_ => false
}
}
impl<'cx,'tcx> BoundsChecker<'cx,'tcx> {
pub fn new(fcx: &'cx FnCtxt<'cx,'tcx>,
- span: Span,
scope: ast::NodeId,
cache: Option<&'cx mut HashSet<Ty<'tcx>>>)
-> BoundsChecker<'cx,'tcx> {
- BoundsChecker { fcx: fcx, span: span, scope: scope,
+ BoundsChecker { fcx: fcx, span: DUMMY_SP, scope: scope,
cache: cache, binding_count: 0 }
}
///
/// Note that it does not (currently, at least) check that `A : Copy` (that check is delegated
/// to the point where impl `A : Trait<B>` is implemented).
- pub fn check_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>) {
+ pub fn check_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>, span: Span) {
let trait_predicates = ty::lookup_predicates(self.fcx.tcx(), trait_ref.def_id);
- let bounds = self.fcx.instantiate_bounds(self.span,
+ let bounds = self.fcx.instantiate_bounds(span,
trait_ref.substs,
&trait_predicates);
self.fcx.add_obligations_for_parameters(
traits::ObligationCause::new(
- self.span,
+ span,
self.fcx.body_id,
traits::ItemObligation(trait_ref.def_id)),
&bounds);
- for &ty in trait_ref.substs.types.iter() {
- self.check_traits_in_ty(ty);
+ for &ty in &trait_ref.substs.types {
+ self.check_traits_in_ty(ty, span);
}
}
- pub fn check_ty(&mut self, ty: Ty<'tcx>) {
+ pub fn check_ty(&mut self, ty: Ty<'tcx>, span: Span) {
+ self.span = span;
ty.fold_with(self);
}
- fn check_traits_in_ty(&mut self, ty: Ty<'tcx>) {
+ fn check_traits_in_ty(&mut self, ty: Ty<'tcx>, span: Span) {
+ self.span = span;
// When checking types outside of a type def'n, we ignore
// region obligations. See discussion below in fold_ty().
self.binding_count += 1;
}
fn fold_binder<T>(&mut self, binder: &ty::Binder<T>) -> ty::Binder<T>
- where T : TypeFoldable<'tcx> + Repr<'tcx>
+ where T : TypeFoldable<'tcx>
{
self.binding_count += 1;
let value = liberate_late_bound_regions(
self.fcx.tcx(),
region::DestructionScopeData::new(self.scope),
binder);
- debug!("BoundsChecker::fold_binder: late-bound regions replaced: {} at scope: {:?}",
- value.repr(self.tcx()), self.scope);
+ debug!("BoundsChecker::fold_binder: late-bound regions replaced: {:?} at scope: {:?}",
+ value, self.scope);
let value = value.fold_with(self);
self.binding_count -= 1;
ty::Binder(value)
}
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
- debug!("BoundsChecker t={}",
- t.repr(self.tcx()));
+ debug!("BoundsChecker t={:?}",
+ t);
match self.cache {
Some(ref mut cache) => {
}
match t.sty{
- ty::ty_struct(type_id, substs) |
- ty::ty_enum(type_id, substs) => {
+ ty::TyStruct(type_id, substs) |
+ ty::TyEnum(type_id, substs) => {
let type_predicates = ty::lookup_predicates(self.fcx.tcx(), type_id);
let bounds = self.fcx.instantiate_bounds(self.span, substs,
&type_predicates);
use middle::infer;
use write_substs_to_tcx;
use write_ty_to_tcx;
-use util::ppaux::Repr;
use std::cell::Cell;
wbcx.visit_expr(e);
wbcx.visit_upvar_borrow_map();
wbcx.visit_closures();
- wbcx.visit_object_cast_map();
}
pub fn resolve_type_vars_in_fn(fcx: &FnCtxt,
}
wbcx.visit_upvar_borrow_map();
wbcx.visit_closures();
- wbcx.visit_object_cast_map();
}
///////////////////////////////////////////////////////////////////////////
self.visit_node_id(ResolvingPattern(p.span), p.id);
- debug!("Type for pattern binding {} (id {}) resolved to {}",
+ debug!("Type for pattern binding {} (id {}) resolved to {:?}",
pat_to_string(p),
p.id,
- ty::node_id_to_type(self.tcx(), p.id).repr(self.tcx()));
+ ty::node_id_to_type(self.tcx(), p.id));
visit::walk_pat(self, p);
}
return;
}
- for (upvar_id, upvar_capture) in &*self.fcx.inh.upvar_capture_map.borrow() {
+ for (upvar_id, upvar_capture) in self.fcx.inh.upvar_capture_map.borrow().iter() {
let new_upvar_capture = match *upvar_capture {
ty::UpvarCapture::ByValue => ty::UpvarCapture::ByValue,
ty::UpvarCapture::ByRef(ref upvar_borrow) => {
ty::UpvarBorrow { kind: upvar_borrow.kind, region: r })
}
};
- debug!("Upvar capture for {} resolved to {}",
- upvar_id.repr(self.tcx()),
- new_upvar_capture.repr(self.tcx()));
+ debug!("Upvar capture for {:?} resolved to {:?}",
+ upvar_id,
+ new_upvar_capture);
self.fcx.tcx().upvar_capture_map.borrow_mut().insert(*upvar_id, new_upvar_capture);
}
}
return
}
- for (def_id, closure_ty) in &*self.fcx.inh.closure_tys.borrow() {
+ for (def_id, closure_ty) in self.fcx.inh.closure_tys.borrow().iter() {
let closure_ty = self.resolve(closure_ty, ResolvingClosure(*def_id));
self.fcx.tcx().closure_tys.borrow_mut().insert(*def_id, closure_ty);
}
- for (def_id, &closure_kind) in &*self.fcx.inh.closure_kinds.borrow() {
+ for (def_id, &closure_kind) in self.fcx.inh.closure_kinds.borrow().iter() {
self.fcx.tcx().closure_kinds.borrow_mut().insert(*def_id, closure_kind);
}
}
- fn visit_object_cast_map(&self) {
- if self.fcx.writeback_errors.get() {
- return
- }
-
- for (&node_id, trait_ref) in self.fcx
- .inh
- .object_cast_map
- .borrow()
- .iter()
- {
- let span = ty::expr_span(self.tcx(), node_id);
- let reason = ResolvingExpr(span);
- let closure_ty = self.resolve(trait_ref, reason);
- self.tcx()
- .object_cast_map
- .borrow_mut()
- .insert(node_id, closure_ty);
- }
- }
-
fn visit_node_id(&self, reason: ResolveReason, id: ast::NodeId) {
// Resolve any borrowings for the node with id `id`
self.visit_adjustments(reason, id);
let n_ty = self.fcx.node_ty(id);
let n_ty = self.resolve(&n_ty, reason);
write_ty_to_tcx(self.tcx(), id, n_ty);
- debug!("Node {} has type {}", id, n_ty.repr(self.tcx()));
+ debug!("Node {} has type {:?}", id, n_ty);
// Resolve any substitutions
self.fcx.opt_node_ty_substs(id, |item_substs| {
// Resolve any method map entry
match self.fcx.inh.method_map.borrow_mut().remove(&method_call) {
Some(method) => {
- debug!("writeback::resolve_method_map_entry(call={:?}, entry={})",
+ debug!("writeback::resolve_method_map_entry(call={:?}, entry={:?})",
method_call,
- method.repr(self.tcx()));
+ method);
let new_method = MethodCallee {
origin: self.resolve(&method.origin, reason),
ty: self.resolve(&method.ty, reason),
match self.infcx.fully_resolve(&t) {
Ok(t) => t,
Err(e) => {
- debug!("Resolver::fold_ty: input type `{}` not fully resolvable",
- t.repr(self.tcx));
+ debug!("Resolver::fold_ty: input type `{:?}` not fully resolvable",
+ t);
self.report_error(e);
self.tcx().types.err
}
use middle::ty::RegionEscape;
use middle::ty::{ImplContainer, ImplOrTraitItemId, ConstTraitItemId};
use middle::ty::{MethodTraitItemId, TypeTraitItemId, ParameterEnvironment};
-use middle::ty::{Ty, ty_bool, ty_char, ty_enum, ty_err};
-use middle::ty::{ty_param, TypeScheme, ty_ptr};
-use middle::ty::{ty_rptr, ty_struct, ty_trait, ty_tup};
-use middle::ty::{ty_str, ty_vec, ty_float, ty_infer, ty_int};
-use middle::ty::{ty_uint, ty_closure, ty_uniq, ty_bare_fn};
-use middle::ty::ty_projection;
+use middle::ty::{Ty, TyBool, TyChar, TyEnum, TyError};
+use middle::ty::{TyParam, TypeScheme, TyRawPtr};
+use middle::ty::{TyRef, TyStruct, TyTrait, TyTuple};
+use middle::ty::{TyStr, TyArray, TySlice, TyFloat, TyInfer, TyInt};
+use middle::ty::{TyUint, TyClosure, TyBox, TyBareFn};
+use middle::ty::TyProjection;
use middle::ty;
use middle::free_region::FreeRegionMap;
use CrateCtxt;
use middle::infer::{self, InferCtxt, new_infer_ctxt};
+use rustc::ast_map::{self, NodeItem};
use std::cell::RefCell;
use std::rc::Rc;
use syntax::ast::{Crate, DefId};
use syntax::ast::{Item, ItemImpl};
-use syntax::ast::{LOCAL_CRATE, TraitRef};
+use syntax::ast::{LOCAL_CRATE};
use syntax::ast;
-use syntax::ast_map::NodeItem;
-use syntax::ast_map;
use syntax::ast_util::local_def;
use syntax::codemap::Span;
use syntax::parse::token;
use syntax::visit;
use util::nodemap::{DefIdMap, FnvHashMap};
-use util::ppaux::Repr;
mod orphan;
mod overlap;
ty: Ty<'tcx>)
-> Option<DefId> {
match ty.sty {
- ty_enum(def_id, _) |
- ty_struct(def_id, _) => {
+ TyEnum(def_id, _) |
+ TyStruct(def_id, _) => {
Some(def_id)
}
- ty_trait(ref t) => {
+ TyTrait(ref t) => {
Some(t.principal_def_id())
}
- ty_uniq(_) => {
+ TyBox(_) => {
inference_context.tcx.lang_items.owned_box()
}
- ty_bool | ty_char | ty_int(..) | ty_uint(..) | ty_float(..) |
- ty_str(..) | ty_vec(..) | ty_bare_fn(..) | ty_tup(..) |
- ty_param(..) | ty_err |
- ty_ptr(_) | ty_rptr(_, _) | ty_projection(..) => {
+ TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) |
+ TyStr(..) | TyArray(..) | TySlice(..) | TyBareFn(..) | TyTuple(..) |
+ TyParam(..) | TyError |
+ TyRawPtr(_) | TyRef(_, _) | TyProjection(..) => {
None
}
- ty_infer(..) | ty_closure(..) => {
+ TyInfer(..) | TyClosure(..) => {
// `ty` comes from a user declaration so we should only expect types
// that the user can type
inference_context.tcx.sess.span_bug(
span,
&format!("coherence encountered unexpected type searching for base type: {}",
- ty.repr(inference_context.tcx)));
+ ty));
}
}
}
impl<'a, 'tcx, 'v> visit::Visitor<'v> for CoherenceCheckVisitor<'a, 'tcx> {
fn visit_item(&mut self, item: &Item) {
-
- //debug!("(checking coherence) item '{}'", token::get_ident(item.ident));
-
- if let ItemImpl(_, _, _, ref opt_trait, _, _) = item.node {
- self.cc.check_implementation(item, opt_trait.as_ref())
+ if let ItemImpl(..) = item.node {
+ self.cc.check_implementation(item)
}
visit::walk_item(self, item);
// the tcx.
let mut tcx_inherent_impls =
self.crate_context.tcx.inherent_impls.borrow_mut();
- for (k, v) in &*self.inherent_impls.borrow() {
+ for (k, v) in self.inherent_impls.borrow().iter() {
tcx_inherent_impls.insert((*k).clone(),
Rc::new((*v.borrow()).clone()));
}
self.check_implementations_of_coerce_unsized();
}
- fn check_implementation(&self, item: &Item, opt_trait: Option<&TraitRef>) {
+ fn check_implementation(&self, item: &Item) {
let tcx = self.crate_context.tcx;
let impl_did = local_def(item.id);
let self_type = ty::lookup_item_type(tcx, impl_did);
let impl_items = self.create_impl_from_item(item);
- if opt_trait.is_some() {
- let trait_ref = ty::impl_id_to_trait_ref(self.crate_context.tcx, item.id);
- debug!("(checking implementation) adding impl for trait '{}', item '{}'",
- trait_ref.repr(self.crate_context.tcx),
- token::get_ident(item.ident));
+ if let Some(trait_ref) = ty::impl_trait_ref(self.crate_context.tcx,
+ impl_did) {
+ debug!("(checking implementation) adding impl for trait '{:?}', item '{}'",
+ trait_ref,
+ item.ident);
enforce_trait_manually_implementable(self.crate_context.tcx,
item.span,
trait_ref.def_id);
self.add_trait_impl(trait_ref, impl_did);
- }
-
- // Add the implementation to the mapping from implementation to base
- // type def ID, if there is a base type for this implementation and
- // the implementation does not have any associated traits.
- match get_base_type_def_id(&self.inference_context,
- item.span,
- self_type.ty) {
- None => {
- // Nothing to do.
- }
- Some(base_type_def_id) => {
- // FIXME: Gather up default methods?
- if opt_trait.is_none() {
- self.add_inherent_impl(base_type_def_id, impl_did);
- }
+ } else {
+ // Add the implementation to the mapping from implementation to base
+ // type def ID, if there is a base type for this implementation and
+ // the implementation does not have any associated traits.
+ if let Some(base_type_def_id) = get_base_type_def_id(
+ &self.inference_context, item.span, self_type.ty) {
+ self.add_inherent_impl(base_type_def_id, impl_did);
}
}
trait_ref: &ty::TraitRef<'tcx>,
all_impl_items: &mut Vec<ImplOrTraitItemId>) {
let tcx = self.crate_context.tcx;
- debug!("instantiate_default_methods(impl_id={:?}, trait_ref={})",
- impl_id, trait_ref.repr(tcx));
+ debug!("instantiate_default_methods(impl_id={:?}, trait_ref={:?})",
+ impl_id, trait_ref);
let impl_type_scheme = ty::lookup_item_type(tcx, impl_id);
let new_id = tcx.sess.next_node_id();
let new_did = local_def(new_id);
- debug!("new_did={:?} trait_method={}", new_did, trait_method.repr(tcx));
+ debug!("new_did={:?} trait_method={:?}", new_did, trait_method);
// Create substitutions for the various trait parameters.
let new_method_ty =
&**trait_method,
Some(trait_method.def_id)));
- debug!("new_method_ty={}", new_method_ty.repr(tcx));
+ debug!("new_method_ty={:?}", new_method_ty);
all_impl_items.push(MethodTraitItemId(new_did));
// construct the polytype for the method based on the
ty: ty::mk_bare_fn(tcx, Some(new_did),
tcx.mk_bare_fn(new_method_ty.fty.clone()))
};
- debug!("new_polytype={}", new_polytype.repr(tcx));
+ debug!("new_polytype={:?}", new_polytype);
tcx.tcache.borrow_mut().insert(new_did, new_polytype);
tcx.predicates.borrow_mut().insert(new_did, new_method_ty.predicates.clone());
// Converts an implementation in the AST to a vector of items.
fn create_impl_from_item(&self, item: &Item) -> Vec<ImplOrTraitItemId> {
match item.node {
- ItemImpl(_, _, _, ref opt_trait, _, ref impl_items) => {
+ ItemImpl(_, _, _, _, _, ref impl_items) => {
let mut items: Vec<ImplOrTraitItemId> =
impl_items.iter().map(|impl_item| {
match impl_item.node {
}
}).collect();
- if opt_trait.is_some() {
- let trait_ref = ty::impl_id_to_trait_ref(self.crate_context.tcx,
- item.id);
-
+ if let Some(trait_ref) = ty::impl_trait_ref(self.crate_context.tcx,
+ local_def(item.id)) {
self.instantiate_default_methods(local_def(item.id),
&trait_ref,
&mut items);
}
_ => {
self.crate_context.tcx.sess.span_bug(item.span,
- "can't convert a non-impl to an impl");
+ "can't convert a non-impl \
+ to an impl");
}
}
}
let self_type = ty::lookup_item_type(tcx, impl_did);
match self_type.ty.sty {
- ty::ty_enum(type_def_id, _) |
- ty::ty_struct(type_def_id, _) |
- ty::ty_closure(type_def_id, _) => {
+ ty::TyEnum(type_def_id, _) |
+ ty::TyStruct(type_def_id, _) |
+ ty::TyClosure(type_def_id, _) => {
tcx.destructor_for_type
.borrow_mut()
.insert(type_def_id, method_def_id.def_id());
let copy_trait = ty::lookup_trait_def(tcx, copy_trait);
copy_trait.for_each_impl(tcx, |impl_did| {
- debug!("check_implementations_of_copy: impl_did={}",
- impl_did.repr(tcx));
+ debug!("check_implementations_of_copy: impl_did={:?}",
+ impl_did);
if impl_did.krate != ast::LOCAL_CRATE {
debug!("check_implementations_of_copy(): impl not in this \
}
let self_type = ty::lookup_item_type(tcx, impl_did);
- debug!("check_implementations_of_copy: self_type={} (bound)",
- self_type.repr(tcx));
+ debug!("check_implementations_of_copy: self_type={:?} (bound)",
+ self_type);
let span = tcx.map.span(impl_did.node);
let param_env = ParameterEnvironment::for_item(tcx, impl_did.node);
let self_type = self_type.ty.subst(tcx, ¶m_env.free_substs);
assert!(!self_type.has_escaping_regions());
- debug!("check_implementations_of_copy: self_type={} (free)",
- self_type.repr(tcx));
+ debug!("check_implementations_of_copy: self_type={:?} (free)",
+ self_type);
match ty::can_type_implement_copy(¶m_env, span, self_type) {
Ok(()) => {}
let trait_def = ty::lookup_trait_def(tcx, coerce_unsized_trait);
trait_def.for_each_impl(tcx, |impl_did| {
- debug!("check_implementations_of_coerce_unsized: impl_did={}",
- impl_did.repr(tcx));
+ debug!("check_implementations_of_coerce_unsized: impl_did={:?}",
+ impl_did);
if impl_did.krate != ast::LOCAL_CRATE {
debug!("check_implementations_of_coerce_unsized(): impl not \
}
let source = ty::lookup_item_type(tcx, impl_did).ty;
- let trait_ref = ty::impl_id_to_trait_ref(self.crate_context.tcx,
- impl_did.node);
+ let trait_ref = ty::impl_trait_ref(self.crate_context.tcx,
+ impl_did).unwrap();
let target = *trait_ref.substs.types.get(subst::TypeSpace, 0);
- debug!("check_implementations_of_coerce_unsized: {} -> {} (bound)",
- source.repr(tcx), target.repr(tcx));
+ debug!("check_implementations_of_coerce_unsized: {:?} -> {:?} (bound)",
+ source, target);
let span = tcx.map.span(impl_did.node);
let param_env = ParameterEnvironment::for_item(tcx, impl_did.node);
let target = target.subst(tcx, ¶m_env.free_substs);
assert!(!source.has_escaping_regions());
- debug!("check_implementations_of_coerce_unsized: {} -> {} (free)",
- source.repr(tcx), target.repr(tcx));
+ debug!("check_implementations_of_coerce_unsized: {:?} -> {:?} (free)",
+ source, target);
let infcx = new_infer_ctxt(tcx);
(mt_a.ty, mt_b.ty, unsize_trait, None)
};
let (source, target, trait_def_id, kind) = match (&source.sty, &target.sty) {
- (&ty::ty_uniq(a), &ty::ty_uniq(b)) => (a, b, unsize_trait, None),
+ (&ty::TyBox(a), &ty::TyBox(b)) => (a, b, unsize_trait, None),
- (&ty::ty_rptr(r_a, mt_a), &ty::ty_rptr(r_b, mt_b)) => {
+ (&ty::TyRef(r_a, mt_a), &ty::TyRef(r_b, mt_b)) => {
infer::mk_subr(&infcx, infer::RelateObjectBound(span), *r_b, *r_a);
check_mutbl(mt_a, mt_b, &|ty| ty::mk_imm_rptr(tcx, r_b, ty))
}
- (&ty::ty_rptr(_, mt_a), &ty::ty_ptr(mt_b)) |
- (&ty::ty_ptr(mt_a), &ty::ty_ptr(mt_b)) => {
+ (&ty::TyRef(_, mt_a), &ty::TyRawPtr(mt_b)) |
+ (&ty::TyRawPtr(mt_a), &ty::TyRawPtr(mt_b)) => {
check_mutbl(mt_a, mt_b, &|ty| ty::mk_imm_ptr(tcx, ty))
}
- (&ty::ty_struct(def_id_a, substs_a), &ty::ty_struct(def_id_b, substs_b)) => {
+ (&ty::TyStruct(def_id_a, substs_a), &ty::TyStruct(def_id_b, substs_b)) => {
if def_id_a != def_id_b {
let source_path = ty::item_path_str(tcx, def_id_a);
let target_path = ty::item_path_str(tcx, def_id_b);
if name == token::special_names::unnamed_field {
i.to_string()
} else {
- token::get_name(name).to_string()
- },
- a.repr(tcx),
- b.repr(tcx))
+ name.to_string()
+ }, a, b)
}).collect::<Vec<_>>().connect(", "));
return;
}
}
};
- let mut fulfill_cx = traits::FulfillmentContext::new();
+ let mut fulfill_cx = traits::FulfillmentContext::new(true);
// Register an obligation for `A: Trait<B>`.
let cause = traits::ObligationCause::misc(span, impl_did.node);
{
let combined_substs = ty::make_substs_for_receiver_types(tcx, trait_ref, method);
- debug!("subst_receiver_types_in_method_ty: combined_substs={}",
- combined_substs.repr(tcx));
+ debug!("subst_receiver_types_in_method_ty: combined_substs={:?}",
+ combined_substs);
let method_predicates = method.predicates.subst(tcx, &combined_substs);
let mut method_generics = method.generics.subst(tcx, &combined_substs);
impl_type_scheme.generics.regions.get_slice(space).to_vec());
}
- debug!("subst_receiver_types_in_method_ty: method_generics={}",
- method_generics.repr(tcx));
+ debug!("subst_receiver_types_in_method_ty: method_generics={:?}",
+ method_generics);
let method_fty = method.fty.subst(tcx, &combined_substs);
- debug!("subst_receiver_types_in_method_ty: method_ty={}",
- method.fty.repr(tcx));
+ debug!("subst_receiver_types_in_method_ty: method_ty={:?}",
+ method.fty);
ty::Method::new(
method.name,
use syntax::ast_util;
use syntax::codemap::Span;
use syntax::visit;
-use util::ppaux::{Repr, UserString};
pub fn check(tcx: &ty::ctxt) {
let mut orphan = OrphanChecker { tcx: tcx };
fn check_def_id(&self, item: &ast::Item, def_id: ast::DefId) {
if def_id.krate != ast::LOCAL_CRATE {
span_err!(self.tcx.sess, item.span, E0116,
- "cannot associate methods with a type outside the \
- crate the type is defined in; define and implement \
+ "cannot define inherent `impl` for a type outside of the \
+ crate where the type is defined; define and implement \
a trait or new type instead");
}
}
match lang_def_id {
Some(lang_def_id) if lang_def_id == impl_def_id => { /* OK */ },
_ => {
- self.tcx.sess.span_err(
- span,
- &format!("only a single inherent implementation marked with `#[lang = \"{}\"]` \
- is allowed for the `{}` primitive", lang, ty));
+ span_err!(self.tcx.sess, span, E0390,
+ "only a single inherent implementation marked with `#[lang = \"{}\"]` \
+ is allowed for the `{}` primitive", lang, ty);
}
}
}
ast::ItemImpl(_, _, _, None, _, _) => {
// For inherent impls, self type must be a nominal type
// defined in this crate.
- debug!("coherence2::orphan check: inherent impl {}", item.repr(self.tcx));
+ debug!("coherence2::orphan check: inherent impl {}",
+ self.tcx.map.node_to_string(item.id));
let self_ty = ty::lookup_item_type(self.tcx, def_id).ty;
match self_ty.sty {
- ty::ty_enum(def_id, _) |
- ty::ty_struct(def_id, _) => {
+ ty::TyEnum(def_id, _) |
+ ty::TyStruct(def_id, _) => {
self.check_def_id(item, def_id);
}
- ty::ty_trait(ref data) => {
+ ty::TyTrait(ref data) => {
self.check_def_id(item, data.principal_def_id());
}
- ty::ty_uniq(..) => {
+ ty::TyBox(..) => {
self.check_def_id(item, self.tcx.lang_items.owned_box().unwrap());
}
- ty::ty_char => {
+ ty::TyChar => {
self.check_primitive_impl(def_id,
self.tcx.lang_items.char_impl(),
"char",
"char",
item.span);
}
- ty::ty_str => {
+ ty::TyStr => {
self.check_primitive_impl(def_id,
self.tcx.lang_items.str_impl(),
"str",
"str",
item.span);
}
- ty::ty_vec(_, None) => {
+ ty::TySlice(_) => {
self.check_primitive_impl(def_id,
self.tcx.lang_items.slice_impl(),
"slice",
"[T]",
item.span);
}
- ty::ty_ptr(ty::mt { ty: _, mutbl: ast::MutImmutable }) => {
+ ty::TyRawPtr(ty::mt { ty: _, mutbl: ast::MutImmutable }) => {
self.check_primitive_impl(def_id,
self.tcx.lang_items.const_ptr_impl(),
"const_ptr",
"*const T",
item.span);
}
- ty::ty_ptr(ty::mt { ty: _, mutbl: ast::MutMutable }) => {
+ ty::TyRawPtr(ty::mt { ty: _, mutbl: ast::MutMutable }) => {
self.check_primitive_impl(def_id,
self.tcx.lang_items.mut_ptr_impl(),
"mut_ptr",
"*mut T",
item.span);
}
- ty::ty_int(ast::TyI8) => {
+ ty::TyInt(ast::TyI8) => {
self.check_primitive_impl(def_id,
self.tcx.lang_items.i8_impl(),
"i8",
"i8",
item.span);
}
- ty::ty_int(ast::TyI16) => {
+ ty::TyInt(ast::TyI16) => {
self.check_primitive_impl(def_id,
self.tcx.lang_items.i16_impl(),
"i16",
"i16",
item.span);
}
- ty::ty_int(ast::TyI32) => {
+ ty::TyInt(ast::TyI32) => {
self.check_primitive_impl(def_id,
self.tcx.lang_items.i32_impl(),
"i32",
"i32",
item.span);
}
- ty::ty_int(ast::TyI64) => {
+ ty::TyInt(ast::TyI64) => {
self.check_primitive_impl(def_id,
self.tcx.lang_items.i64_impl(),
"i64",
"i64",
item.span);
}
- ty::ty_int(ast::TyIs) => {
+ ty::TyInt(ast::TyIs) => {
self.check_primitive_impl(def_id,
self.tcx.lang_items.isize_impl(),
"isize",
"isize",
item.span);
}
- ty::ty_uint(ast::TyU8) => {
+ ty::TyUint(ast::TyU8) => {
self.check_primitive_impl(def_id,
self.tcx.lang_items.u8_impl(),
"u8",
"u8",
item.span);
}
- ty::ty_uint(ast::TyU16) => {
+ ty::TyUint(ast::TyU16) => {
self.check_primitive_impl(def_id,
self.tcx.lang_items.u16_impl(),
"u16",
"u16",
item.span);
}
- ty::ty_uint(ast::TyU32) => {
+ ty::TyUint(ast::TyU32) => {
self.check_primitive_impl(def_id,
self.tcx.lang_items.u32_impl(),
"u32",
"u32",
item.span);
}
- ty::ty_uint(ast::TyU64) => {
+ ty::TyUint(ast::TyU64) => {
self.check_primitive_impl(def_id,
self.tcx.lang_items.u64_impl(),
"u64",
"u64",
item.span);
}
- ty::ty_uint(ast::TyUs) => {
+ ty::TyUint(ast::TyUs) => {
self.check_primitive_impl(def_id,
self.tcx.lang_items.usize_impl(),
"usize",
"usize",
item.span);
}
- ty::ty_float(ast::TyF32) => {
+ ty::TyFloat(ast::TyF32) => {
self.check_primitive_impl(def_id,
self.tcx.lang_items.f32_impl(),
"f32",
"f32",
item.span);
}
- ty::ty_float(ast::TyF64) => {
+ ty::TyFloat(ast::TyF64) => {
self.check_primitive_impl(def_id,
self.tcx.lang_items.f64_impl(),
"f64",
}
ast::ItemImpl(_, _, _, Some(_), _, _) => {
// "Trait" impl
- debug!("coherence2::orphan check: trait impl {}", item.repr(self.tcx));
+ debug!("coherence2::orphan check: trait impl {}",
+ self.tcx.map.node_to_string(item.id));
let trait_ref = ty::impl_trait_ref(self.tcx, def_id).unwrap();
let trait_def_id = trait_ref.def_id;
match traits::orphan_check(self.tcx, def_id) {
"type parameter `{}` must be used as the type parameter for \
some local type (e.g. `MyStruct<T>`); only traits defined in \
the current crate can be implemented for a type parameter",
- param_ty.user_string(self.tcx));
+ param_ty);
return;
}
}
// This final impl is legal according to the orpan
// rules, but it invalidates the reasoning from
// `two_foos` above.
- debug!("trait_ref={} trait_def_id={} trait_has_default_impl={}",
- trait_ref.repr(self.tcx),
- trait_def_id.repr(self.tcx),
+ debug!("trait_ref={:?} trait_def_id={:?} trait_has_default_impl={}",
+ trait_ref,
+ trait_def_id,
ty::trait_has_default_impl(self.tcx, trait_def_id));
if
ty::trait_has_default_impl(self.tcx, trait_def_id) &&
{
let self_ty = trait_ref.self_ty();
let opt_self_def_id = match self_ty.sty {
- ty::ty_struct(self_def_id, _) | ty::ty_enum(self_def_id, _) =>
+ ty::TyStruct(self_def_id, _) | ty::TyEnum(self_def_id, _) =>
Some(self_def_id),
- ty::ty_uniq(..) =>
+ ty::TyBox(..) =>
self.tcx.lang_items.owned_box(),
_ =>
None
can only be implemented for a struct/enum type, \
not `{}`",
ty::item_path_str(self.tcx, trait_def_id),
- self_ty.user_string(self.tcx)))
+ self_ty))
}
};
}
ast::ItemDefaultImpl(..) => {
// "Trait" impl
- debug!("coherence2::orphan check: default trait impl {}", item.repr(self.tcx));
+ debug!("coherence2::orphan check: default trait impl {}",
+ self.tcx.map.node_to_string(item.id));
let trait_ref = ty::impl_trait_ref(self.tcx, def_id).unwrap();
if trait_ref.def_id.krate != ast::LOCAL_CRATE {
span_err!(self.tcx.sess, item.span, E0318,
use syntax::visit;
use syntax::codemap::Span;
use util::nodemap::DefIdMap;
-use util::ppaux::{Repr, UserString};
pub fn check(tcx: &ty::ctxt) {
let mut overlap = OverlapChecker { tcx: tcx, default_impls: DefIdMap() };
fn check_for_overlapping_impls_of_trait(&self,
trait_def: &'tcx ty::TraitDef<'tcx>)
{
- debug!("check_for_overlapping_impls_of_trait(trait_def={})",
- trait_def.repr(self.tcx));
+ debug!("check_for_overlapping_impls_of_trait(trait_def={:?})",
+ trait_def);
// We should already know all impls of this trait, so these
// borrows are safe.
if let Some((impl1_def_id, impl2_def_id)) = self.order_impls(
impl1_def_id, impl2_def_id)
{
- debug!("check_if_impls_overlap({}, {}, {})",
- trait_def_id.repr(self.tcx),
- impl1_def_id.repr(self.tcx),
- impl2_def_id.repr(self.tcx));
+ debug!("check_if_impls_overlap({:?}, {:?}, {:?})",
+ trait_def_id,
+ impl1_def_id,
+ impl2_def_id);
let infcx = infer::new_infer_ctxt(self.tcx);
if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id) {
let trait_ref = ty::impl_trait_ref(self.tcx, impl_def_id).unwrap();
let trait_def_id = trait_ref.def_id;
match trait_ref.self_ty().sty {
- ty::ty_trait(ref data) => {
+ ty::TyTrait(ref data) => {
// This is something like impl Trait1 for Trait2. Illegal
// if Trait1 is a supertrait of Trait2 or Trait2 is not object safe.
span_err!(self.tcx.sess, item.span, E0371,
"the object type `{}` automatically \
implements the trait `{}`",
- trait_ref.self_ty().user_string(self.tcx),
+ trait_ref.self_ty(),
ty::item_path_str(self.tcx, trait_def_id));
}
}
use syntax::ast;
use syntax::ast_util;
use syntax::visit;
-use util::ppaux::UserString;
pub fn check(tcx: &ty::ctxt) {
let mut orphan = UnsafetyChecker { tcx: tcx };
(ast::Unsafety::Normal, ast::Unsafety::Unsafe, _) => {
span_err!(self.tcx.sess, item.span, E0199,
"implementing the trait `{}` is not unsafe",
- trait_ref.user_string(self.tcx));
+ trait_ref);
}
(ast::Unsafety::Unsafe,
ast::Unsafety::Normal, ast::ImplPolarity::Positive) => {
span_err!(self.tcx.sess, item.span, E0200,
"the trait `{}` requires an `unsafe impl` declaration",
- trait_ref.user_string(self.tcx));
+ trait_ref);
}
(ast::Unsafety::Unsafe,
use middle::ty_fold::{self, TypeFolder, TypeFoldable};
use middle::infer;
use rscope::*;
+use rustc::ast_map;
use util::common::{ErrorReported, memoized};
use util::nodemap::{FnvHashMap, FnvHashSet};
-use util::ppaux;
-use util::ppaux::{Repr,UserString};
use write_ty_to_tcx;
use std::cell::{Cell, RefCell};
use syntax::abi;
use syntax::ast;
-use syntax::ast_map;
use syntax::ast_util::local_def;
use syntax::codemap::Span;
use syntax::parse::token::special_idents;
assert!(!cycle.is_empty());
let tcx = self.tcx;
- tcx.sess.span_err(
- span,
- &format!("unsupported cyclic reference between types/traits detected"));
+ span_err!(tcx.sess, span, E0391,
+ "unsupported cyclic reference between types/traits detected");
match cycle[0] {
AstConvRequest::GetItemTypeScheme(def_id) |
tcx.sess.note(
&format!("the cycle begins when computing the bounds \
for type parameter `{}`...",
- def.name.user_string(tcx)));
+ def.name));
}
}
- for request in cycle[1..].iter() {
+ for request in &cycle[1..] {
match *request {
AstConvRequest::GetItemTypeScheme(def_id) |
AstConvRequest::GetTraitDef(def_id) => {
tcx.sess.note(
&format!("...which then requires computing the bounds \
for type parameter `{}`...",
- def.name.user_string(tcx)));
+ def.name));
}
}
}
tcx.sess.note(
&format!("...which then again requires computing the bounds \
for type parameter `{}`, completing the cycle.",
- def.name.user_string(tcx)));
+ def.name));
}
}
}
let item = match tcx.map.get(trait_id.node) {
ast_map::NodeItem(item) => item,
- _ => tcx.sess.bug(&format!("get_trait_def({}): not an item", trait_id.repr(tcx)))
+ _ => tcx.sess.bug(&format!("get_trait_def({:?}): not an item", trait_id))
};
trait_def_of_item(self, &*item)
trait_def_id: ast::DefId)
-> Result<(), ErrorReported>
{
- debug!("ensure_super_predicates(trait_def_id={})",
- trait_def_id.repr(self.tcx()));
+ debug!("ensure_super_predicates(trait_def_id={:?})",
+ trait_def_id);
self.ccx.ensure_super_predicates(span, trait_def_id)
}
-> Vec<ty::Predicate<'tcx>>
{
let mut v = self.0.get_type_parameter_bounds(astconv, span, node_id);
- v.extend(self.1.get_type_parameter_bounds(astconv, span, node_id).into_iter());
+ v.extend(self.1.get_type_parameter_bounds(astconv, span, node_id));
v
}
}
.iter()
.filter(|p| p.id == node_id)
.flat_map(|p| p.bounds.iter())
- .flat_map(|b| predicates_from_bound(astconv, ty, b).into_iter());
+ .flat_map(|b| predicates_from_bound(astconv, ty, b));
let from_where_clauses =
self.where_clause
})
.filter(|bp| is_param(astconv.tcx(), &bp.bounded_ty, node_id))
.flat_map(|bp| bp.bounds.iter())
- .flat_map(|b| predicates_from_bound(astconv, ty, b).into_iter());
+ .flat_map(|b| predicates_from_bound(astconv, ty, b));
from_ty_params.chain(from_where_clauses).collect()
}
let fty = ty::mk_bare_fn(ccx.tcx, Some(def_id),
ccx.tcx.mk_bare_fn(ty_method.fty.clone()));
- debug!("method {} (id {}) has type {}",
- ident.repr(ccx.tcx), id, fty.repr(ccx.tcx));
+ debug!("method {} (id {}) has type {:?}",
+ ident, id, fty);
ccx.tcx.tcache.borrow_mut().insert(def_id,TypeScheme {
generics: ty_method.generics.clone(),
ty: fty
write_ty_to_tcx(ccx.tcx, id, fty);
- debug!("writing method type: def_id={:?} mty={}",
- def_id, ty_method.repr(ccx.tcx));
+ debug!("writing method type: def_id={:?} mty={:?}",
+ def_id, ty_method);
ccx.tcx.impl_or_trait_items.borrow_mut().insert(def_id,
ty::MethodTraitItem(Rc::new(ty_method)));
.insert(local_def(id), ty::ConstTraitItem(associated_const));
}
-fn as_refsociated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
- container: ImplOrTraitItemContainer,
- ident: ast::Ident,
- id: ast::NodeId,
- vis: ast::Visibility)
+fn convert_associated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+ container: ImplOrTraitItemContainer,
+ ident: ast::Ident,
+ id: ast::NodeId,
+ vis: ast::Visibility,
+ ty: Option<Ty<'tcx>>)
{
let associated_type = Rc::new(ty::AssociatedType {
name: ident.name,
vis: vis,
+ ty: ty,
def_id: local_def(id),
container: container
});
rcvr_ty_predicates: &ty::GenericPredicates<'tcx>)
where I: Iterator<Item=(&'i ast::MethodSig, ast::NodeId, ast::Ident, ast::Visibility, Span)>
{
- debug!("convert_methods(untransformed_rcvr_ty={}, rcvr_ty_generics={}, rcvr_ty_predicates={})",
- untransformed_rcvr_ty.repr(ccx.tcx),
- rcvr_ty_generics.repr(ccx.tcx),
- rcvr_ty_predicates.repr(ccx.tcx));
+ debug!("convert_methods(untransformed_rcvr_ty={:?}, rcvr_ty_generics={:?}, \
+ rcvr_ty_predicates={:?})",
+ untransformed_rcvr_ty,
+ rcvr_ty_generics,
+ rcvr_ty_predicates);
let tcx = ccx.tcx;
let mut seen_methods = FnvHashSet();
for (sig, id, ident, vis, span) in methods {
if !seen_methods.insert(ident.name) {
- span_err!(tcx.sess, span, E0201, "duplicate method");
+ let fn_desc = match sig.explicit_self.node {
+ ast::SelfStatic => "associated function",
+ _ => "method",
+ };
+ span_err!(tcx.sess, span, E0201, "duplicate {}", fn_desc);
}
convert_method(ccx,
thing: &'static str) {
let mut warn = false;
- for ty_param in &*generics.ty_params {
- for bound in &*ty_param.bounds {
+ for ty_param in generics.ty_params.iter() {
+ for bound in ty_param.bounds.iter() {
match *bound {
ast::TraitTyParamBound(..) => {
warn = true;
ty::record_trait_has_default_impl(tcx, trait_ref.def_id);
- tcx.impl_trait_refs.borrow_mut().insert(it.id, trait_ref);
+ tcx.impl_trait_refs.borrow_mut().insert(local_def(it.id), Some(trait_ref));
}
ast::ItemImpl(_, _,
ref generics,
ref selfty,
ref impl_items) => {
// Create generics from the generics specified in the impl head.
-
debug!("convert: ast_generics={:?}", generics);
let ty_generics = ty_generics_for_type_or_impl(ccx, generics);
let ty_predicates = ty_generic_predicates_for_type_or_impl(ccx, generics);
if let ast::TypeImplItem(ref ty) = impl_item.node {
if opt_trait_ref.is_none() {
span_err!(tcx.sess, impl_item.span, E0202,
- "associated items are not allowed in inherent impls");
+ "associated types are not allowed in inherent impls");
}
- as_refsociated_type(ccx, ImplContainer(local_def(it.id)),
- impl_item.ident, impl_item.id, impl_item.vis);
-
let typ = ccx.icx(&ty_predicates).to_ty(&ExplicitRscope, ty);
- tcx.tcache.borrow_mut().insert(local_def(impl_item.id),
- TypeScheme {
- generics: ty::Generics::empty(),
- ty: typ,
- });
- tcx.predicates.borrow_mut().insert(local_def(impl_item.id),
- ty::GenericPredicates::empty());
- write_ty_to_tcx(tcx, impl_item.id, typ);
+
+ convert_associated_type(ccx, ImplContainer(local_def(it.id)),
+ impl_item.ident, impl_item.id, impl_item.vis,
+ Some(typ));
}
}
}
}
- if let Some(ref ast_trait_ref) = *opt_trait_ref {
- let trait_ref =
- astconv::instantiate_mono_trait_ref(&ccx.icx(&ty_predicates),
- &ExplicitRscope,
- ast_trait_ref,
- Some(selfty));
-
- tcx.impl_trait_refs.borrow_mut().insert(it.id, trait_ref);
+ if let &Some(ref ast_trait_ref) = opt_trait_ref {
+ tcx.impl_trait_refs.borrow_mut().insert(
+ local_def(it.id),
+ Some(astconv::instantiate_mono_trait_ref(&ccx.icx(&ty_predicates),
+ &ExplicitRscope,
+ ast_trait_ref,
+ Some(selfty)))
+ );
+ } else {
+ tcx.impl_trait_refs.borrow_mut().insert(local_def(it.id), None);
}
enforce_impl_params_are_constrained(tcx,
// Convert all the associated types.
for trait_item in trait_items {
match trait_item.node {
- ast::TypeTraitItem(..) => {
- as_refsociated_type(ccx, TraitContainer(local_def(it.id)),
- trait_item.ident, trait_item.id, ast::Public);
+ ast::TypeTraitItem(_, ref opt_ty) => {
+ let typ = opt_ty.as_ref().map({
+ |ty| ccx.icx(&trait_predicates).to_ty(&ExplicitRscope, &ty)
+ });
+
+ convert_associated_type(ccx, TraitContainer(local_def(it.id)),
+ trait_item.ident, trait_item.id, ast::Public,
+ typ);
}
_ => {}
}
{
let tcx = ccx.tcx;
- debug!("ensure_super_predicates_step(trait_def_id={})", trait_def_id.repr(tcx));
+ debug!("ensure_super_predicates_step(trait_def_id={:?})", trait_def_id);
if trait_def_id.krate != ast::LOCAL_CRATE {
// If this trait comes from an external crate, then all of the
// Convert the bounds that follow the colon, e.g. `Bar+Zed` in `trait Foo : Bar+Zed`.
let self_param_ty = ty::mk_self_type(tcx);
- let superbounds1 = compute_bounds(&ccx.icx(scope), self_param_ty, bounds,
- SizedByDefault::No, item.span);
- let superbounds1 = ty::predicates(tcx, self_param_ty, &superbounds1);
+ let superbounds1 = compute_bounds(&ccx.icx(scope),
+ self_param_ty,
+ bounds,
+ SizedByDefault::No,
+ item.span);
+
+ let superbounds1 = superbounds1.predicates(tcx, self_param_ty);
// Convert any explicit superbounds in the where clause,
// e.g. `trait Foo where Self : Bar`:
let superbounds2 = generics.get_type_parameter_bounds(&ccx.icx(scope), item.span, item.id);
// Combine the two lists to form the complete set of superbounds:
- let superbounds = superbounds1.into_iter().chain(superbounds2.into_iter()).collect();
+ let superbounds = superbounds1.into_iter().chain(superbounds2).collect();
let superpredicates = ty::GenericPredicates {
predicates: VecPerParamSpace::new(superbounds, vec![], vec![])
};
- debug!("superpredicates for trait {} = {}",
- local_def(item.id).repr(ccx.tcx),
- superpredicates.repr(ccx.tcx));
+ debug!("superpredicates for trait {:?} = {:?}",
+ local_def(item.id),
+ superpredicates);
tcx.super_predicates.borrow_mut().insert(trait_def_id, superpredicates.clone());
.map(|tr| tr.def_id())
.collect();
- debug!("ensure_super_predicates_step: def_ids={}", def_ids.repr(tcx));
+ debug!("ensure_super_predicates_step: def_ids={:?}", def_ids);
def_ids
}
SizedByDefault::Yes,
trait_item.span);
- ty::predicates(ccx.tcx, assoc_ty, &bounds).into_iter()
+ bounds.predicates(ccx.tcx, assoc_ty).into_iter()
}).collect()
}
}
let ty = ccx.icx(&()).to_ty(&ExplicitRscope, &**t);
ty::TypeScheme { ty: ty, generics: ty::Generics::empty() }
}
- ast::ItemFn(ref decl, unsafety, abi, ref generics, _) => {
+ ast::ItemFn(ref decl, unsafety, _, abi, ref generics, _) => {
let ty_generics = ty_generics_for_fn(ccx, generics, &ty::Generics::empty());
let tofd = astconv::ty_of_bare_fn(&ccx.icx(generics), unsafety, abi, &**decl);
let ty = ty::mk_bare_fn(tcx, Some(local_def(it.id)), tcx.mk_bare_fn(tofd));
ast::ItemStatic(..) | ast::ItemConst(..) => {
ty::GenericPredicates::empty()
}
- ast::ItemFn(_, _, _, ref ast_generics, _) => {
+ ast::ItemFn(_, _, _, _, ref ast_generics, _) => {
ty_generic_predicates_for_fn(ccx, ast_generics, &ty::GenericPredicates::empty())
}
ast::ItemTy(_, ref generics) => {
let object_lifetime_default_reprs: String =
scheme.generics.types.iter()
.map(|t| match t.object_lifetime_default {
- Some(ty::ObjectLifetimeDefault::Specific(r)) =>
- r.user_string(tcx),
- d =>
- d.repr(ccx.tcx),
+ ty::ObjectLifetimeDefault::Specific(r) => r.to_string(),
+ d => format!("{:?}", d),
})
.collect::<Vec<String>>()
.connect(",");
ast_generics: &ast::Generics)
-> ty::Generics<'tcx>
{
- debug!("ty_generics_for_trait(trait_id={}, substs={})",
- local_def(trait_id).repr(ccx.tcx), substs.repr(ccx.tcx));
+ debug!("ty_generics_for_trait(trait_id={:?}, substs={:?})",
+ local_def(trait_id), substs);
let mut generics = ty_generics_for_type_or_impl(ccx, ast_generics);
name: special_idents::type_self.name,
def_id: local_def(param_id),
default: None,
- object_lifetime_default: None,
+ object_lifetime_default: ty::ObjectLifetimeDefault::BaseDefault,
};
ccx.tcx.ty_param_defs.borrow_mut().insert(param_id, def.clone());
¶m.bounds,
SizedByDefault::Yes,
param.span);
- let predicates = ty::predicates(ccx.tcx, param_ty, &bounds);
+ let predicates = bounds.predicates(ccx.tcx, param_ty);
result.predicates.extend(space, predicates.into_iter());
}
&ExplicitRscope,
&*bound_pred.bounded_ty);
- for bound in &*bound_pred.bounds {
+ for bound in bound_pred.bounds.iter() {
match bound {
&ast::TyParamBound::TraitTyParamBound(ref poly_trait_ref, _) => {
let mut projections = Vec::new();
ty::walk_ty(ty, |t| {
match t.sty {
- ty::ty_param(p) => if p.idx > cur_idx {
+ ty::TyParam(p) => if p.idx > cur_idx {
span_err!(tcx.sess, path.span, E0128,
"type parameters with a default cannot use \
forward declared identifiers");
param_id: ast::NodeId,
param_bounds: &[ast::TyParamBound],
where_clause: &ast::WhereClause)
- -> Option<ty::ObjectLifetimeDefault>
+ -> ty::ObjectLifetimeDefault
{
let inline_bounds = from_bounds(ccx, param_bounds);
let where_bounds = from_predicates(ccx, param_id, &where_clause.predicates);
let all_bounds: HashSet<_> = inline_bounds.into_iter()
- .chain(where_bounds.into_iter())
+ .chain(where_bounds)
.collect();
return if all_bounds.len() > 1 {
- Some(ty::ObjectLifetimeDefault::Ambiguous)
+ ty::ObjectLifetimeDefault::Ambiguous
+ } else if all_bounds.len() == 0 {
+ ty::ObjectLifetimeDefault::BaseDefault
} else {
- all_bounds.into_iter()
- .next()
- .map(ty::ObjectLifetimeDefault::Specific)
+ ty::ObjectLifetimeDefault::Specific(
+ all_bounds.into_iter().next().unwrap())
};
fn from_bounds<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
ast_bounds: &[ast::TyParamBound],
sized_by_default: SizedByDefault,
span: Span)
- -> ty::ParamBounds<'tcx>
+ -> astconv::Bounds<'tcx>
{
- let mut param_bounds = conv_param_bounds(astconv,
- span,
- param_ty,
- ast_bounds);
+ let mut bounds =
+ conv_param_bounds(astconv,
+ span,
+ param_ty,
+ ast_bounds);
if let SizedByDefault::Yes = sized_by_default {
add_unsized_bound(astconv,
- &mut param_bounds.builtin_bounds,
+ &mut bounds.builtin_bounds,
ast_bounds,
span);
}
- param_bounds.trait_bounds.sort_by(|a,b| a.def_id().cmp(&b.def_id()));
+ bounds.trait_bounds.sort_by(|a,b| a.def_id().cmp(&b.def_id()));
- param_bounds
+ bounds
}
/// Converts a specific TyParamBound from the AST into a set of
let pred = conv_poly_trait_ref(astconv, param_ty, tr, &mut projections);
projections.into_iter()
.map(|p| p.as_predicate())
- .chain(Some(pred.as_predicate()).into_iter())
+ .chain(Some(pred.as_predicate()))
.collect()
}
ast::RegionTyParamBound(ref lifetime) => {
span: Span,
param_ty: ty::Ty<'tcx>,
ast_bounds: &[ast::TyParamBound])
- -> ty::ParamBounds<'tcx>
+ -> astconv::Bounds<'tcx>
{
let tcx = astconv.tcx();
let astconv::PartitionedBounds {
.map(|r| ast_region_to_region(tcx, r))
.collect();
- ty::ParamBounds {
+ astconv::Bounds {
region_bounds: region_bounds,
builtin_bounds: builtin_bounds,
trait_bounds: trait_bounds,
abi: abi::Abi)
-> ty::TypeScheme<'tcx>
{
- for i in decl.inputs.iter() {
+ for i in &decl.inputs {
match (*i).pat.node {
ast::PatIdent(_, _, _) => (),
ast::PatWild(ast::PatWildSingle) => (),
if let ast::SelfExplicit(ref ast_type, _) = explicit_self.node {
let typ = ccx.icx(&method_type.predicates).to_ty(rs, &**ast_type);
let base_type = match typ.sty {
- ty::ty_ptr(tm) | ty::ty_rptr(_, tm) => tm.ty,
- ty::ty_uniq(typ) => typ,
+ ty::TyRef(_, tm) => tm.ty,
+ ty::TyBox(typ) => typ,
_ => typ,
};
&ty::liberate_late_bound_regions(
tcx, body_scope, &ty::Binder(base_type)));
- debug!("required_type={} required_type_free={} \
- base_type={} base_type_free={}",
- required_type.repr(tcx),
- required_type_free.repr(tcx),
- base_type.repr(tcx),
- base_type_free.repr(tcx));
+ debug!("required_type={:?} required_type_free={:?} \
+ base_type={:?} base_type_free={:?}",
+ required_type,
+ required_type_free,
+ base_type,
+ base_type_free);
let infcx = infer::new_infer_ctxt(tcx);
drop(::require_same_types(tcx,
required_type_free,
|| {
format!("mismatched self type: expected `{}`",
- ppaux::ty_to_string(tcx, required_type))
+ required_type)
}));
- // We could conceviably add more free-reion relations here,
+ // We could conceviably add more free-region relations here,
// but since this code is just concerned with checking that
// the `&Self` types etc match up, it's not really necessary.
// It would just allow people to be more approximate in some
scope: region::DestructionScopeData,
value: &T)
-> T
- where T : TypeFoldable<'tcx> + Repr<'tcx>
+ where T : TypeFoldable<'tcx>
{
/*!
* Convert early-bound regions into free regions; normally this is done by
idx: index as u32,
name: ty_param.ident.name };
if !input_parameters.contains(&ctp::Parameter::Type(param_ty)) {
- report_unused_parameter(tcx, ty_param.span, "type", ¶m_ty.user_string(tcx));
+ report_unused_parameter(tcx, ty_param.span, "type", ¶m_ty.to_string());
}
}
let lifetimes_in_associated_types: HashSet<_> =
impl_items.iter()
- .filter_map(|item| match item.node {
- ast::TypeImplItem(..) => Some(ty::node_id_to_type(tcx, item.id)),
- ast::ConstImplItem(..) | ast::MethodImplItem(..) |
- ast::MacImplItem(..) => None,
+ .map(|item| ty::impl_or_trait_item(tcx, local_def(item.id)))
+ .filter_map(|item| match item {
+ ty::TypeTraitItem(ref assoc_ty) => assoc_ty.ty,
+ ty::ConstTraitItem(..) | ty::MethodTraitItem(..) => None
})
- .flat_map(|ty| ctp::parameters_for_type(ty).into_iter())
+ .flat_map(|ty| ctp::parameters_for_type(ty))
.filter_map(|p| match p {
ctp::Parameter::Type(_) => None,
ctp::Parameter::Region(r) => Some(r),
!input_parameters.contains(&ctp::Parameter::Region(region))
{
report_unused_parameter(tcx, lifetime_def.lifetime.span,
- "lifetime", ®ion.name.user_string(tcx));
+ "lifetime", ®ion.name.to_string());
}
}
Region(ty::EarlyBoundRegion),
}
+/// Returns the list of parameters that are constrained by the type `ty`
+/// - i.e. the value of each parameter in the list is uniquely determined
+/// by `ty` (see RFC 447).
pub fn parameters_for_type<'tcx>(ty: Ty<'tcx>) -> Vec<Parameter> {
- ty.walk()
- .flat_map(|ty| parameters_for_type_shallow(ty).into_iter())
- .collect()
+ let mut result = vec![];
+ ty::maybe_walk_ty(ty, |t| {
+ if let ty::TyProjection(..) = t.sty {
+ false // projections are not injective.
+ } else {
+ result.append(&mut parameters_for_type_shallow(t));
+ // non-projection type constructors are injective.
+ true
+ }
+ });
+ result
}
pub fn parameters_for_trait_ref<'tcx>(trait_ref: &ty::TraitRef<'tcx>) -> Vec<Parameter> {
let type_parameters =
trait_ref.substs.types.iter()
- .flat_map(|ty| parameters_for_type(ty).into_iter());
+ .flat_map(|ty| parameters_for_type(ty));
region_parameters.extend(type_parameters);
fn parameters_for_type_shallow<'tcx>(ty: Ty<'tcx>) -> Vec<Parameter> {
match ty.sty {
- ty::ty_param(ref d) =>
+ ty::TyParam(ref d) =>
vec![Parameter::Type(d.clone())],
- ty::ty_rptr(region, _) =>
+ ty::TyRef(region, _) =>
parameters_for_region(region).into_iter().collect(),
- ty::ty_struct(_, substs) |
- ty::ty_enum(_, substs) =>
+ ty::TyStruct(_, substs) |
+ ty::TyEnum(_, substs) =>
parameters_for_regions_in_substs(substs),
- ty::ty_trait(ref data) =>
+ ty::TyTrait(ref data) =>
parameters_for_regions_in_substs(&data.principal.skip_binder().substs),
_ =>
vec![],
register_long_diagnostics! {
+E0023: r##"
+A pattern used to match against an enum variant must provide a sub-pattern for
+each field of the enum variant. This error indicates that a pattern attempted to
+extract an incorrect number of fields from a variant.
+
+```
+enum Fruit {
+ Apple(String, String)
+ Pear(u32)
+}
+```
+
+Here the `Apple` variant has two fields, and should be matched against like so:
+
+```
+// Correct.
+match x {
+ Apple(a, b) => ...
+}
+```
+
+Matching with the wrong number of fields has no sensible interpretation:
+
+```
+// Incorrect.
+match x {
+ Apple(a) => ...,
+ Apple(a, b, c) => ...
+}
+```
+
+Check how many fields the enum was declared with and ensure that your pattern
+uses the same number.
+"##,
+
+E0024: r##"
+This error indicates that a pattern attempted to extract the fields of an enum
+variant with no fields. Here's a tiny example of this error:
+
+```
+// This enum has two variants.
+enum Number {
+ // This variant has no fields.
+ Zero,
+ // This variant has one field.
+ One(u32)
+}
+
+// Assuming x is a Number we can pattern match on its contents.
+match x {
+ Zero(inside) => ...,
+ One(inside) => ...
+}
+```
+
+The pattern match `Zero(inside)` is incorrect because the `Zero` variant
+contains no fields, yet the `inside` name attempts to bind the first field of
+the enum.
+"##,
+
+E0025: r##"
+Each field of a struct can only be bound once in a pattern. Each occurrence of a
+field name binds the value of that field, so to fix this error you will have to
+remove or alter the duplicate uses of the field name. Perhaps you misspelt
+another field name?
+"##,
+
+E0026: r##"
+This error indicates that a struct pattern attempted to extract a non-existant
+field from a struct. Struct fields are identified by the name used before the
+colon `:` so struct patterns should resemble the declaration of the struct type
+being matched.
+
+```
+// Correct matching.
+struct Thing {
+ x: u32,
+ y: u32
+}
+
+let thing = Thing { x: 1, y: 2 };
+match thing {
+ Thing { x: xfield, y: yfield } => ...
+}
+```
+
+If you are using shorthand field patterns but want to refer to the struct field
+by a different name, you should rename it explicitly.
+
+```
+// Change this:
+match thing {
+ Thing { x, z } => ...
+}
+
+// To this:
+match thing {
+ Thing { x, y: z } => ...
+}
+```
+"##,
+
+E0027: r##"
+This error indicates that a pattern for a struct fails to specify a sub-pattern
+for every one of the struct's fields. Ensure that each field from the struct's
+definition is mentioned in the pattern, or use `..` to ignore unwanted fields.
+
+For example:
+
+```
+struct Dog {
+ name: String,
+ age: u32
+}
+
+let d = Dog { name: "Rusty".to_string(), age: 8 };
+
+// This is incorrect.
+match d {
+ Dog { age: x } => ...
+}
+
+// This is correct (explicit).
+match d {
+ Dog { name: n, age: x } => ...
+}
+
+// This is also correct (ignore unused fields).
+match d {
+ Dog { age: x, .. } => ...
+}
+```
+"##,
+
+E0029: r##"
+In a match expression, only numbers and characters can be matched against a
+range. This is because the compiler checks that the range is non-empty at
+compile-time, and is unable to evaluate arbitrary comparison functions. If you
+want to capture values of an orderable type between two end-points, you can use
+a guard.
+
+```
+// The ordering relation for strings can't be evaluated at compile time,
+// so this doesn't work:
+match string {
+ "hello" ... "world" => ...
+ _ => ...
+}
+
+// This is a more general version, using a guard:
+match string {
+ s if s >= "hello" && s <= "world" => ...
+ _ => ...
+}
+```
+"##,
+
+E0030: r##"
+When matching against a range, the compiler verifies that the range is
+non-empty. Range patterns include both end-points, so this is equivalent to
+requiring the start of the range to be less than or equal to the end of the
+range.
+
+For example:
+
+```
+match 5u32 {
+ // This range is ok, albeit pointless.
+ 1 ... 1 => ...
+ // This range is empty, and the compiler can tell.
+ 1000 ... 5 => ...
+}
+```
+"##,
+
+E0033: r##"
+This error indicates that a pointer to a trait type cannot be implicitly
+dereferenced by a pattern. Every trait defines a type, but because the
+size of trait implementors isn't fixed, this type has no compile-time size.
+Therefore, all accesses to trait types must be through pointers. If you
+encounter this error you should try to avoid dereferencing the pointer.
+
+```
+let trait_obj: &SomeTrait = ...;
+
+// This tries to implicitly dereference to create an unsized local variable.
+let &invalid = trait_obj;
+
+// You can call methods without binding to the value being pointed at.
+trait_obj.method_one();
+trait_obj.method_two();
+```
+
+You can read more about trait objects in the Trait Object section of the
+Reference:
+
+http://doc.rust-lang.org/reference.html#trait-objects
+"##,
+
+E0034: r##"
+The compiler doesn't know what method to call because more than one method
+has the same prototype. Example:
+
+```
+struct Test;
+
+trait Trait1 {
+ fn foo();
+}
+
+trait Trait2 {
+ fn foo();
+}
+
+impl Trait1 for Test { fn foo() {} }
+impl Trait2 for Test { fn foo() {} }
+
+fn main() {
+ Test::foo() // error, which foo() to call?
+}
+```
+
+To avoid this error, you have to keep only one of them and remove the others.
+So let's take our example and fix it:
+
+```
+struct Test;
+
+trait Trait1 {
+ fn foo();
+}
+
+impl Trait1 for Test { fn foo() {} }
+
+fn main() {
+ Test::foo() // and now that's good!
+}
+```
+
+However, a better solution would be using fully explicit naming of type and
+trait:
+
+```
+struct Test;
+
+trait Trait1 {
+ fn foo();
+}
+
+trait Trait2 {
+ fn foo();
+}
+
+impl Trait1 for Test { fn foo() {} }
+impl Trait2 for Test { fn foo() {} }
+
+fn main() {
+ <Test as Trait1>::foo()
+}
+```
+"##,
+
+E0035: r##"
+You tried to give a type parameter where it wasn't needed. Bad example:
+
+```
+struct Test;
+
+impl Test {
+ fn method(&self) {}
+}
+
+fn main() {
+ let x = Test;
+
+ x.method::<i32>(); // Error: Test::method doesn't need type parameter!
+}
+```
+
+To fix this error, just remove the type parameter:
+
+```
+struct Test;
+
+impl Test {
+ fn method(&self) {}
+}
+
+fn main() {
+ let x = Test;
+
+ x.method(); // OK, we're good!
+}
+```
+"##,
+
+E0036: r##"
+This error occurrs when you pass too many or not enough type parameters to
+a method. Example:
+
+```
+struct Test;
+
+impl Test {
+ fn method<T>(&self, v: &[T]) -> usize {
+ v.len()
+ }
+}
+
+fn main() {
+ let x = Test;
+ let v = &[0i32];
+
+ x.method::<i32, i32>(v); // error: only one type parameter is expected!
+}
+```
+
+To fix it, just specify a correct number of type parameters:
+
+```
+struct Test;
+
+impl Test {
+ fn method<T>(&self, v: &[T]) -> usize {
+ v.len()
+ }
+}
+
+fn main() {
+ let x = Test;
+ let v = &[0i32];
+
+ x.method::<i32>(v); // OK, we're good!
+}
+```
+
+Please note on the last example that we could have called `method` like this:
+
+```
+x.method(v);
+```
+"##,
+
+E0040: r##"
+It is not allowed to manually call destructors in Rust. It is also not
+necessary to do this since `drop` is called automatically whenever a value goes
+out of scope.
+
+Here's an example of this error:
+
+```
+struct Foo {
+ x: i32,
+}
+
+impl Drop for Foo {
+ fn drop(&mut self) {
+ println!("kaboom");
+ }
+}
+
+fn main() {
+ let mut x = Foo { x: -7 };
+ x.drop(); // error: explicit use of destructor method
+}
+```
+"##,
+
+E0045: r##"
+Rust only supports variadic parameters for interoperability with C code in its
+FFI. As such, variadic parameters can only be used with functions which are
+using the C ABI. Examples of erroneous code:
+
+```
+extern "rust-call" { fn foo(x: u8, ...); }
+// or
+fn foo(x: u8, ...) {}
+```
+
+To fix such code, put them in an extern "C" block:
+
+```
+extern "C" fn foo (x: u8, ...);
+// or:
+extern "C" {
+ fn foo (x: u8, ...);
+}
+```
+"##,
+
E0046: r##"
When trying to make some type implement a trait `Foo`, you must, at minimum,
provide implementations for all of `Foo`'s required methods (meaning the
"##,
E0053: r##"
-For any given method of a trait, the mutabilities of the parameters must match
-between the trait definition and the implementation.
+The parameters of any trait method must match between a trait implementation
+and the trait definition.
-Here's an example where the mutability of the `self` parameter is wrong:
+Here are a couple examples of this error:
```
-trait Foo { fn foo(&self); }
+trait Foo {
+ fn foo(x: u16);
+ fn bar(&self);
+}
struct Bar;
impl Foo for Bar {
- // error, the signature should be `fn foo(&self)` instead
- fn foo(&mut self) { }
+ // error, expected u16, found i16
+ fn foo(x: i16) { }
+
+ // error, values differ in mutability
+ fn bar(&mut self) { }
}
+```
+"##,
+
+E0054: r##"
+It is not allowed to cast to a bool. If you are trying to cast a numeric type
+to a bool, you can compare it with zero instead:
-fn main() {}
```
+let x = 5;
-Here's another example, this time for a non-`self` parameter:
+// Ok
+let x_is_nonzero = x != 0;
+// Not allowed, won't compile
+let x_is_nonzero = x as bool;
```
-trait Foo { fn foo(x: &mut bool) -> bool; }
+"##,
-struct Bar;
+E0055: r##"
+During a method call, a value is automatically dereferenced as many times as
+needed to make the value's type match the method's receiver. The catch is that
+the compiler will only attempt to dereference a number of times up to the
+recursion limit (which can be set via the `recursion_limit` attribute).
-impl Foo for Bar {
- // error, the type of `x` should be `&mut bool` instead
- fn foo(x: &bool) -> bool { *x }
+For a somewhat artificial example:
+
+```
+#![recursion_limit="2"]
+
+struct Foo;
+
+impl Foo {
+ fn foo(&self) {}
+}
+
+fn main() {
+ let foo = Foo;
+ let ref_foo = &&Foo;
+
+ // error, reached the recursion limit while auto-dereferencing &&Foo
+ ref_foo.foo();
+}
+```
+
+One fix may be to increase the recursion limit. Note that it is possible to
+create an infinite recursion of dereferencing, in which case the only fix is to
+somehow break the recursion.
+"##,
+
+E0057: r##"
+When invoking closures or other implementations of the function traits `Fn`,
+`FnMut` or `FnOnce` using call notation, the number of parameters passed to the
+function must match its definition.
+
+An example using a closure:
+
+```
+let f = |x| x * 3;
+let a = f(); // invalid, too few parameters
+let b = f(4); // this works!
+let c = f(2, 3); // invalid, too many parameters
+```
+
+A generic function must be treated similarly:
+
+```
+fn foo<F: Fn()>(f: F) {
+ f(); // this is valid, but f(3) would not work
}
+```
+"##,
+
+E0059: r##"
+The built-in function traits are generic over a tuple of the function arguments.
+If one uses angle-bracket notation (`Fn<(T,), Output=U>`) instead of parentheses
+(`Fn(T) -> U`) to denote the function trait, the type parameter should be a
+tuple. Otherwise function call notation cannot be used and the trait will not be
+implemented by closures.
-fn main() {}
+The most likely source of this error is using angle-bracket notation without
+wrapping the function argument type into a tuple, for example:
+
+```
+fn foo<F: Fn<i32>>(f: F) -> F::Output { f(3) }
```
+It can be fixed by adjusting the trait bound like this:
+
+```
+fn foo<F: Fn<(i32,)>>(f: F) -> F::Output { f(3) }
+```
+Note that `(T,)` always denotes the type of a 1-tuple containing an element of
+type `T`. The comma is necessary for syntactic disambiguation.
"##,
-E0054: r##"
-It is not allowed to cast to a bool. If you are trying to cast a numeric type
-to a bool, you can compare it with zero instead:
+E0060: r##"
+External C functions are allowed to be variadic. However, a variadic function
+takes a minimum number of arguments. For example, consider C's variadic `printf`
+function:
```
-let x = 5;
+extern crate libc;
+use libc::{ c_char, c_int };
-// Ok
-let x_is_nonzero = x != 0;
+extern "C" {
+ fn printf(_: *const c_char, ...) -> c_int;
+}
+```
+
+Using this declaration, it must be called with at least one argument, so
+simply calling `printf()` is illegal. But the following uses are allowed:
-// Not allowed, won't compile
-let x_is_nonzero = x as bool;
```
+unsafe {
+ use std::ffi::CString;
+
+ printf(CString::new("test\n").unwrap().as_ptr());
+ printf(CString::new("number = %d\n").unwrap().as_ptr(), 3);
+ printf(CString::new("%d, %d\n").unwrap().as_ptr(), 10, 5);
+}
+```
+"##,
+
+E0061: r##"
+The number of arguments passed to a function must match the number of arguments
+specified in the function signature.
+
+For example, a function like
+
+```
+fn f(a: u16, b: &str) {}
+```
+
+must always be called with exactly two arguments, e.g. `f(2, "test")`.
+
+Note, that Rust does not have a notion of optional function arguments or
+variadic functions (except for its C-FFI).
"##,
E0062: r##"
E0063: r##"
This error indicates that during an attempt to build a struct or struct-like
-enum variant, one of the fields was not provided. Each field should be specified
-exactly once.
+enum variant, one of the fields was not provided. Each field should be
+specified exactly once.
"##,
E0066: r##"
"##,
E0067: r##"
-The left-hand side of an assignment operator must be an lvalue expression. An
-lvalue expression represents a memory location and includes item paths (ie,
-namespaced variables), dereferences, indexing expressions, and field references.
+The left-hand side of a compound assignment expression must be an lvalue
+expression. An lvalue expression represents a memory location and includes
+item paths (ie, namespaced variables), dereferences, indexing expressions,
+and field references.
+Let's start with some bad examples:
```
use std::collections::LinkedList;
-// Good
-let mut list = LinkedList::new();
-
-
// Bad: assignment to non-lvalue expression
LinkedList::new() += 1;
+
+// ...
+
+fn some_func(i: &mut i32) {
+ i += 12; // Error : '+=' operation cannot be applied on a reference !
+}
+
+And now some good examples:
+```
+let mut i : i32 = 0;
+
+i += 12; // Good !
+
+// ...
+
+fn some_func(i: &mut i32) {
+ *i += 12; // Good !
+}
+
```
"##,
function's return type and the value being returned.
"##,
+E0070: r##"
+The left-hand side of an assignment operator must be an lvalue expression. An
+lvalue expression represents a memory location and can be a variable (with
+optional namespacing), a dereference, an indexing expression or a field
+reference.
+
+More details can be found here:
+https://doc.rust-lang.org/reference.html#lvalues,-rvalues-and-temporaries
+
+Now, we can go further. Here are some bad examples:
+```
+struct SomeStruct {
+ x: i32,
+ y: i32
+}
+const SOME_CONST : i32 = 12;
+
+fn some_other_func() {}
+
+fn some_function() {
+ SOME_CONST = 14; // error : a constant value cannot be changed!
+ 1 = 3; // error : 1 isn't a valid lvalue!
+ some_other_func() = 4; // error : we can't assign value to a function!
+ SomeStruct.x = 12; // error : SomeStruct a structure name but it is used
+ // like a variable!
+}
+```
+
+And now let's give good examples:
+
+```
+struct SomeStruct {
+ x: i32,
+ y: i32
+}
+let mut s = SomeStruct {x: 0, y: 0};
+
+s.x = 3; // that's good !
+
+// ...
+
+fn some_func(x: &mut i32) {
+ *x = 12; // that's good !
+}
+```
+"##,
+
+E0072: r##"
+When defining a recursive struct or enum, any use of the type being defined
+from inside the definition must occur behind a pointer (like `Box` or `&`).
+This is because structs and enums must have a well-defined size, and without
+the pointer the size of the type would need to be unbounded.
+
+Consider the following erroneous definition of a type for a list of bytes:
+
+```
+// error, illegal recursive struct type
+struct ListNode {
+ head: u8,
+ tail: Option<ListNode>,
+}
+```
+
+This type cannot have a well-defined size, because it needs to be arbitrarily
+large (since we would be able to nest `ListNode`s to any depth). Specifically,
+
+```plain
+size of `ListNode` = 1 byte for `head`
+ + 1 byte for the discriminant of the `Option`
+ + size of `ListNode`
+```
+
+One way to fix this is by wrapping `ListNode` in a `Box`, like so:
+
+```
+struct ListNode {
+ head: u8,
+ tail: Option<Box<ListNode>>,
+}
+```
+
+This works because `Box` is a pointer, so its size is well-known.
+"##,
+
+E0073: r##"
+You cannot define a struct (or enum) `Foo` that requires an instance of `Foo`
+in order to make a new `Foo` value. This is because there would be no way a
+first instance of `Foo` could be made to initialize another instance!
+
+Here's an example of a struct that has this problem:
+
+```
+struct Foo { x: Box<Foo> } // error
+```
+
+One fix is to use `Option`, like so:
+
+```
+struct Foo { x: Option<Box<Foo>> }
+```
+
+Now it's possible to create at least one instance of `Foo`: `Foo { x: None }`.
+"##,
+
E0081: r##"
Enum discriminants are used to differentiate enum variants stored in memory.
This error indicates that the same value was used for two or more variants,
```
"##,
+E0087: r##"
+Too many type parameters were supplied for a function. For example:
+
+```
+fn foo<T>() {}
+
+fn main() {
+ foo::<f64, bool>(); // error, expected 1 parameter, found 2 parameters
+}
+```
+
+The number of supplied parameters much exactly match the number of defined type
+parameters.
+"##,
+
+E0089: r##"
+Not enough type parameters were supplied for a function. For example:
+
+```
+fn foo<T, U>() {}
+
+fn main() {
+ foo::<f64>(); // error, expected 2 parameters, found 1 parameter
+}
+```
+
+Note that if a function takes multiple type parameters but you want the compiler
+to infer some of them, you can use type placeholders:
+
+```
+fn foo<T, U>(x: T) {}
+
+fn main() {
+ let x: bool = true;
+ foo::<f64>(x); // error, expected 2 parameters, found 1 parameter
+ foo::<_, f64>(x); // same as `foo::<bool, f64>(x)`
+}
+```
+"##,
+
E0106: r##"
This error indicates that a lifetime is missing from a type. If it is an error
inside a function signature, the problem may be with failing to adhere to the
[iss15872]: https://github.com/rust-lang/rust/issues/15872
"##,
+E0116: r##"
+You can only define an inherent implementation for a type in the same crate
+where the type was defined. For example, an `impl` block as below is not allowed
+since `Vec` is defined in the standard library:
+
+```
+impl Vec<u8> { ... } // error
+```
+
+To fix this problem, you can do either of these things:
+
+ - define a trait that has the desired associated functions/types/constants and
+ implement the trait for the type in question
+ - define a new type wrapping the type and define an implementation on the new
+ type
+
+Note that using the `type` keyword does not work here because `type` only
+introduces a type alias:
+
+```
+type Bytes = Vec<u8>;
+
+impl Bytes { ... } // error, same as above
+```
+"##,
+
+E0121: r##"
+In order to be consistent with Rust's lack of global type inference, type
+placeholders are disallowed by design in item signatures.
+
+Examples of this error include:
+
+```
+fn foo() -> _ { 5 } // error, explicitly write out the return type instead
+
+static BAR: _ = "test"; // error, explicitly write out the type instead
+```
+"##,
+
E0131: r##"
It is not possible to define `main` with type parameters, or even with function
parameters. When `main` is present, it must take no arguments and return `()`.
diverging function (such as `panic!()`).
"##,
+E0178: r##"
+In types, the `+` type operator has low precedence, so it is often necessary
+to use parentheses.
+
+For example:
+
+```
+trait Foo {}
+
+struct Bar<'a> {
+ w: &'a Foo + Copy, // error, use &'a (Foo + Copy)
+ x: &'a Foo + 'a, // error, use &'a (Foo + 'a)
+ y: &'a mut Foo + 'a, // error, use &'a mut (Foo + 'a)
+ z: fn() -> Foo + 'a, // error, use fn() -> (Foo + 'a)
+}
+```
+
+More details can be found in [RFC 438].
+
+[RFC 438]: https://github.com/rust-lang/rfcs/pull/438
+"##,
+
E0184: r##"
Explicitly implementing both Drop and Copy for a type is currently disallowed.
This feature can make some sense in theory, but the current implementation is
[iss20126]: https://github.com/rust-lang/rust/issues/20126
"##,
+E0185: r##"
+An associated function for a trait was defined to be static, but an
+implementation of the trait declared the same function to be a method (i.e. to
+take a `self` parameter).
+
+Here's an example of this error:
+
+```
+trait Foo {
+ fn foo();
+}
+
+struct Bar;
+
+impl Foo for Bar {
+ // error, method `foo` has a `&self` declaration in the impl, but not in
+ // the trait
+ fn foo(&self) {}
+}
+"##,
+
+E0186: r##"
+An associated function for a trait was defined to be a method (i.e. to take a
+`self` parameter), but an implementation of the trait declared the same function
+to be static.
+
+Here's an example of this error:
+
+```
+trait Foo {
+ fn foo(&self);
+}
+
+struct Bar;
+
+impl Foo for Bar {
+ // error, method `foo` has a `&self` declaration in the trait, but not in
+ // the impl
+ fn foo() {}
+}
+"##,
+
+E0192: r##"
+Negative impls are only allowed for traits with default impls. For more
+information see the [opt-in builtin traits RFC](https://github.com/rust-lang/
+rfcs/blob/master/text/0019-opt-in-builtin-traits.md).
+"##,
+
E0197: r##"
Inherent implementations (one that do not implement a trait but provide
methods associated with a type) are always safe because they are not
"##,
E0201: r##"
-It is an error to define a method--a trait method or an inherent method--more
-than once.
+It is an error to define an associated function more than once.
-For example,
+For example:
```
struct Foo(u8);
impl Foo {
+ fn bar(&self) -> bool { self.0 > 5 }
+
+ // error: duplicate associated function
fn bar() {}
+}
+
+trait Baz {
+ fn baz(&self) -> bool;
+}
+
+impl Baz for Foo {
+ fn baz(&self) -> bool { true }
// error: duplicate method
- fn bar(&self) -> bool { self.0 > 5 }
+ fn baz(&self) -> bool { self.0 > 5 }
}
```
"##,
+E0202: r##"
+Inherent associated types were part of [RFC 195] but are not yet implemented.
+See [the tracking issue][iss8995] for the status of this implementation.
+
+[RFC 195]: https://github.com/rust-lang/rfcs/pull/195
+[iss8995]: https://github.com/rust-lang/rust/issues/8995
+"##,
+
E0204: r##"
An attempt to implement the `Copy` trait for a struct failed because one of the
fields does not implement `Copy`. To fix this, you must implement `Copy` for the
"##,
E0250: r##"
-This means there was an error while evaluating the expression for the length of
-a fixed-size array type.
+There was an error while evaluating the expression for the length of a fixed-
+size array type.
-Some examples of code that produces this error are:
+Some examples of this error are:
```
// divide by zero in the length expression
```
"##,
+E0318: r##"
+Default impls for a trait must be located in the same crate where the trait was
+defined. For more information see the [opt-in builtin traits RFC](https://github
+.com/rust-lang/rfcs/blob/master/text/0019-opt-in-builtin-traits.md).
+"##,
+
E0322: r##"
The `Sized` trait is a special trait built-in to the compiler for types with a
constant size known at compile-time. This trait is automatically implemented
explicitly implement it for a type.
"##,
+E0326: r##"
+The types of any associated constants in a trait implementation must match the
+types in the trait definition. This error indicates that there was a mismatch.
+
+Here's an example of this error:
+
+```
+trait Foo {
+ const BAR: bool;
+}
+
+struct Bar;
+
+impl Foo for Bar {
+ const BAR: u32 = 5; // error, expected bool, found u32
+}
+```
+"##,
+
E0368: r##"
This error indicates that a binary assignment operator like `+=` or `^=` was
-applied to the wrong types.
-
-A couple examples of this are as follows:
+applied to the wrong types. For example:
```
let mut x: u16 = 5;
to change this.
[RFC 953]: https://github.com/rust-lang/rfcs/pull/953
+"##,
+
+E0371: r##"
+When `Trait2` is a subtrait of `Trait1` (for example, when `Trait2` has a
+definition like `trait Trait2: Trait1 { ... }`), it is not allowed to implement
+`Trait1` for `Trait2`. This is because `Trait2` already implements `Trait1` by
+definition, so it is not useful to do this.
+
+Example:
+
+```
+trait Foo { fn foo(&self) { } }
+trait Bar: Foo { }
+trait Baz: Bar { }
+
+impl Bar for Baz { } // error, `Baz` implements `Bar` by definition
+impl Foo for Baz { } // error, `Baz` implements `Bar` which implements `Foo`
+impl Baz for Baz { } // error, `Baz` (trivially) implements `Baz`
+impl Baz for Bar { } // Note: This is OK
+```
+"##,
+
+E0372: r##"
+Trying to implement a trait for a trait object (as in `impl Trait1 for
+Trait2 { ... }`) does not work if the trait is not object-safe. Please see the
+[RFC 255] for more details on object safety rules.
+
+[RFC 255]: https://github.com/rust-lang/rfcs/pull/255
+"##,
+
+E0379: r##"
+Trait methods cannot be declared `const` by design. For more information, see
+[RFC 911].
+
+[RFC 911]: https://github.com/rust-lang/rfcs/pull/911
+"##,
+
+E0380: r##"
+Default impls are only allowed for traits with no methods or associated items.
+For more information see the [opt-in builtin traits RFC](https://github.com/rust
+-lang/rfcs/blob/master/text/0019-opt-in-builtin-traits.md).
"##
}
register_diagnostics! {
- E0023,
- E0024,
- E0025,
- E0026,
- E0027,
- E0029,
- E0030,
- E0031,
- E0033,
- E0034, // multiple applicable methods in scope
- E0035, // does not take type parameters
- E0036, // incorrect number of type parameters given for this method
- E0040, // explicit use of destructor method
E0044, // foreign items may not have type parameters
- E0045, // variadic function must have C calling convention
- E0055, // method has an incompatible type for trait
- E0057, // method has an incompatible type for trait
- E0059,
- E0060,
- E0061,
E0068,
- E0070,
E0071,
- E0072,
- E0073,
E0074,
E0075,
E0076,
E0077,
E0085,
E0086,
- E0087,
E0088,
- E0089,
E0090,
E0091,
E0092,
E0102,
E0103,
E0104,
- E0116,
E0117,
E0118,
E0119,
E0120,
- E0121,
E0122,
E0123,
E0124,
E0172,
E0173, // manual implementations of unboxed closure traits are experimental
E0174, // explicit use of unboxed closure methods are experimental
- E0178,
E0182,
E0183,
- E0185,
- E0186,
E0187, // can't infer the kind of the closure
- E0188, // types differ in mutability
- E0189, // can only cast a boxed pointer to a boxed object
- E0190, // can only cast a &-pointer to an &-object
+ E0188, // can not cast a immutable reference to a mutable pointer
+ E0189, // deprecated: can only cast a boxed pointer to a boxed object
+ E0190, // deprecated: can only cast a &-pointer to an &-object
E0191, // value of the associated type must be specified
- E0192, // negative imples are allowed just for `Send` and `Sync`
E0193, // cannot bound type where clause bounds may only be attached to types
// involving type parameters
E0194,
E0195, // lifetime parameters or bounds on method do not match the trait declaration
E0196, // cannot determine a type for this closure
- E0202, // associated items are not allowed in inherent impls
E0203, // type parameter has more than one relaxed default bound,
// and only one is supported
E0207, // type parameter is not constrained by the impl trait, self type, or predicate
E0219, // associated type defined in higher-ranked supertrait
E0220, // associated type not found for type parameter
E0221, // ambiguous associated type in bounds
- E0222, // variadic function must have C calling convention
+ //E0222, // Error code E0045 (variadic function must have C calling
+ // convention) duplicate
E0223, // ambiguous associated type
E0224, // at least one non-builtin train is required for an object type
E0225, // only the builtin traits can be used as closure or object bounds
E0246, // illegal recursive type
E0247, // found module name used as a type
E0248, // found value name used as a type
- E0318, // can't create default impls for traits outside their crates
E0319, // trait impls for defaulted traits allowed just for structs/enums
E0320, // recursive overflow during dropck
E0321, // extended coherence rules for defaulted traits violated
E0323, // implemented an associated const when another trait item expected
E0324, // implemented a method when another trait item expected
E0325, // implemented an associated type when another trait item expected
- E0326, // associated const implemented with different type from trait
E0327, // referred to method instead of constant in match pattern
E0328, // cannot implement Unsize explicitly
+ E0329, // associated const depends on type parameter or Self.
E0366, // dropck forbid specialization to concrete type or region
E0367, // dropck forbid specialization to predicate not in struct/enum
E0369, // binary operation `<op>` cannot be applied to types
- E0371, // impl Trait for Trait is illegal
- E0372, // impl Trait for Trait where Trait is not object safe
E0374, // the trait `CoerceUnsized` may only be implemented for a coercion
// between structures with one field being coerced, none found
E0375, // the trait `CoerceUnsized` may only be implemented for a coercion
// fields need coercions
E0376, // the trait `CoerceUnsized` may only be implemented for a coercion
// between structures
- E0377 // the trait `CoerceUnsized` may only be implemented for a coercion
+ E0377, // the trait `CoerceUnsized` may only be implemented for a coercion
// between structures with the same definition
+ E0390, // only a single inherent implementation marked with
+ // `#[lang = \"{}\"]` is allowed for the `{}` primitive
+ E0391, // unsupported cyclic reference between types/traits detected
+ E0392, // parameter `{}` is never used
+ E0393 // the type parameter `{}` must be explicitly specified in an object
+ // type because its default value `{}` references the type `Self`"
}
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
- html_favicon_url = "http://www.rust-lang.org/favicon.ico",
+ html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/")]
#![allow(non_camel_case_types)]
+#![feature(append)]
#![feature(box_patterns)]
#![feature(box_syntax)]
-#![feature(collections)]
-#![feature(core)]
+#![feature(drain)]
+#![feature(iter_cmp)]
+#![feature(iter_arith)]
#![feature(quote)]
+#![feature(ref_slice)]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
+#![feature(slice_extras)]
#![feature(staged_api)]
+#![feature(vec_push_all)]
#[macro_use] extern crate log;
#[macro_use] extern crate syntax;
use middle::infer;
use middle::subst;
use middle::ty::{self, Ty};
+use rustc::ast_map;
use session::config;
use util::common::time;
-use util::ppaux::Repr;
-use util::ppaux;
use syntax::codemap::Span;
use syntax::print::pprust::*;
-use syntax::{ast, ast_map, abi};
+use syntax::{ast, abi};
use syntax::ast_util::local_def;
use std::cell::RefCell;
// registered before they are used.
pub mod diagnostics;
-mod check;
+pub mod check;
mod rscope;
mod astconv;
-mod collect;
+pub mod collect;
mod constrained_type_params;
-mod coherence;
-mod variance;
+pub mod coherence;
+pub mod variance;
pub struct TypeAndSubsts<'tcx> {
pub substs: subst::Substs<'tcx>,
pub struct CrateCtxt<'a, 'tcx: 'a> {
// A mapping from method call sites to traits that have that method.
- trait_map: ty::TraitMap,
+ pub trait_map: ty::TraitMap,
/// A vector of every trait accessible in the whole crate
/// (i.e. including those from subcrates). This is used only for
/// error reporting, and so is lazily initialised and generally
/// shouldn't taint the common path (hence the RefCell).
- all_traits: RefCell<Option<check::method::AllTraitsVec>>,
- tcx: &'a ty::ctxt<'tcx>,
+ pub all_traits: RefCell<Option<check::method::AllTraitsVec>>,
+ pub tcx: &'a ty::ctxt<'tcx>,
}
// Functions that write types into the node type table
fn write_ty_to_tcx<'tcx>(tcx: &ty::ctxt<'tcx>, node_id: ast::NodeId, ty: Ty<'tcx>) {
- debug!("write_ty_to_tcx({}, {})", node_id, ppaux::ty_to_string(tcx, ty));
+ debug!("write_ty_to_tcx({}, {:?})", node_id, ty);
assert!(!ty::type_needs_infer(ty));
tcx.node_type_insert(node_id, ty);
}
node_id: ast::NodeId,
item_substs: ty::ItemSubsts<'tcx>) {
if !item_substs.is_noop() {
- debug!("write_substs_to_tcx({}, {})",
+ debug!("write_substs_to_tcx({}, {:?})",
node_id,
- item_substs.repr(tcx));
+ item_substs);
assert!(item_substs.substs.types.all(|t| !ty::type_needs_infer(*t)));
match result {
Ok(_) => true,
Err(ref terr) => {
- span_err!(tcx.sess, span, E0211,
- "{}: {}",
- msg(),
- ty::type_err_to_str(tcx,
- terr));
+ span_err!(tcx.sess, span, E0211, "{}: {}", msg(), terr);
ty::note_and_explain_type_err(tcx, terr, span);
false
}
let tcx = ccx.tcx;
let main_t = ty::node_id_to_type(tcx, main_id);
match main_t.sty {
- ty::ty_bare_fn(..) => {
+ ty::TyBareFn(..) => {
match tcx.map.find(main_id) {
Some(ast_map::NodeItem(it)) => {
match it.node {
- ast::ItemFn(_, _, _, ref ps, _)
+ ast::ItemFn(_, _, _, _, ref ps, _)
if ps.is_parameterized() => {
span_err!(ccx.tcx.sess, main_span, E0131,
"main function is not allowed to have type parameters");
require_same_types(tcx, None, false, main_span, main_t, se_ty,
|| {
format!("main function expects type: `{}`",
- ppaux::ty_to_string(ccx.tcx, se_ty))
+ se_ty)
});
}
_ => {
tcx.sess.span_bug(main_span,
- &format!("main has a non-function type: found \
- `{}`",
- ppaux::ty_to_string(tcx,
- main_t)));
+ &format!("main has a non-function type: found `{}`",
+ main_t));
}
}
}
let tcx = ccx.tcx;
let start_t = ty::node_id_to_type(tcx, start_id);
match start_t.sty {
- ty::ty_bare_fn(..) => {
+ ty::TyBareFn(..) => {
match tcx.map.find(start_id) {
Some(ast_map::NodeItem(it)) => {
match it.node {
- ast::ItemFn(_,_,_,ref ps,_)
+ ast::ItemFn(_,_,_,_,ref ps,_)
if ps.is_parameterized() => {
span_err!(tcx.sess, start_span, E0132,
"start function is not allowed to have type parameters");
require_same_types(tcx, None, false, start_span, start_t, se_ty,
|| {
format!("start function expects type: `{}`",
- ppaux::ty_to_string(ccx.tcx, se_ty))
+ se_ty)
});
}
_ => {
tcx.sess.span_bug(start_span,
- &format!("start has a non-function type: found \
- `{}`",
- ppaux::ty_to_string(tcx, start_t)));
+ &format!("start has a non-function type: found `{}`",
+ start_t));
}
}
}
tcx.sess.abort_if_errors();
}
-#[cfg(stage0)]
-__build_diagnostic_array! { DIAGNOSTICS }
-#[cfg(not(stage0))]
__build_diagnostic_array! { librustc_typeck, DIAGNOSTICS }
/// be derived from the object traits, what should we use? If
/// `None` is returned, an explicit annotation is required.
fn object_lifetime_default(&self, span: Span) -> Option<ty::Region>;
+
+ /// The "base" default is the initial default for a scope. This is
+ /// 'static except for in fn bodies, where it is a fresh inference
+ /// variable. You shouldn't call this except for as part of
+ /// computing `object_lifetime_default` (in particular, in legacy
+ /// modes, it may not be relevant).
+ fn base_object_lifetime_default(&self, span: Span) -> ty::Region;
+
+ /// Used to issue warnings in Rust 1.2, not needed after that.
+ /// True if the result of `object_lifetime_default` will change in 1.3.
+ fn object_lifetime_default_will_change_in_1_3(&self) -> bool {
+ false
+ }
+
+ /// Used to issue warnings in Rust 1.2, not needed after that.
+ /// True if the result of `base_object_lifetime_default` differs
+ /// from the result of `object_lifetime_default`.
+ fn base_object_lifetime_default_differs(&self) -> bool {
+ false
+ }
}
// A scope in which all regions must be explicitly named. This is used
pub struct ExplicitRscope;
impl RegionScope for ExplicitRscope {
- fn object_lifetime_default(&self, _span: Span) -> Option<ty::Region> {
- Some(ty::ReStatic)
- }
-
fn anon_regions(&self,
_span: Span,
_count: usize)
-> Result<Vec<ty::Region>, Option<Vec<(String, usize)>>> {
Err(None)
}
+
+ fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
+ Some(self.base_object_lifetime_default(span))
+ }
+
+ fn base_object_lifetime_default(&self, _span: Span) -> ty::Region {
+ ty::ReStatic
+ }
}
// Same as `ExplicitRscope`, but provides some extra information for diagnostics
}
impl RegionScope for UnelidableRscope {
- fn object_lifetime_default(&self, _span: Span) -> Option<ty::Region> {
- Some(ty::ReStatic)
- }
-
fn anon_regions(&self,
_span: Span,
_count: usize)
let UnelidableRscope(ref v) = *self;
Err(Some(v.clone()))
}
+
+ fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
+ Some(self.base_object_lifetime_default(span))
+ }
+
+ fn base_object_lifetime_default(&self, _span: Span) -> ty::Region {
+ ty::ReStatic
+ }
}
// A scope in which omitted anonymous region defaults to
}
impl RegionScope for ElidableRscope {
- fn object_lifetime_default(&self, _span: Span) -> Option<ty::Region> {
+ fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
// Per RFC #599, object-lifetimes default to 'static unless
// overridden by context, and this takes precedence over
// lifetime elision.
- Some(ty::ReStatic)
+ Some(self.base_object_lifetime_default(span))
+ }
+
+ fn base_object_lifetime_default(&self, _span: Span) -> ty::Region {
+ ty::ReStatic
}
fn anon_regions(&self,
}
impl RegionScope for BindingRscope {
- fn object_lifetime_default(&self, _span: Span) -> Option<ty::Region> {
+ fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
// Per RFC #599, object-lifetimes default to 'static unless
// overridden by context, and this takes precedence over the
- // binding defaults.
- Some(ty::ReStatic)
+ // binding defaults in a fn signature.
+ Some(self.base_object_lifetime_default(span))
+ }
+
+ fn base_object_lifetime_default(&self, _span: Span) -> ty::Region {
+ ty::ReStatic
}
fn anon_regions(&self,
/// A scope which overrides the default object lifetime but has no other effect.
pub struct ObjectLifetimeDefaultRscope<'r> {
base_scope: &'r (RegionScope+'r),
- default: Option<ty::ObjectLifetimeDefault>,
+ default: ty::ObjectLifetimeDefault,
}
impl<'r> ObjectLifetimeDefaultRscope<'r> {
pub fn new(base_scope: &'r (RegionScope+'r),
- default: Option<ty::ObjectLifetimeDefault>)
+ default: ty::ObjectLifetimeDefault)
-> ObjectLifetimeDefaultRscope<'r>
{
ObjectLifetimeDefaultRscope {
impl<'r> RegionScope for ObjectLifetimeDefaultRscope<'r> {
fn object_lifetime_default(&self, span: Span) -> Option<ty::Region> {
match self.default {
- None => self.base_scope.object_lifetime_default(span),
- Some(ty::ObjectLifetimeDefault::Ambiguous) => None,
- Some(ty::ObjectLifetimeDefault::Specific(r)) => Some(r),
+ ty::ObjectLifetimeDefault::Ambiguous =>
+ None,
+
+ ty::ObjectLifetimeDefault::BaseDefault =>
+ if false { // this will become the behavior in Rust 1.3
+ Some(self.base_object_lifetime_default(span))
+ } else {
+ self.base_scope.object_lifetime_default(span)
+ },
+
+ ty::ObjectLifetimeDefault::Specific(r) =>
+ Some(r),
+ }
+ }
+
+ fn base_object_lifetime_default(&self, span: Span) -> ty::Region {
+ assert!(false, "this code should not execute until Rust 1.3");
+ self.base_scope.base_object_lifetime_default(span)
+ }
+
+ fn object_lifetime_default_will_change_in_1_3(&self) -> bool {
+ debug!("object_lifetime_default_will_change_in_1_3: {:?}", self.default);
+
+ match self.default {
+ ty::ObjectLifetimeDefault::Ambiguous |
+ ty::ObjectLifetimeDefault::Specific(_) =>
+ false,
+
+ ty::ObjectLifetimeDefault::BaseDefault =>
+ self.base_scope.base_object_lifetime_default_differs()
+ }
+ }
+
+ fn base_object_lifetime_default_differs(&self) -> bool {
+ debug!("base_object_lifetime_default_differs: {:?}", self.default);
+
+ match self.default {
+ ty::ObjectLifetimeDefault::Ambiguous |
+ ty::ObjectLifetimeDefault::Specific(_) =>
+ true,
+
+ ty::ObjectLifetimeDefault::BaseDefault =>
+ self.base_scope.base_object_lifetime_default_differs(),
}
}
.map(|r| ty_fold::shift_region(r, 1))
}
+ fn base_object_lifetime_default(&self, span: Span) -> ty::Region {
+ ty_fold::shift_region(self.base_scope.base_object_lifetime_default(span), 1)
+ }
+
fn anon_regions(&self,
span: Span,
count: usize)
use middle::subst;
use middle::subst::{ParamSpace, FnSpace, TypeSpace, SelfSpace, VecPerParamSpace};
use middle::ty::{self, Ty};
+use rustc::ast_map;
use std::fmt;
use std::rc::Rc;
use syntax::ast;
-use syntax::ast_map;
use syntax::ast_util;
use syntax::visit;
use syntax::visit::Visitor;
use util::nodemap::NodeMap;
-use util::ppaux::Repr;
pub fn infer_variance(tcx: &ty::ctxt) {
let krate = tcx.map.krate();
impl<'a, 'tcx, 'v> Visitor<'v> for TermsContext<'a, 'tcx> {
fn visit_item(&mut self, item: &ast::Item) {
- debug!("add_inferreds for item {}", item.repr(self.tcx));
+ debug!("add_inferreds for item {}", self.tcx.map.node_to_string(item.id));
match item.node {
ast::ItemEnum(_, ref generics) |
let did = ast_util::local_def(item.id);
let tcx = self.terms_cx.tcx;
- debug!("visit_item item={}",
- item.repr(tcx));
+ debug!("visit_item item={}", tcx.map.node_to_string(item.id));
match item.node {
ast::ItemEnum(ref enum_definition, _) => {
generics: &ty::Generics<'tcx>,
trait_ref: ty::TraitRef<'tcx>,
variance: VarianceTermPtr<'a>) {
- debug!("add_constraints_from_trait_ref: trait_ref={} variance={:?}",
- trait_ref.repr(self.tcx()),
+ debug!("add_constraints_from_trait_ref: trait_ref={:?} variance={:?}",
+ trait_ref,
variance);
let trait_def = ty::lookup_trait_def(self.tcx(), trait_ref.def_id);
generics: &ty::Generics<'tcx>,
ty: Ty<'tcx>,
variance: VarianceTermPtr<'a>) {
- debug!("add_constraints_from_ty(ty={}, variance={:?})",
- ty.repr(self.tcx()),
+ debug!("add_constraints_from_ty(ty={:?}, variance={:?})",
+ ty,
variance);
match ty.sty {
- ty::ty_bool |
- ty::ty_char | ty::ty_int(_) | ty::ty_uint(_) |
- ty::ty_float(_) | ty::ty_str => {
+ ty::TyBool |
+ ty::TyChar | ty::TyInt(_) | ty::TyUint(_) |
+ ty::TyFloat(_) | ty::TyStr => {
/* leaf type -- noop */
}
- ty::ty_closure(..) => {
+ ty::TyClosure(..) => {
self.tcx().sess.bug("Unexpected closure type in variance computation");
}
- ty::ty_rptr(region, ref mt) => {
+ ty::TyRef(region, ref mt) => {
let contra = self.contravariant(variance);
self.add_constraints_from_region(generics, *region, contra);
self.add_constraints_from_mt(generics, mt, variance);
}
- ty::ty_uniq(typ) | ty::ty_vec(typ, _) => {
+ ty::TyBox(typ) | ty::TyArray(typ, _) | ty::TySlice(typ) => {
self.add_constraints_from_ty(generics, typ, variance);
}
- ty::ty_ptr(ref mt) => {
+ ty::TyRawPtr(ref mt) => {
self.add_constraints_from_mt(generics, mt, variance);
}
- ty::ty_tup(ref subtys) => {
+ ty::TyTuple(ref subtys) => {
for &subty in subtys {
self.add_constraints_from_ty(generics, subty, variance);
}
}
- ty::ty_enum(def_id, substs) |
- ty::ty_struct(def_id, substs) => {
+ ty::TyEnum(def_id, substs) |
+ ty::TyStruct(def_id, substs) => {
let item_type = ty::lookup_item_type(self.tcx(), def_id);
// All type parameters on enums and structs should be
variance);
}
- ty::ty_projection(ref data) => {
+ ty::TyProjection(ref data) => {
let trait_ref = &data.trait_ref;
let trait_def = ty::lookup_trait_def(self.tcx(), trait_ref.def_id);
self.add_constraints_from_substs(
variance);
}
- ty::ty_trait(ref data) => {
+ ty::TyTrait(ref data) => {
let poly_trait_ref =
data.principal_trait_ref_with_self_ty(self.tcx(),
self.tcx().types.err);
}
}
- ty::ty_param(ref data) => {
+ ty::TyParam(ref data) => {
let def_id = generics.types.get(data.space, data.idx as usize).def_id;
assert_eq!(def_id.krate, ast::LOCAL_CRATE);
match self.terms_cx.inferred_map.get(&def_id.node) {
}
}
- ty::ty_bare_fn(_, &ty::BareFnTy { ref sig, .. }) => {
+ ty::TyBareFn(_, &ty::BareFnTy { ref sig, .. }) => {
self.add_constraints_from_sig(generics, sig, variance);
}
- ty::ty_err => {
+ ty::TyError => {
// we encounter this when walking the trait references for object
- // types, where we use ty_err as the Self type
+ // types, where we use TyError as the Self type
}
- ty::ty_infer(..) => {
+ ty::TyInfer(..) => {
self.tcx().sess.bug(
&format!("unexpected type encountered in \
- variance inference: {}",
- ty.repr(self.tcx())));
+ variance inference: {}", ty));
}
}
}
region_param_defs: &[ty::RegionParameterDef],
substs: &subst::Substs<'tcx>,
variance: VarianceTermPtr<'a>) {
- debug!("add_constraints_from_substs(def_id={}, substs={}, variance={:?})",
- def_id.repr(self.tcx()),
- substs.repr(self.tcx()),
+ debug!("add_constraints_from_substs(def_id={:?}, substs={:?}, variance={:?})",
+ def_id,
+ substs,
variance);
for p in type_param_defs {
self.tcx()
.sess
.bug(&format!("unexpected region encountered in variance \
- inference: {}",
- region.repr(self.tcx())));
+ inference: {:?}",
+ region));
}
}
}
types: types,
regions: regions
};
- debug!("item_id={} item_variances={}",
+ debug!("item_id={} item_variances={:?}",
item_id,
- item_variances.repr(tcx));
+ item_variances);
let item_def_id = ast_util::local_def(item_id);
// For unit testing: check for a special "rustc_variance"
// attribute and report an error with various results if found.
if ty::has_attr(tcx, item_def_id, "rustc_variance") {
- let found = item_variances.repr(tcx);
- span_err!(tcx.sess, tcx.map.span(item_id), E0208, "{}", &found[..]);
+ span_err!(tcx.sess, tcx.map.span(item_id), E0208, "{:?}", item_variances);
}
let newly_added = tcx.item_variance_map.borrow_mut()
#![doc(primitive = "char")]
use core::char::CharExt as C;
-use core::option::Option::{self, Some};
+use core::option::Option::{self, Some, None};
use core::iter::Iterator;
use tables::{derived_property, property, general_category, conversions, charwidth};
/// the [`to_lowercase` method](../primitive.char.html#method.to_lowercase) on
/// characters.
#[stable(feature = "rust1", since = "1.0.0")]
-pub struct ToLowercase(Option<char>);
+pub struct ToLowercase(CaseMappingIter);
#[stable(feature = "rust1", since = "1.0.0")]
impl Iterator for ToLowercase {
type Item = char;
- fn next(&mut self) -> Option<char> { self.0.take() }
+ fn next(&mut self) -> Option<char> { self.0.next() }
}
/// An iterator over the uppercase mapping of a given character, returned from
/// the [`to_uppercase` method](../primitive.char.html#method.to_uppercase) on
/// characters.
#[stable(feature = "rust1", since = "1.0.0")]
-pub struct ToUppercase(Option<char>);
+pub struct ToUppercase(CaseMappingIter);
#[stable(feature = "rust1", since = "1.0.0")]
impl Iterator for ToUppercase {
type Item = char;
- fn next(&mut self) -> Option<char> { self.0.take() }
+ fn next(&mut self) -> Option<char> { self.0.next() }
+}
+
+/// An iterator over the titlecase mapping of a given character, returned from
+/// the [`to_titlecase` method](../primitive.char.html#method.to_titlecase) on
+/// characters.
+#[unstable(feature = "unicode", reason = "recently added")]
+pub struct ToTitlecase(CaseMappingIter);
+
+#[stable(feature = "unicode_case_mapping", since = "1.2.0")]
+impl Iterator for ToTitlecase {
+ type Item = char;
+ fn next(&mut self) -> Option<char> { self.0.next() }
+}
+
+
+enum CaseMappingIter {
+ Three(char, char, char),
+ Two(char, char),
+ One(char),
+ Zero
+}
+
+impl CaseMappingIter {
+ fn new(chars: [char; 3]) -> CaseMappingIter {
+ if chars[2] == '\0' {
+ if chars[1] == '\0' {
+ CaseMappingIter::One(chars[0]) // Including if chars[0] == '\0'
+ } else {
+ CaseMappingIter::Two(chars[0], chars[1])
+ }
+ } else {
+ CaseMappingIter::Three(chars[0], chars[1], chars[2])
+ }
+ }
+}
+
+impl Iterator for CaseMappingIter {
+ type Item = char;
+ fn next(&mut self) -> Option<char> {
+ match *self {
+ CaseMappingIter::Three(a, b, c) => {
+ *self = CaseMappingIter::Two(b, c);
+ Some(a)
+ }
+ CaseMappingIter::Two(b, c) => {
+ *self = CaseMappingIter::One(c);
+ Some(b)
+ }
+ CaseMappingIter::One(c) => {
+ *self = CaseMappingIter::Zero;
+ Some(c)
+ }
+ CaseMappingIter::Zero => None,
+ }
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
/// assert_eq!('f'.to_digit(16), Some(15));
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
pub fn to_digit(self, radix: u32) -> Option<u32> { C::to_digit(self, radix) }
/// Returns an iterator that yields the hexadecimal Unicode escape of a
/// # Examples
///
/// ```
- /// for i in '❤'.escape_unicode() {
- /// println!("{}", i);
+ /// for c in '❤'.escape_unicode() {
+ /// print!("{}", c);
/// }
+ /// println!("");
/// ```
///
/// This prints:
///
/// ```text
- /// \
- /// u
- /// {
- /// 2
- /// 7
- /// 6
- /// 4
- /// }
+ /// \u{2764}
/// ```
///
/// Collecting into a `String`:
/// assert_eq!(heart, r"\u{2764}");
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
pub fn escape_unicode(self) -> EscapeUnicode { C::escape_unicode(self) }
/// Returns an iterator that yields the 'default' ASCII and
/// assert_eq!(quote, "\\\"");
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
pub fn escape_default(self) -> EscapeDefault { C::escape_default(self) }
/// Returns the number of bytes this character would need if encoded in
/// assert_eq!(n, 2);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
pub fn len_utf8(self) -> usize { C::len_utf8(self) }
/// Returns the number of 16-bit code units this character would need if
/// assert_eq!(n, 1);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
pub fn len_utf16(self) -> usize { C::len_utf16(self) }
/// Encodes this character as UTF-8 into the provided byte buffer, and then
/// ```
#[unstable(feature = "unicode",
reason = "pending decision about Iterator/Writer/Reader")]
- pub fn encode_utf8(self, dst: &mut [u8]) -> Option<usize> { C::encode_utf8(self, dst) }
+ #[inline]
+ pub fn encode_utf8(self, dst: &mut [u8]) -> Option<usize> {
+ C::encode_utf8(self, dst)
+ }
/// Encodes this character as UTF-16 into the provided `u16` buffer, and
/// then returns the number of `u16`s written.
/// ```
#[unstable(feature = "unicode",
reason = "pending decision about Iterator/Writer/Reader")]
- pub fn encode_utf16(self, dst: &mut [u16]) -> Option<usize> { C::encode_utf16(self, dst) }
+ #[inline]
+ pub fn encode_utf16(self, dst: &mut [u16]) -> Option<usize> {
+ C::encode_utf16(self, dst)
+ }
/// Returns whether the specified character is considered a Unicode
/// alphabetic code point.
/// Converts a character to its lowercase equivalent.
///
- /// The case-folding performed is the common or simple mapping. See
- /// `to_uppercase()` for references and more information.
+ /// This performs complex unconditional mappings with no tailoring.
+ /// See `to_uppercase()` for references and more information.
///
/// # Return value
///
/// Returns an iterator which yields the characters corresponding to the
/// lowercase equivalent of the character. If no conversion is possible then
- /// the input character is returned.
+ /// an iterator with just the input character is returned.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// assert_eq!(Some('c'), 'C'.to_lowercase().next());
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn to_lowercase(self) -> ToLowercase {
- ToLowercase(Some(conversions::to_lower(self)))
+ ToLowercase(CaseMappingIter::new(conversions::to_lower(self)))
+ }
+
+ /// Converts a character to its titlecase equivalent.
+ ///
+ /// This performs complex unconditional mappings with no tailoring.
+ /// See `to_uppercase()` for references and more information.
+ ///
+ /// This differs from `to_uppercase()` since Unicode contains
+ /// digraphs and ligature characters.
+ /// For example, U+01F3 “dz” and U+FB01 “fi”
+ /// map to U+01F1 “DZ” and U+0046 U+0069 “Fi”, respectively.
+ ///
+ /// # Return value
+ ///
+ /// Returns an iterator which yields the characters corresponding to the
+ /// titlecase equivalent of the character. If no conversion is possible then
+ /// an iterator with just the input character is returned.
+ #[unstable(feature = "unicode", reason = "recently added")]
+ #[inline]
+ pub fn to_titlecase(self) -> ToTitlecase {
+ ToTitlecase(CaseMappingIter::new(conversions::to_title(self)))
}
/// Converts a character to its uppercase equivalent.
///
- /// The case-folding performed is the common or simple mapping: it maps
- /// one Unicode codepoint to its uppercase equivalent according to the
- /// Unicode database [1]. The additional [`SpecialCasing.txt`] is not yet
- /// considered here, but the iterator returned will soon support this form
- /// of case folding.
+ /// This performs complex unconditional mappings with no tailoring:
+ /// it maps one Unicode character to its uppercase equivalent
+ /// according to the Unicode database [1]
+ /// and the additional complex mappings [`SpecialCasing.txt`].
+ /// Conditional mappings (based on context or language) are not considerd here.
///
/// A full reference can be found here [2].
///
///
/// Returns an iterator which yields the characters corresponding to the
/// uppercase equivalent of the character. If no conversion is possible then
- /// the input character is returned.
+ /// an iterator with just the input character is returned.
///
/// [1]: ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.txt
///
- /// [`SpecialCasing`.txt`]: ftp://ftp.unicode.org/Public/UNIDATA/SpecialCasing.txt
+ /// [`SpecialCasing.txt`]: ftp://ftp.unicode.org/Public/UNIDATA/SpecialCasing.txt
+ ///
+ /// [2]: http://www.unicode.org/versions/Unicode7.0.0/ch03.pdf#G33992
///
- /// [2]: http://www.unicode.org/versions/Unicode4.0.0/ch03.pdf#G33992
+ /// # Examples
+ ///
+ /// ```
+ /// assert_eq!(Some('C'), 'c'.to_uppercase().next());
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn to_uppercase(self) -> ToUppercase {
- ToUppercase(Some(conversions::to_upper(self)))
+ ToUppercase(CaseMappingIter::new(conversions::to_upper(self)))
}
/// Returns this character's displayed width in columns, or `None` if it is a
since = "1.0.0")]
#[unstable(feature = "unicode",
reason = "needs expert opinion. is_cjk flag stands out as ugly")]
- pub fn width(self, is_cjk: bool) -> Option<usize> { charwidth::width(self, is_cjk) }
+ #[inline]
+ pub fn width(self, is_cjk: bool) -> Option<usize> {
+ charwidth::width(self, is_cjk)
+ }
}
#![cfg_attr(stage0, feature(custom_attribute))]
#![crate_name = "rustc_unicode"]
#![unstable(feature = "unicode")]
-#![feature(lang_items)]
-#![feature(staged_api)]
#![staged_api]
#![crate_type = "rlib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
- html_favicon_url = "http://www.rust-lang.org/favicon.ico",
+ html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/",
- html_playground_url = "http://play.rust-lang.org/")]
-#![feature(no_std)]
+ html_playground_url = "http://play.rust-lang.org/",
+ test(no_crate_inject))]
#![no_std]
+
#![feature(core)]
-#![doc(test(no_crate_inject))]
+#![feature(core_char_ext)]
+#![feature(core_prelude)]
+#![feature(core_slice_ext)]
+#![feature(core_str_ext)]
+#![feature(iter_arith)]
+#![feature(lang_items)]
+#![feature(no_std)]
+#![feature(staged_api)]
extern crate core;
pub use u_str::{utf8_char_width, is_utf16, Utf16Items, Utf16Item};
pub use u_str::{utf16_items, Utf16Encoder};
}
+
+// For use in libcollections, not re-exported in libstd.
+pub mod derived_property {
+ pub use tables::derived_property::{Cased, Case_Ignorable};
+}
pub mod general_category {
pub const Cc_table: &'static [(char, char)] = &[
- ('\u{0}', '\u{1f}'), ('\u{7f}', '\u{9f}')
+ ('\0', '\u{1f}'), ('\u{7f}', '\u{9f}')
];
pub fn Cc(c: char) -> bool {
super::bsearch_range_table(c, Alphabetic_table)
}
+ pub const Case_Ignorable_table: &'static [(char, char)] = &[
+ ('\u{27}', '\u{27}'), ('\u{2e}', '\u{2e}'), ('\u{3a}', '\u{3a}'), ('\u{5e}', '\u{5e}'),
+ ('\u{60}', '\u{60}'), ('\u{a8}', '\u{a8}'), ('\u{ad}', '\u{ad}'), ('\u{af}', '\u{af}'),
+ ('\u{b4}', '\u{b4}'), ('\u{b7}', '\u{b8}'), ('\u{2b0}', '\u{36f}'), ('\u{374}', '\u{375}'),
+ ('\u{37a}', '\u{37a}'), ('\u{384}', '\u{385}'), ('\u{387}', '\u{387}'), ('\u{483}',
+ '\u{489}'), ('\u{559}', '\u{559}'), ('\u{591}', '\u{5bd}'), ('\u{5bf}', '\u{5bf}'),
+ ('\u{5c1}', '\u{5c2}'), ('\u{5c4}', '\u{5c5}'), ('\u{5c7}', '\u{5c7}'), ('\u{5f4}',
+ '\u{5f4}'), ('\u{600}', '\u{605}'), ('\u{610}', '\u{61a}'), ('\u{61c}', '\u{61c}'),
+ ('\u{640}', '\u{640}'), ('\u{64b}', '\u{65f}'), ('\u{670}', '\u{670}'), ('\u{6d6}',
+ '\u{6dd}'), ('\u{6df}', '\u{6e8}'), ('\u{6ea}', '\u{6ed}'), ('\u{70f}', '\u{70f}'),
+ ('\u{711}', '\u{711}'), ('\u{730}', '\u{74a}'), ('\u{7a6}', '\u{7b0}'), ('\u{7eb}',
+ '\u{7f5}'), ('\u{7fa}', '\u{7fa}'), ('\u{816}', '\u{82d}'), ('\u{859}', '\u{85b}'),
+ ('\u{8e4}', '\u{902}'), ('\u{93a}', '\u{93a}'), ('\u{93c}', '\u{93c}'), ('\u{941}',
+ '\u{948}'), ('\u{94d}', '\u{94d}'), ('\u{951}', '\u{957}'), ('\u{962}', '\u{963}'),
+ ('\u{971}', '\u{971}'), ('\u{981}', '\u{981}'), ('\u{9bc}', '\u{9bc}'), ('\u{9c1}',
+ '\u{9c4}'), ('\u{9cd}', '\u{9cd}'), ('\u{9e2}', '\u{9e3}'), ('\u{a01}', '\u{a02}'),
+ ('\u{a3c}', '\u{a3c}'), ('\u{a41}', '\u{a42}'), ('\u{a47}', '\u{a48}'), ('\u{a4b}',
+ '\u{a4d}'), ('\u{a51}', '\u{a51}'), ('\u{a70}', '\u{a71}'), ('\u{a75}', '\u{a75}'),
+ ('\u{a81}', '\u{a82}'), ('\u{abc}', '\u{abc}'), ('\u{ac1}', '\u{ac5}'), ('\u{ac7}',
+ '\u{ac8}'), ('\u{acd}', '\u{acd}'), ('\u{ae2}', '\u{ae3}'), ('\u{b01}', '\u{b01}'),
+ ('\u{b3c}', '\u{b3c}'), ('\u{b3f}', '\u{b3f}'), ('\u{b41}', '\u{b44}'), ('\u{b4d}',
+ '\u{b4d}'), ('\u{b56}', '\u{b56}'), ('\u{b62}', '\u{b63}'), ('\u{b82}', '\u{b82}'),
+ ('\u{bc0}', '\u{bc0}'), ('\u{bcd}', '\u{bcd}'), ('\u{c00}', '\u{c00}'), ('\u{c3e}',
+ '\u{c40}'), ('\u{c46}', '\u{c48}'), ('\u{c4a}', '\u{c4d}'), ('\u{c55}', '\u{c56}'),
+ ('\u{c62}', '\u{c63}'), ('\u{c81}', '\u{c81}'), ('\u{cbc}', '\u{cbc}'), ('\u{cbf}',
+ '\u{cbf}'), ('\u{cc6}', '\u{cc6}'), ('\u{ccc}', '\u{ccd}'), ('\u{ce2}', '\u{ce3}'),
+ ('\u{d01}', '\u{d01}'), ('\u{d41}', '\u{d44}'), ('\u{d4d}', '\u{d4d}'), ('\u{d62}',
+ '\u{d63}'), ('\u{dca}', '\u{dca}'), ('\u{dd2}', '\u{dd4}'), ('\u{dd6}', '\u{dd6}'),
+ ('\u{e31}', '\u{e31}'), ('\u{e34}', '\u{e3a}'), ('\u{e46}', '\u{e4e}'), ('\u{eb1}',
+ '\u{eb1}'), ('\u{eb4}', '\u{eb9}'), ('\u{ebb}', '\u{ebc}'), ('\u{ec6}', '\u{ec6}'),
+ ('\u{ec8}', '\u{ecd}'), ('\u{f18}', '\u{f19}'), ('\u{f35}', '\u{f35}'), ('\u{f37}',
+ '\u{f37}'), ('\u{f39}', '\u{f39}'), ('\u{f71}', '\u{f7e}'), ('\u{f80}', '\u{f84}'),
+ ('\u{f86}', '\u{f87}'), ('\u{f8d}', '\u{f97}'), ('\u{f99}', '\u{fbc}'), ('\u{fc6}',
+ '\u{fc6}'), ('\u{102d}', '\u{1030}'), ('\u{1032}', '\u{1037}'), ('\u{1039}', '\u{103a}'),
+ ('\u{103d}', '\u{103e}'), ('\u{1058}', '\u{1059}'), ('\u{105e}', '\u{1060}'), ('\u{1071}',
+ '\u{1074}'), ('\u{1082}', '\u{1082}'), ('\u{1085}', '\u{1086}'), ('\u{108d}', '\u{108d}'),
+ ('\u{109d}', '\u{109d}'), ('\u{10fc}', '\u{10fc}'), ('\u{135d}', '\u{135f}'), ('\u{1712}',
+ '\u{1714}'), ('\u{1732}', '\u{1734}'), ('\u{1752}', '\u{1753}'), ('\u{1772}', '\u{1773}'),
+ ('\u{17b4}', '\u{17b5}'), ('\u{17b7}', '\u{17bd}'), ('\u{17c6}', '\u{17c6}'), ('\u{17c9}',
+ '\u{17d3}'), ('\u{17d7}', '\u{17d7}'), ('\u{17dd}', '\u{17dd}'), ('\u{180b}', '\u{180e}'),
+ ('\u{1843}', '\u{1843}'), ('\u{18a9}', '\u{18a9}'), ('\u{1920}', '\u{1922}'), ('\u{1927}',
+ '\u{1928}'), ('\u{1932}', '\u{1932}'), ('\u{1939}', '\u{193b}'), ('\u{1a17}', '\u{1a18}'),
+ ('\u{1a1b}', '\u{1a1b}'), ('\u{1a56}', '\u{1a56}'), ('\u{1a58}', '\u{1a5e}'), ('\u{1a60}',
+ '\u{1a60}'), ('\u{1a62}', '\u{1a62}'), ('\u{1a65}', '\u{1a6c}'), ('\u{1a73}', '\u{1a7c}'),
+ ('\u{1a7f}', '\u{1a7f}'), ('\u{1aa7}', '\u{1aa7}'), ('\u{1ab0}', '\u{1abe}'), ('\u{1b00}',
+ '\u{1b03}'), ('\u{1b34}', '\u{1b34}'), ('\u{1b36}', '\u{1b3a}'), ('\u{1b3c}', '\u{1b3c}'),
+ ('\u{1b42}', '\u{1b42}'), ('\u{1b6b}', '\u{1b73}'), ('\u{1b80}', '\u{1b81}'), ('\u{1ba2}',
+ '\u{1ba5}'), ('\u{1ba8}', '\u{1ba9}'), ('\u{1bab}', '\u{1bad}'), ('\u{1be6}', '\u{1be6}'),
+ ('\u{1be8}', '\u{1be9}'), ('\u{1bed}', '\u{1bed}'), ('\u{1bef}', '\u{1bf1}'), ('\u{1c2c}',
+ '\u{1c33}'), ('\u{1c36}', '\u{1c37}'), ('\u{1c78}', '\u{1c7d}'), ('\u{1cd0}', '\u{1cd2}'),
+ ('\u{1cd4}', '\u{1ce0}'), ('\u{1ce2}', '\u{1ce8}'), ('\u{1ced}', '\u{1ced}'), ('\u{1cf4}',
+ '\u{1cf4}'), ('\u{1cf8}', '\u{1cf9}'), ('\u{1d2c}', '\u{1d6a}'), ('\u{1d78}', '\u{1d78}'),
+ ('\u{1d9b}', '\u{1df5}'), ('\u{1dfc}', '\u{1dff}'), ('\u{1fbd}', '\u{1fbd}'), ('\u{1fbf}',
+ '\u{1fc1}'), ('\u{1fcd}', '\u{1fcf}'), ('\u{1fdd}', '\u{1fdf}'), ('\u{1fed}', '\u{1fef}'),
+ ('\u{1ffd}', '\u{1ffe}'), ('\u{200b}', '\u{200f}'), ('\u{2018}', '\u{2019}'), ('\u{2024}',
+ '\u{2024}'), ('\u{2027}', '\u{2027}'), ('\u{202a}', '\u{202e}'), ('\u{2060}', '\u{2064}'),
+ ('\u{2066}', '\u{206f}'), ('\u{2071}', '\u{2071}'), ('\u{207f}', '\u{207f}'), ('\u{2090}',
+ '\u{209c}'), ('\u{20d0}', '\u{20f0}'), ('\u{2c7c}', '\u{2c7d}'), ('\u{2cef}', '\u{2cf1}'),
+ ('\u{2d6f}', '\u{2d6f}'), ('\u{2d7f}', '\u{2d7f}'), ('\u{2de0}', '\u{2dff}'), ('\u{2e2f}',
+ '\u{2e2f}'), ('\u{3005}', '\u{3005}'), ('\u{302a}', '\u{302d}'), ('\u{3031}', '\u{3035}'),
+ ('\u{303b}', '\u{303b}'), ('\u{3099}', '\u{309e}'), ('\u{30fc}', '\u{30fe}'), ('\u{a015}',
+ '\u{a015}'), ('\u{a4f8}', '\u{a4fd}'), ('\u{a60c}', '\u{a60c}'), ('\u{a66f}', '\u{a672}'),
+ ('\u{a674}', '\u{a67d}'), ('\u{a67f}', '\u{a67f}'), ('\u{a69c}', '\u{a69d}'), ('\u{a69f}',
+ '\u{a69f}'), ('\u{a6f0}', '\u{a6f1}'), ('\u{a700}', '\u{a721}'), ('\u{a770}', '\u{a770}'),
+ ('\u{a788}', '\u{a78a}'), ('\u{a7f8}', '\u{a7f9}'), ('\u{a802}', '\u{a802}'), ('\u{a806}',
+ '\u{a806}'), ('\u{a80b}', '\u{a80b}'), ('\u{a825}', '\u{a826}'), ('\u{a8c4}', '\u{a8c4}'),
+ ('\u{a8e0}', '\u{a8f1}'), ('\u{a926}', '\u{a92d}'), ('\u{a947}', '\u{a951}'), ('\u{a980}',
+ '\u{a982}'), ('\u{a9b3}', '\u{a9b3}'), ('\u{a9b6}', '\u{a9b9}'), ('\u{a9bc}', '\u{a9bc}'),
+ ('\u{a9cf}', '\u{a9cf}'), ('\u{a9e5}', '\u{a9e6}'), ('\u{aa29}', '\u{aa2e}'), ('\u{aa31}',
+ '\u{aa32}'), ('\u{aa35}', '\u{aa36}'), ('\u{aa43}', '\u{aa43}'), ('\u{aa4c}', '\u{aa4c}'),
+ ('\u{aa70}', '\u{aa70}'), ('\u{aa7c}', '\u{aa7c}'), ('\u{aab0}', '\u{aab0}'), ('\u{aab2}',
+ '\u{aab4}'), ('\u{aab7}', '\u{aab8}'), ('\u{aabe}', '\u{aabf}'), ('\u{aac1}', '\u{aac1}'),
+ ('\u{aadd}', '\u{aadd}'), ('\u{aaec}', '\u{aaed}'), ('\u{aaf3}', '\u{aaf4}'), ('\u{aaf6}',
+ '\u{aaf6}'), ('\u{ab5b}', '\u{ab5f}'), ('\u{abe5}', '\u{abe5}'), ('\u{abe8}', '\u{abe8}'),
+ ('\u{abed}', '\u{abed}'), ('\u{fb1e}', '\u{fb1e}'), ('\u{fbb2}', '\u{fbc1}'), ('\u{fe00}',
+ '\u{fe0f}'), ('\u{fe13}', '\u{fe13}'), ('\u{fe20}', '\u{fe2d}'), ('\u{fe52}', '\u{fe52}'),
+ ('\u{fe55}', '\u{fe55}'), ('\u{feff}', '\u{feff}'), ('\u{ff07}', '\u{ff07}'), ('\u{ff0e}',
+ '\u{ff0e}'), ('\u{ff1a}', '\u{ff1a}'), ('\u{ff3e}', '\u{ff3e}'), ('\u{ff40}', '\u{ff40}'),
+ ('\u{ff70}', '\u{ff70}'), ('\u{ff9e}', '\u{ff9f}'), ('\u{ffe3}', '\u{ffe3}'), ('\u{fff9}',
+ '\u{fffb}'), ('\u{101fd}', '\u{101fd}'), ('\u{102e0}', '\u{102e0}'), ('\u{10376}',
+ '\u{1037a}'), ('\u{10a01}', '\u{10a03}'), ('\u{10a05}', '\u{10a06}'), ('\u{10a0c}',
+ '\u{10a0f}'), ('\u{10a38}', '\u{10a3a}'), ('\u{10a3f}', '\u{10a3f}'), ('\u{10ae5}',
+ '\u{10ae6}'), ('\u{11001}', '\u{11001}'), ('\u{11038}', '\u{11046}'), ('\u{1107f}',
+ '\u{11081}'), ('\u{110b3}', '\u{110b6}'), ('\u{110b9}', '\u{110ba}'), ('\u{110bd}',
+ '\u{110bd}'), ('\u{11100}', '\u{11102}'), ('\u{11127}', '\u{1112b}'), ('\u{1112d}',
+ '\u{11134}'), ('\u{11173}', '\u{11173}'), ('\u{11180}', '\u{11181}'), ('\u{111b6}',
+ '\u{111be}'), ('\u{1122f}', '\u{11231}'), ('\u{11234}', '\u{11234}'), ('\u{11236}',
+ '\u{11237}'), ('\u{112df}', '\u{112df}'), ('\u{112e3}', '\u{112ea}'), ('\u{11301}',
+ '\u{11301}'), ('\u{1133c}', '\u{1133c}'), ('\u{11340}', '\u{11340}'), ('\u{11366}',
+ '\u{1136c}'), ('\u{11370}', '\u{11374}'), ('\u{114b3}', '\u{114b8}'), ('\u{114ba}',
+ '\u{114ba}'), ('\u{114bf}', '\u{114c0}'), ('\u{114c2}', '\u{114c3}'), ('\u{115b2}',
+ '\u{115b5}'), ('\u{115bc}', '\u{115bd}'), ('\u{115bf}', '\u{115c0}'), ('\u{11633}',
+ '\u{1163a}'), ('\u{1163d}', '\u{1163d}'), ('\u{1163f}', '\u{11640}'), ('\u{116ab}',
+ '\u{116ab}'), ('\u{116ad}', '\u{116ad}'), ('\u{116b0}', '\u{116b5}'), ('\u{116b7}',
+ '\u{116b7}'), ('\u{16af0}', '\u{16af4}'), ('\u{16b30}', '\u{16b36}'), ('\u{16b40}',
+ '\u{16b43}'), ('\u{16f8f}', '\u{16f9f}'), ('\u{1bc9d}', '\u{1bc9e}'), ('\u{1bca0}',
+ '\u{1bca3}'), ('\u{1d167}', '\u{1d169}'), ('\u{1d173}', '\u{1d182}'), ('\u{1d185}',
+ '\u{1d18b}'), ('\u{1d1aa}', '\u{1d1ad}'), ('\u{1d242}', '\u{1d244}'), ('\u{1e8d0}',
+ '\u{1e8d6}'), ('\u{e0001}', '\u{e0001}'), ('\u{e0020}', '\u{e007f}'), ('\u{e0100}',
+ '\u{e01ef}')
+ ];
+
+ pub fn Case_Ignorable(c: char) -> bool {
+ super::bsearch_range_table(c, Case_Ignorable_table)
+ }
+
+ pub const Cased_table: &'static [(char, char)] = &[
+ ('\u{41}', '\u{5a}'), ('\u{61}', '\u{7a}'), ('\u{aa}', '\u{aa}'), ('\u{b5}', '\u{b5}'),
+ ('\u{ba}', '\u{ba}'), ('\u{c0}', '\u{d6}'), ('\u{d8}', '\u{f6}'), ('\u{f8}', '\u{1ba}'),
+ ('\u{1bc}', '\u{1bf}'), ('\u{1c4}', '\u{293}'), ('\u{295}', '\u{2b8}'), ('\u{2c0}',
+ '\u{2c1}'), ('\u{2e0}', '\u{2e4}'), ('\u{345}', '\u{345}'), ('\u{370}', '\u{373}'),
+ ('\u{376}', '\u{377}'), ('\u{37a}', '\u{37d}'), ('\u{37f}', '\u{37f}'), ('\u{386}',
+ '\u{386}'), ('\u{388}', '\u{38a}'), ('\u{38c}', '\u{38c}'), ('\u{38e}', '\u{3a1}'),
+ ('\u{3a3}', '\u{3f5}'), ('\u{3f7}', '\u{481}'), ('\u{48a}', '\u{52f}'), ('\u{531}',
+ '\u{556}'), ('\u{561}', '\u{587}'), ('\u{10a0}', '\u{10c5}'), ('\u{10c7}', '\u{10c7}'),
+ ('\u{10cd}', '\u{10cd}'), ('\u{1d00}', '\u{1dbf}'), ('\u{1e00}', '\u{1f15}'), ('\u{1f18}',
+ '\u{1f1d}'), ('\u{1f20}', '\u{1f45}'), ('\u{1f48}', '\u{1f4d}'), ('\u{1f50}', '\u{1f57}'),
+ ('\u{1f59}', '\u{1f59}'), ('\u{1f5b}', '\u{1f5b}'), ('\u{1f5d}', '\u{1f5d}'), ('\u{1f5f}',
+ '\u{1f7d}'), ('\u{1f80}', '\u{1fb4}'), ('\u{1fb6}', '\u{1fbc}'), ('\u{1fbe}', '\u{1fbe}'),
+ ('\u{1fc2}', '\u{1fc4}'), ('\u{1fc6}', '\u{1fcc}'), ('\u{1fd0}', '\u{1fd3}'), ('\u{1fd6}',
+ '\u{1fdb}'), ('\u{1fe0}', '\u{1fec}'), ('\u{1ff2}', '\u{1ff4}'), ('\u{1ff6}', '\u{1ffc}'),
+ ('\u{2071}', '\u{2071}'), ('\u{207f}', '\u{207f}'), ('\u{2090}', '\u{209c}'), ('\u{2102}',
+ '\u{2102}'), ('\u{2107}', '\u{2107}'), ('\u{210a}', '\u{2113}'), ('\u{2115}', '\u{2115}'),
+ ('\u{2119}', '\u{211d}'), ('\u{2124}', '\u{2124}'), ('\u{2126}', '\u{2126}'), ('\u{2128}',
+ '\u{2128}'), ('\u{212a}', '\u{212d}'), ('\u{212f}', '\u{2134}'), ('\u{2139}', '\u{2139}'),
+ ('\u{213c}', '\u{213f}'), ('\u{2145}', '\u{2149}'), ('\u{214e}', '\u{214e}'), ('\u{2160}',
+ '\u{217f}'), ('\u{2183}', '\u{2184}'), ('\u{24b6}', '\u{24e9}'), ('\u{2c00}', '\u{2c2e}'),
+ ('\u{2c30}', '\u{2c5e}'), ('\u{2c60}', '\u{2ce4}'), ('\u{2ceb}', '\u{2cee}'), ('\u{2cf2}',
+ '\u{2cf3}'), ('\u{2d00}', '\u{2d25}'), ('\u{2d27}', '\u{2d27}'), ('\u{2d2d}', '\u{2d2d}'),
+ ('\u{a640}', '\u{a66d}'), ('\u{a680}', '\u{a69d}'), ('\u{a722}', '\u{a787}'), ('\u{a78b}',
+ '\u{a78e}'), ('\u{a790}', '\u{a7ad}'), ('\u{a7b0}', '\u{a7b1}'), ('\u{a7f8}', '\u{a7fa}'),
+ ('\u{ab30}', '\u{ab5a}'), ('\u{ab5c}', '\u{ab5f}'), ('\u{ab64}', '\u{ab65}'), ('\u{fb00}',
+ '\u{fb06}'), ('\u{fb13}', '\u{fb17}'), ('\u{ff21}', '\u{ff3a}'), ('\u{ff41}', '\u{ff5a}'),
+ ('\u{10400}', '\u{1044f}'), ('\u{118a0}', '\u{118df}'), ('\u{1d400}', '\u{1d454}'),
+ ('\u{1d456}', '\u{1d49c}'), ('\u{1d49e}', '\u{1d49f}'), ('\u{1d4a2}', '\u{1d4a2}'),
+ ('\u{1d4a5}', '\u{1d4a6}'), ('\u{1d4a9}', '\u{1d4ac}'), ('\u{1d4ae}', '\u{1d4b9}'),
+ ('\u{1d4bb}', '\u{1d4bb}'), ('\u{1d4bd}', '\u{1d4c3}'), ('\u{1d4c5}', '\u{1d505}'),
+ ('\u{1d507}', '\u{1d50a}'), ('\u{1d50d}', '\u{1d514}'), ('\u{1d516}', '\u{1d51c}'),
+ ('\u{1d51e}', '\u{1d539}'), ('\u{1d53b}', '\u{1d53e}'), ('\u{1d540}', '\u{1d544}'),
+ ('\u{1d546}', '\u{1d546}'), ('\u{1d54a}', '\u{1d550}'), ('\u{1d552}', '\u{1d6a5}'),
+ ('\u{1d6a8}', '\u{1d6c0}'), ('\u{1d6c2}', '\u{1d6da}'), ('\u{1d6dc}', '\u{1d6fa}'),
+ ('\u{1d6fc}', '\u{1d714}'), ('\u{1d716}', '\u{1d734}'), ('\u{1d736}', '\u{1d74e}'),
+ ('\u{1d750}', '\u{1d76e}'), ('\u{1d770}', '\u{1d788}'), ('\u{1d78a}', '\u{1d7a8}'),
+ ('\u{1d7aa}', '\u{1d7c2}'), ('\u{1d7c4}', '\u{1d7cb}'), ('\u{1f130}', '\u{1f149}'),
+ ('\u{1f150}', '\u{1f169}'), ('\u{1f170}', '\u{1f189}')
+ ];
+
+ pub fn Cased(c: char) -> bool {
+ super::bsearch_range_table(c, Cased_table)
+ }
+
pub const Lowercase_table: &'static [(char, char)] = &[
('\u{61}', '\u{7a}'), ('\u{aa}', '\u{aa}'), ('\u{b5}', '\u{b5}'), ('\u{ba}', '\u{ba}'),
('\u{df}', '\u{f6}'), ('\u{f8}', '\u{ff}'), ('\u{101}', '\u{101}'), ('\u{103}', '\u{103}'),
use core::option::Option::{Some, None};
use core::result::Result::{Ok, Err};
- pub fn to_lower(c: char) -> char {
- match bsearch_case_table(c, LuLl_table) {
- None => c,
- Some(index) => LuLl_table[index].1
+ pub fn to_lower(c: char) -> [char; 3] {
+ match bsearch_case_table(c, to_lowercase_table) {
+ None => [c, '\0', '\0'],
+ Some(index) => to_lowercase_table[index].1
+ }
+ }
+
+ pub fn to_upper(c: char) -> [char; 3] {
+ match bsearch_case_table(c, to_uppercase_table) {
+ None => [c, '\0', '\0'],
+ Some(index) => to_uppercase_table[index].1
}
}
- pub fn to_upper(c: char) -> char {
- match bsearch_case_table(c, LlLu_table) {
- None => c,
- Some(index) => LlLu_table[index].1
+ pub fn to_title(c: char) -> [char; 3] {
+ match bsearch_case_table(c, to_titlecase_table) {
+ None => [c, '\0', '\0'],
+ Some(index) => to_titlecase_table[index].1
}
}
- fn bsearch_case_table(c: char, table: &'static [(char, char)]) -> Option<usize> {
+ fn bsearch_case_table(c: char, table: &'static [(char, [char; 3])]) -> Option<usize> {
match table.binary_search_by(|&(key, _)| {
if c == key { Equal }
else if key < c { Less }
}
}
- const LuLl_table: &'static [(char, char)] = &[
- ('\u{41}', '\u{61}'), ('\u{42}', '\u{62}'), ('\u{43}', '\u{63}'), ('\u{44}', '\u{64}'),
- ('\u{45}', '\u{65}'), ('\u{46}', '\u{66}'), ('\u{47}', '\u{67}'), ('\u{48}', '\u{68}'),
- ('\u{49}', '\u{69}'), ('\u{4a}', '\u{6a}'), ('\u{4b}', '\u{6b}'), ('\u{4c}', '\u{6c}'),
- ('\u{4d}', '\u{6d}'), ('\u{4e}', '\u{6e}'), ('\u{4f}', '\u{6f}'), ('\u{50}', '\u{70}'),
- ('\u{51}', '\u{71}'), ('\u{52}', '\u{72}'), ('\u{53}', '\u{73}'), ('\u{54}', '\u{74}'),
- ('\u{55}', '\u{75}'), ('\u{56}', '\u{76}'), ('\u{57}', '\u{77}'), ('\u{58}', '\u{78}'),
- ('\u{59}', '\u{79}'), ('\u{5a}', '\u{7a}'), ('\u{c0}', '\u{e0}'), ('\u{c1}', '\u{e1}'),
- ('\u{c2}', '\u{e2}'), ('\u{c3}', '\u{e3}'), ('\u{c4}', '\u{e4}'), ('\u{c5}', '\u{e5}'),
- ('\u{c6}', '\u{e6}'), ('\u{c7}', '\u{e7}'), ('\u{c8}', '\u{e8}'), ('\u{c9}', '\u{e9}'),
- ('\u{ca}', '\u{ea}'), ('\u{cb}', '\u{eb}'), ('\u{cc}', '\u{ec}'), ('\u{cd}', '\u{ed}'),
- ('\u{ce}', '\u{ee}'), ('\u{cf}', '\u{ef}'), ('\u{d0}', '\u{f0}'), ('\u{d1}', '\u{f1}'),
- ('\u{d2}', '\u{f2}'), ('\u{d3}', '\u{f3}'), ('\u{d4}', '\u{f4}'), ('\u{d5}', '\u{f5}'),
- ('\u{d6}', '\u{f6}'), ('\u{d8}', '\u{f8}'), ('\u{d9}', '\u{f9}'), ('\u{da}', '\u{fa}'),
- ('\u{db}', '\u{fb}'), ('\u{dc}', '\u{fc}'), ('\u{dd}', '\u{fd}'), ('\u{de}', '\u{fe}'),
- ('\u{100}', '\u{101}'), ('\u{102}', '\u{103}'), ('\u{104}', '\u{105}'), ('\u{106}',
- '\u{107}'), ('\u{108}', '\u{109}'), ('\u{10a}', '\u{10b}'), ('\u{10c}', '\u{10d}'),
- ('\u{10e}', '\u{10f}'), ('\u{110}', '\u{111}'), ('\u{112}', '\u{113}'), ('\u{114}',
- '\u{115}'), ('\u{116}', '\u{117}'), ('\u{118}', '\u{119}'), ('\u{11a}', '\u{11b}'),
- ('\u{11c}', '\u{11d}'), ('\u{11e}', '\u{11f}'), ('\u{120}', '\u{121}'), ('\u{122}',
- '\u{123}'), ('\u{124}', '\u{125}'), ('\u{126}', '\u{127}'), ('\u{128}', '\u{129}'),
- ('\u{12a}', '\u{12b}'), ('\u{12c}', '\u{12d}'), ('\u{12e}', '\u{12f}'), ('\u{130}',
- '\u{69}'), ('\u{132}', '\u{133}'), ('\u{134}', '\u{135}'), ('\u{136}', '\u{137}'),
- ('\u{139}', '\u{13a}'), ('\u{13b}', '\u{13c}'), ('\u{13d}', '\u{13e}'), ('\u{13f}',
- '\u{140}'), ('\u{141}', '\u{142}'), ('\u{143}', '\u{144}'), ('\u{145}', '\u{146}'),
- ('\u{147}', '\u{148}'), ('\u{14a}', '\u{14b}'), ('\u{14c}', '\u{14d}'), ('\u{14e}',
- '\u{14f}'), ('\u{150}', '\u{151}'), ('\u{152}', '\u{153}'), ('\u{154}', '\u{155}'),
- ('\u{156}', '\u{157}'), ('\u{158}', '\u{159}'), ('\u{15a}', '\u{15b}'), ('\u{15c}',
- '\u{15d}'), ('\u{15e}', '\u{15f}'), ('\u{160}', '\u{161}'), ('\u{162}', '\u{163}'),
- ('\u{164}', '\u{165}'), ('\u{166}', '\u{167}'), ('\u{168}', '\u{169}'), ('\u{16a}',
- '\u{16b}'), ('\u{16c}', '\u{16d}'), ('\u{16e}', '\u{16f}'), ('\u{170}', '\u{171}'),
- ('\u{172}', '\u{173}'), ('\u{174}', '\u{175}'), ('\u{176}', '\u{177}'), ('\u{178}',
- '\u{ff}'), ('\u{179}', '\u{17a}'), ('\u{17b}', '\u{17c}'), ('\u{17d}', '\u{17e}'),
- ('\u{181}', '\u{253}'), ('\u{182}', '\u{183}'), ('\u{184}', '\u{185}'), ('\u{186}',
- '\u{254}'), ('\u{187}', '\u{188}'), ('\u{189}', '\u{256}'), ('\u{18a}', '\u{257}'),
- ('\u{18b}', '\u{18c}'), ('\u{18e}', '\u{1dd}'), ('\u{18f}', '\u{259}'), ('\u{190}',
- '\u{25b}'), ('\u{191}', '\u{192}'), ('\u{193}', '\u{260}'), ('\u{194}', '\u{263}'),
- ('\u{196}', '\u{269}'), ('\u{197}', '\u{268}'), ('\u{198}', '\u{199}'), ('\u{19c}',
- '\u{26f}'), ('\u{19d}', '\u{272}'), ('\u{19f}', '\u{275}'), ('\u{1a0}', '\u{1a1}'),
- ('\u{1a2}', '\u{1a3}'), ('\u{1a4}', '\u{1a5}'), ('\u{1a6}', '\u{280}'), ('\u{1a7}',
- '\u{1a8}'), ('\u{1a9}', '\u{283}'), ('\u{1ac}', '\u{1ad}'), ('\u{1ae}', '\u{288}'),
- ('\u{1af}', '\u{1b0}'), ('\u{1b1}', '\u{28a}'), ('\u{1b2}', '\u{28b}'), ('\u{1b3}',
- '\u{1b4}'), ('\u{1b5}', '\u{1b6}'), ('\u{1b7}', '\u{292}'), ('\u{1b8}', '\u{1b9}'),
- ('\u{1bc}', '\u{1bd}'), ('\u{1c4}', '\u{1c6}'), ('\u{1c7}', '\u{1c9}'), ('\u{1ca}',
- '\u{1cc}'), ('\u{1cd}', '\u{1ce}'), ('\u{1cf}', '\u{1d0}'), ('\u{1d1}', '\u{1d2}'),
- ('\u{1d3}', '\u{1d4}'), ('\u{1d5}', '\u{1d6}'), ('\u{1d7}', '\u{1d8}'), ('\u{1d9}',
- '\u{1da}'), ('\u{1db}', '\u{1dc}'), ('\u{1de}', '\u{1df}'), ('\u{1e0}', '\u{1e1}'),
- ('\u{1e2}', '\u{1e3}'), ('\u{1e4}', '\u{1e5}'), ('\u{1e6}', '\u{1e7}'), ('\u{1e8}',
- '\u{1e9}'), ('\u{1ea}', '\u{1eb}'), ('\u{1ec}', '\u{1ed}'), ('\u{1ee}', '\u{1ef}'),
- ('\u{1f1}', '\u{1f3}'), ('\u{1f4}', '\u{1f5}'), ('\u{1f6}', '\u{195}'), ('\u{1f7}',
- '\u{1bf}'), ('\u{1f8}', '\u{1f9}'), ('\u{1fa}', '\u{1fb}'), ('\u{1fc}', '\u{1fd}'),
- ('\u{1fe}', '\u{1ff}'), ('\u{200}', '\u{201}'), ('\u{202}', '\u{203}'), ('\u{204}',
- '\u{205}'), ('\u{206}', '\u{207}'), ('\u{208}', '\u{209}'), ('\u{20a}', '\u{20b}'),
- ('\u{20c}', '\u{20d}'), ('\u{20e}', '\u{20f}'), ('\u{210}', '\u{211}'), ('\u{212}',
- '\u{213}'), ('\u{214}', '\u{215}'), ('\u{216}', '\u{217}'), ('\u{218}', '\u{219}'),
- ('\u{21a}', '\u{21b}'), ('\u{21c}', '\u{21d}'), ('\u{21e}', '\u{21f}'), ('\u{220}',
- '\u{19e}'), ('\u{222}', '\u{223}'), ('\u{224}', '\u{225}'), ('\u{226}', '\u{227}'),
- ('\u{228}', '\u{229}'), ('\u{22a}', '\u{22b}'), ('\u{22c}', '\u{22d}'), ('\u{22e}',
- '\u{22f}'), ('\u{230}', '\u{231}'), ('\u{232}', '\u{233}'), ('\u{23a}', '\u{2c65}'),
- ('\u{23b}', '\u{23c}'), ('\u{23d}', '\u{19a}'), ('\u{23e}', '\u{2c66}'), ('\u{241}',
- '\u{242}'), ('\u{243}', '\u{180}'), ('\u{244}', '\u{289}'), ('\u{245}', '\u{28c}'),
- ('\u{246}', '\u{247}'), ('\u{248}', '\u{249}'), ('\u{24a}', '\u{24b}'), ('\u{24c}',
- '\u{24d}'), ('\u{24e}', '\u{24f}'), ('\u{370}', '\u{371}'), ('\u{372}', '\u{373}'),
- ('\u{376}', '\u{377}'), ('\u{37f}', '\u{3f3}'), ('\u{386}', '\u{3ac}'), ('\u{388}',
- '\u{3ad}'), ('\u{389}', '\u{3ae}'), ('\u{38a}', '\u{3af}'), ('\u{38c}', '\u{3cc}'),
- ('\u{38e}', '\u{3cd}'), ('\u{38f}', '\u{3ce}'), ('\u{391}', '\u{3b1}'), ('\u{392}',
- '\u{3b2}'), ('\u{393}', '\u{3b3}'), ('\u{394}', '\u{3b4}'), ('\u{395}', '\u{3b5}'),
- ('\u{396}', '\u{3b6}'), ('\u{397}', '\u{3b7}'), ('\u{398}', '\u{3b8}'), ('\u{399}',
- '\u{3b9}'), ('\u{39a}', '\u{3ba}'), ('\u{39b}', '\u{3bb}'), ('\u{39c}', '\u{3bc}'),
- ('\u{39d}', '\u{3bd}'), ('\u{39e}', '\u{3be}'), ('\u{39f}', '\u{3bf}'), ('\u{3a0}',
- '\u{3c0}'), ('\u{3a1}', '\u{3c1}'), ('\u{3a3}', '\u{3c3}'), ('\u{3a4}', '\u{3c4}'),
- ('\u{3a5}', '\u{3c5}'), ('\u{3a6}', '\u{3c6}'), ('\u{3a7}', '\u{3c7}'), ('\u{3a8}',
- '\u{3c8}'), ('\u{3a9}', '\u{3c9}'), ('\u{3aa}', '\u{3ca}'), ('\u{3ab}', '\u{3cb}'),
- ('\u{3cf}', '\u{3d7}'), ('\u{3d8}', '\u{3d9}'), ('\u{3da}', '\u{3db}'), ('\u{3dc}',
- '\u{3dd}'), ('\u{3de}', '\u{3df}'), ('\u{3e0}', '\u{3e1}'), ('\u{3e2}', '\u{3e3}'),
- ('\u{3e4}', '\u{3e5}'), ('\u{3e6}', '\u{3e7}'), ('\u{3e8}', '\u{3e9}'), ('\u{3ea}',
- '\u{3eb}'), ('\u{3ec}', '\u{3ed}'), ('\u{3ee}', '\u{3ef}'), ('\u{3f4}', '\u{3b8}'),
- ('\u{3f7}', '\u{3f8}'), ('\u{3f9}', '\u{3f2}'), ('\u{3fa}', '\u{3fb}'), ('\u{3fd}',
- '\u{37b}'), ('\u{3fe}', '\u{37c}'), ('\u{3ff}', '\u{37d}'), ('\u{400}', '\u{450}'),
- ('\u{401}', '\u{451}'), ('\u{402}', '\u{452}'), ('\u{403}', '\u{453}'), ('\u{404}',
- '\u{454}'), ('\u{405}', '\u{455}'), ('\u{406}', '\u{456}'), ('\u{407}', '\u{457}'),
- ('\u{408}', '\u{458}'), ('\u{409}', '\u{459}'), ('\u{40a}', '\u{45a}'), ('\u{40b}',
- '\u{45b}'), ('\u{40c}', '\u{45c}'), ('\u{40d}', '\u{45d}'), ('\u{40e}', '\u{45e}'),
- ('\u{40f}', '\u{45f}'), ('\u{410}', '\u{430}'), ('\u{411}', '\u{431}'), ('\u{412}',
- '\u{432}'), ('\u{413}', '\u{433}'), ('\u{414}', '\u{434}'), ('\u{415}', '\u{435}'),
- ('\u{416}', '\u{436}'), ('\u{417}', '\u{437}'), ('\u{418}', '\u{438}'), ('\u{419}',
- '\u{439}'), ('\u{41a}', '\u{43a}'), ('\u{41b}', '\u{43b}'), ('\u{41c}', '\u{43c}'),
- ('\u{41d}', '\u{43d}'), ('\u{41e}', '\u{43e}'), ('\u{41f}', '\u{43f}'), ('\u{420}',
- '\u{440}'), ('\u{421}', '\u{441}'), ('\u{422}', '\u{442}'), ('\u{423}', '\u{443}'),
- ('\u{424}', '\u{444}'), ('\u{425}', '\u{445}'), ('\u{426}', '\u{446}'), ('\u{427}',
- '\u{447}'), ('\u{428}', '\u{448}'), ('\u{429}', '\u{449}'), ('\u{42a}', '\u{44a}'),
- ('\u{42b}', '\u{44b}'), ('\u{42c}', '\u{44c}'), ('\u{42d}', '\u{44d}'), ('\u{42e}',
- '\u{44e}'), ('\u{42f}', '\u{44f}'), ('\u{460}', '\u{461}'), ('\u{462}', '\u{463}'),
- ('\u{464}', '\u{465}'), ('\u{466}', '\u{467}'), ('\u{468}', '\u{469}'), ('\u{46a}',
- '\u{46b}'), ('\u{46c}', '\u{46d}'), ('\u{46e}', '\u{46f}'), ('\u{470}', '\u{471}'),
- ('\u{472}', '\u{473}'), ('\u{474}', '\u{475}'), ('\u{476}', '\u{477}'), ('\u{478}',
- '\u{479}'), ('\u{47a}', '\u{47b}'), ('\u{47c}', '\u{47d}'), ('\u{47e}', '\u{47f}'),
- ('\u{480}', '\u{481}'), ('\u{48a}', '\u{48b}'), ('\u{48c}', '\u{48d}'), ('\u{48e}',
- '\u{48f}'), ('\u{490}', '\u{491}'), ('\u{492}', '\u{493}'), ('\u{494}', '\u{495}'),
- ('\u{496}', '\u{497}'), ('\u{498}', '\u{499}'), ('\u{49a}', '\u{49b}'), ('\u{49c}',
- '\u{49d}'), ('\u{49e}', '\u{49f}'), ('\u{4a0}', '\u{4a1}'), ('\u{4a2}', '\u{4a3}'),
- ('\u{4a4}', '\u{4a5}'), ('\u{4a6}', '\u{4a7}'), ('\u{4a8}', '\u{4a9}'), ('\u{4aa}',
- '\u{4ab}'), ('\u{4ac}', '\u{4ad}'), ('\u{4ae}', '\u{4af}'), ('\u{4b0}', '\u{4b1}'),
- ('\u{4b2}', '\u{4b3}'), ('\u{4b4}', '\u{4b5}'), ('\u{4b6}', '\u{4b7}'), ('\u{4b8}',
- '\u{4b9}'), ('\u{4ba}', '\u{4bb}'), ('\u{4bc}', '\u{4bd}'), ('\u{4be}', '\u{4bf}'),
- ('\u{4c0}', '\u{4cf}'), ('\u{4c1}', '\u{4c2}'), ('\u{4c3}', '\u{4c4}'), ('\u{4c5}',
- '\u{4c6}'), ('\u{4c7}', '\u{4c8}'), ('\u{4c9}', '\u{4ca}'), ('\u{4cb}', '\u{4cc}'),
- ('\u{4cd}', '\u{4ce}'), ('\u{4d0}', '\u{4d1}'), ('\u{4d2}', '\u{4d3}'), ('\u{4d4}',
- '\u{4d5}'), ('\u{4d6}', '\u{4d7}'), ('\u{4d8}', '\u{4d9}'), ('\u{4da}', '\u{4db}'),
- ('\u{4dc}', '\u{4dd}'), ('\u{4de}', '\u{4df}'), ('\u{4e0}', '\u{4e1}'), ('\u{4e2}',
- '\u{4e3}'), ('\u{4e4}', '\u{4e5}'), ('\u{4e6}', '\u{4e7}'), ('\u{4e8}', '\u{4e9}'),
- ('\u{4ea}', '\u{4eb}'), ('\u{4ec}', '\u{4ed}'), ('\u{4ee}', '\u{4ef}'), ('\u{4f0}',
- '\u{4f1}'), ('\u{4f2}', '\u{4f3}'), ('\u{4f4}', '\u{4f5}'), ('\u{4f6}', '\u{4f7}'),
- ('\u{4f8}', '\u{4f9}'), ('\u{4fa}', '\u{4fb}'), ('\u{4fc}', '\u{4fd}'), ('\u{4fe}',
- '\u{4ff}'), ('\u{500}', '\u{501}'), ('\u{502}', '\u{503}'), ('\u{504}', '\u{505}'),
- ('\u{506}', '\u{507}'), ('\u{508}', '\u{509}'), ('\u{50a}', '\u{50b}'), ('\u{50c}',
- '\u{50d}'), ('\u{50e}', '\u{50f}'), ('\u{510}', '\u{511}'), ('\u{512}', '\u{513}'),
- ('\u{514}', '\u{515}'), ('\u{516}', '\u{517}'), ('\u{518}', '\u{519}'), ('\u{51a}',
- '\u{51b}'), ('\u{51c}', '\u{51d}'), ('\u{51e}', '\u{51f}'), ('\u{520}', '\u{521}'),
- ('\u{522}', '\u{523}'), ('\u{524}', '\u{525}'), ('\u{526}', '\u{527}'), ('\u{528}',
- '\u{529}'), ('\u{52a}', '\u{52b}'), ('\u{52c}', '\u{52d}'), ('\u{52e}', '\u{52f}'),
- ('\u{531}', '\u{561}'), ('\u{532}', '\u{562}'), ('\u{533}', '\u{563}'), ('\u{534}',
- '\u{564}'), ('\u{535}', '\u{565}'), ('\u{536}', '\u{566}'), ('\u{537}', '\u{567}'),
- ('\u{538}', '\u{568}'), ('\u{539}', '\u{569}'), ('\u{53a}', '\u{56a}'), ('\u{53b}',
- '\u{56b}'), ('\u{53c}', '\u{56c}'), ('\u{53d}', '\u{56d}'), ('\u{53e}', '\u{56e}'),
- ('\u{53f}', '\u{56f}'), ('\u{540}', '\u{570}'), ('\u{541}', '\u{571}'), ('\u{542}',
- '\u{572}'), ('\u{543}', '\u{573}'), ('\u{544}', '\u{574}'), ('\u{545}', '\u{575}'),
- ('\u{546}', '\u{576}'), ('\u{547}', '\u{577}'), ('\u{548}', '\u{578}'), ('\u{549}',
- '\u{579}'), ('\u{54a}', '\u{57a}'), ('\u{54b}', '\u{57b}'), ('\u{54c}', '\u{57c}'),
- ('\u{54d}', '\u{57d}'), ('\u{54e}', '\u{57e}'), ('\u{54f}', '\u{57f}'), ('\u{550}',
- '\u{580}'), ('\u{551}', '\u{581}'), ('\u{552}', '\u{582}'), ('\u{553}', '\u{583}'),
- ('\u{554}', '\u{584}'), ('\u{555}', '\u{585}'), ('\u{556}', '\u{586}'), ('\u{10a0}',
- '\u{2d00}'), ('\u{10a1}', '\u{2d01}'), ('\u{10a2}', '\u{2d02}'), ('\u{10a3}', '\u{2d03}'),
- ('\u{10a4}', '\u{2d04}'), ('\u{10a5}', '\u{2d05}'), ('\u{10a6}', '\u{2d06}'), ('\u{10a7}',
- '\u{2d07}'), ('\u{10a8}', '\u{2d08}'), ('\u{10a9}', '\u{2d09}'), ('\u{10aa}', '\u{2d0a}'),
- ('\u{10ab}', '\u{2d0b}'), ('\u{10ac}', '\u{2d0c}'), ('\u{10ad}', '\u{2d0d}'), ('\u{10ae}',
- '\u{2d0e}'), ('\u{10af}', '\u{2d0f}'), ('\u{10b0}', '\u{2d10}'), ('\u{10b1}', '\u{2d11}'),
- ('\u{10b2}', '\u{2d12}'), ('\u{10b3}', '\u{2d13}'), ('\u{10b4}', '\u{2d14}'), ('\u{10b5}',
- '\u{2d15}'), ('\u{10b6}', '\u{2d16}'), ('\u{10b7}', '\u{2d17}'), ('\u{10b8}', '\u{2d18}'),
- ('\u{10b9}', '\u{2d19}'), ('\u{10ba}', '\u{2d1a}'), ('\u{10bb}', '\u{2d1b}'), ('\u{10bc}',
- '\u{2d1c}'), ('\u{10bd}', '\u{2d1d}'), ('\u{10be}', '\u{2d1e}'), ('\u{10bf}', '\u{2d1f}'),
- ('\u{10c0}', '\u{2d20}'), ('\u{10c1}', '\u{2d21}'), ('\u{10c2}', '\u{2d22}'), ('\u{10c3}',
- '\u{2d23}'), ('\u{10c4}', '\u{2d24}'), ('\u{10c5}', '\u{2d25}'), ('\u{10c7}', '\u{2d27}'),
- ('\u{10cd}', '\u{2d2d}'), ('\u{1e00}', '\u{1e01}'), ('\u{1e02}', '\u{1e03}'), ('\u{1e04}',
- '\u{1e05}'), ('\u{1e06}', '\u{1e07}'), ('\u{1e08}', '\u{1e09}'), ('\u{1e0a}', '\u{1e0b}'),
- ('\u{1e0c}', '\u{1e0d}'), ('\u{1e0e}', '\u{1e0f}'), ('\u{1e10}', '\u{1e11}'), ('\u{1e12}',
- '\u{1e13}'), ('\u{1e14}', '\u{1e15}'), ('\u{1e16}', '\u{1e17}'), ('\u{1e18}', '\u{1e19}'),
- ('\u{1e1a}', '\u{1e1b}'), ('\u{1e1c}', '\u{1e1d}'), ('\u{1e1e}', '\u{1e1f}'), ('\u{1e20}',
- '\u{1e21}'), ('\u{1e22}', '\u{1e23}'), ('\u{1e24}', '\u{1e25}'), ('\u{1e26}', '\u{1e27}'),
- ('\u{1e28}', '\u{1e29}'), ('\u{1e2a}', '\u{1e2b}'), ('\u{1e2c}', '\u{1e2d}'), ('\u{1e2e}',
- '\u{1e2f}'), ('\u{1e30}', '\u{1e31}'), ('\u{1e32}', '\u{1e33}'), ('\u{1e34}', '\u{1e35}'),
- ('\u{1e36}', '\u{1e37}'), ('\u{1e38}', '\u{1e39}'), ('\u{1e3a}', '\u{1e3b}'), ('\u{1e3c}',
- '\u{1e3d}'), ('\u{1e3e}', '\u{1e3f}'), ('\u{1e40}', '\u{1e41}'), ('\u{1e42}', '\u{1e43}'),
- ('\u{1e44}', '\u{1e45}'), ('\u{1e46}', '\u{1e47}'), ('\u{1e48}', '\u{1e49}'), ('\u{1e4a}',
- '\u{1e4b}'), ('\u{1e4c}', '\u{1e4d}'), ('\u{1e4e}', '\u{1e4f}'), ('\u{1e50}', '\u{1e51}'),
- ('\u{1e52}', '\u{1e53}'), ('\u{1e54}', '\u{1e55}'), ('\u{1e56}', '\u{1e57}'), ('\u{1e58}',
- '\u{1e59}'), ('\u{1e5a}', '\u{1e5b}'), ('\u{1e5c}', '\u{1e5d}'), ('\u{1e5e}', '\u{1e5f}'),
- ('\u{1e60}', '\u{1e61}'), ('\u{1e62}', '\u{1e63}'), ('\u{1e64}', '\u{1e65}'), ('\u{1e66}',
- '\u{1e67}'), ('\u{1e68}', '\u{1e69}'), ('\u{1e6a}', '\u{1e6b}'), ('\u{1e6c}', '\u{1e6d}'),
- ('\u{1e6e}', '\u{1e6f}'), ('\u{1e70}', '\u{1e71}'), ('\u{1e72}', '\u{1e73}'), ('\u{1e74}',
- '\u{1e75}'), ('\u{1e76}', '\u{1e77}'), ('\u{1e78}', '\u{1e79}'), ('\u{1e7a}', '\u{1e7b}'),
- ('\u{1e7c}', '\u{1e7d}'), ('\u{1e7e}', '\u{1e7f}'), ('\u{1e80}', '\u{1e81}'), ('\u{1e82}',
- '\u{1e83}'), ('\u{1e84}', '\u{1e85}'), ('\u{1e86}', '\u{1e87}'), ('\u{1e88}', '\u{1e89}'),
- ('\u{1e8a}', '\u{1e8b}'), ('\u{1e8c}', '\u{1e8d}'), ('\u{1e8e}', '\u{1e8f}'), ('\u{1e90}',
- '\u{1e91}'), ('\u{1e92}', '\u{1e93}'), ('\u{1e94}', '\u{1e95}'), ('\u{1e9e}', '\u{df}'),
- ('\u{1ea0}', '\u{1ea1}'), ('\u{1ea2}', '\u{1ea3}'), ('\u{1ea4}', '\u{1ea5}'), ('\u{1ea6}',
- '\u{1ea7}'), ('\u{1ea8}', '\u{1ea9}'), ('\u{1eaa}', '\u{1eab}'), ('\u{1eac}', '\u{1ead}'),
- ('\u{1eae}', '\u{1eaf}'), ('\u{1eb0}', '\u{1eb1}'), ('\u{1eb2}', '\u{1eb3}'), ('\u{1eb4}',
- '\u{1eb5}'), ('\u{1eb6}', '\u{1eb7}'), ('\u{1eb8}', '\u{1eb9}'), ('\u{1eba}', '\u{1ebb}'),
- ('\u{1ebc}', '\u{1ebd}'), ('\u{1ebe}', '\u{1ebf}'), ('\u{1ec0}', '\u{1ec1}'), ('\u{1ec2}',
- '\u{1ec3}'), ('\u{1ec4}', '\u{1ec5}'), ('\u{1ec6}', '\u{1ec7}'), ('\u{1ec8}', '\u{1ec9}'),
- ('\u{1eca}', '\u{1ecb}'), ('\u{1ecc}', '\u{1ecd}'), ('\u{1ece}', '\u{1ecf}'), ('\u{1ed0}',
- '\u{1ed1}'), ('\u{1ed2}', '\u{1ed3}'), ('\u{1ed4}', '\u{1ed5}'), ('\u{1ed6}', '\u{1ed7}'),
- ('\u{1ed8}', '\u{1ed9}'), ('\u{1eda}', '\u{1edb}'), ('\u{1edc}', '\u{1edd}'), ('\u{1ede}',
- '\u{1edf}'), ('\u{1ee0}', '\u{1ee1}'), ('\u{1ee2}', '\u{1ee3}'), ('\u{1ee4}', '\u{1ee5}'),
- ('\u{1ee6}', '\u{1ee7}'), ('\u{1ee8}', '\u{1ee9}'), ('\u{1eea}', '\u{1eeb}'), ('\u{1eec}',
- '\u{1eed}'), ('\u{1eee}', '\u{1eef}'), ('\u{1ef0}', '\u{1ef1}'), ('\u{1ef2}', '\u{1ef3}'),
- ('\u{1ef4}', '\u{1ef5}'), ('\u{1ef6}', '\u{1ef7}'), ('\u{1ef8}', '\u{1ef9}'), ('\u{1efa}',
- '\u{1efb}'), ('\u{1efc}', '\u{1efd}'), ('\u{1efe}', '\u{1eff}'), ('\u{1f08}', '\u{1f00}'),
- ('\u{1f09}', '\u{1f01}'), ('\u{1f0a}', '\u{1f02}'), ('\u{1f0b}', '\u{1f03}'), ('\u{1f0c}',
- '\u{1f04}'), ('\u{1f0d}', '\u{1f05}'), ('\u{1f0e}', '\u{1f06}'), ('\u{1f0f}', '\u{1f07}'),
- ('\u{1f18}', '\u{1f10}'), ('\u{1f19}', '\u{1f11}'), ('\u{1f1a}', '\u{1f12}'), ('\u{1f1b}',
- '\u{1f13}'), ('\u{1f1c}', '\u{1f14}'), ('\u{1f1d}', '\u{1f15}'), ('\u{1f28}', '\u{1f20}'),
- ('\u{1f29}', '\u{1f21}'), ('\u{1f2a}', '\u{1f22}'), ('\u{1f2b}', '\u{1f23}'), ('\u{1f2c}',
- '\u{1f24}'), ('\u{1f2d}', '\u{1f25}'), ('\u{1f2e}', '\u{1f26}'), ('\u{1f2f}', '\u{1f27}'),
- ('\u{1f38}', '\u{1f30}'), ('\u{1f39}', '\u{1f31}'), ('\u{1f3a}', '\u{1f32}'), ('\u{1f3b}',
- '\u{1f33}'), ('\u{1f3c}', '\u{1f34}'), ('\u{1f3d}', '\u{1f35}'), ('\u{1f3e}', '\u{1f36}'),
- ('\u{1f3f}', '\u{1f37}'), ('\u{1f48}', '\u{1f40}'), ('\u{1f49}', '\u{1f41}'), ('\u{1f4a}',
- '\u{1f42}'), ('\u{1f4b}', '\u{1f43}'), ('\u{1f4c}', '\u{1f44}'), ('\u{1f4d}', '\u{1f45}'),
- ('\u{1f59}', '\u{1f51}'), ('\u{1f5b}', '\u{1f53}'), ('\u{1f5d}', '\u{1f55}'), ('\u{1f5f}',
- '\u{1f57}'), ('\u{1f68}', '\u{1f60}'), ('\u{1f69}', '\u{1f61}'), ('\u{1f6a}', '\u{1f62}'),
- ('\u{1f6b}', '\u{1f63}'), ('\u{1f6c}', '\u{1f64}'), ('\u{1f6d}', '\u{1f65}'), ('\u{1f6e}',
- '\u{1f66}'), ('\u{1f6f}', '\u{1f67}'), ('\u{1fb8}', '\u{1fb0}'), ('\u{1fb9}', '\u{1fb1}'),
- ('\u{1fba}', '\u{1f70}'), ('\u{1fbb}', '\u{1f71}'), ('\u{1fc8}', '\u{1f72}'), ('\u{1fc9}',
- '\u{1f73}'), ('\u{1fca}', '\u{1f74}'), ('\u{1fcb}', '\u{1f75}'), ('\u{1fd8}', '\u{1fd0}'),
- ('\u{1fd9}', '\u{1fd1}'), ('\u{1fda}', '\u{1f76}'), ('\u{1fdb}', '\u{1f77}'), ('\u{1fe8}',
- '\u{1fe0}'), ('\u{1fe9}', '\u{1fe1}'), ('\u{1fea}', '\u{1f7a}'), ('\u{1feb}', '\u{1f7b}'),
- ('\u{1fec}', '\u{1fe5}'), ('\u{1ff8}', '\u{1f78}'), ('\u{1ff9}', '\u{1f79}'), ('\u{1ffa}',
- '\u{1f7c}'), ('\u{1ffb}', '\u{1f7d}'), ('\u{2126}', '\u{3c9}'), ('\u{212a}', '\u{6b}'),
- ('\u{212b}', '\u{e5}'), ('\u{2132}', '\u{214e}'), ('\u{2183}', '\u{2184}'), ('\u{2c00}',
- '\u{2c30}'), ('\u{2c01}', '\u{2c31}'), ('\u{2c02}', '\u{2c32}'), ('\u{2c03}', '\u{2c33}'),
- ('\u{2c04}', '\u{2c34}'), ('\u{2c05}', '\u{2c35}'), ('\u{2c06}', '\u{2c36}'), ('\u{2c07}',
- '\u{2c37}'), ('\u{2c08}', '\u{2c38}'), ('\u{2c09}', '\u{2c39}'), ('\u{2c0a}', '\u{2c3a}'),
- ('\u{2c0b}', '\u{2c3b}'), ('\u{2c0c}', '\u{2c3c}'), ('\u{2c0d}', '\u{2c3d}'), ('\u{2c0e}',
- '\u{2c3e}'), ('\u{2c0f}', '\u{2c3f}'), ('\u{2c10}', '\u{2c40}'), ('\u{2c11}', '\u{2c41}'),
- ('\u{2c12}', '\u{2c42}'), ('\u{2c13}', '\u{2c43}'), ('\u{2c14}', '\u{2c44}'), ('\u{2c15}',
- '\u{2c45}'), ('\u{2c16}', '\u{2c46}'), ('\u{2c17}', '\u{2c47}'), ('\u{2c18}', '\u{2c48}'),
- ('\u{2c19}', '\u{2c49}'), ('\u{2c1a}', '\u{2c4a}'), ('\u{2c1b}', '\u{2c4b}'), ('\u{2c1c}',
- '\u{2c4c}'), ('\u{2c1d}', '\u{2c4d}'), ('\u{2c1e}', '\u{2c4e}'), ('\u{2c1f}', '\u{2c4f}'),
- ('\u{2c20}', '\u{2c50}'), ('\u{2c21}', '\u{2c51}'), ('\u{2c22}', '\u{2c52}'), ('\u{2c23}',
- '\u{2c53}'), ('\u{2c24}', '\u{2c54}'), ('\u{2c25}', '\u{2c55}'), ('\u{2c26}', '\u{2c56}'),
- ('\u{2c27}', '\u{2c57}'), ('\u{2c28}', '\u{2c58}'), ('\u{2c29}', '\u{2c59}'), ('\u{2c2a}',
- '\u{2c5a}'), ('\u{2c2b}', '\u{2c5b}'), ('\u{2c2c}', '\u{2c5c}'), ('\u{2c2d}', '\u{2c5d}'),
- ('\u{2c2e}', '\u{2c5e}'), ('\u{2c60}', '\u{2c61}'), ('\u{2c62}', '\u{26b}'), ('\u{2c63}',
- '\u{1d7d}'), ('\u{2c64}', '\u{27d}'), ('\u{2c67}', '\u{2c68}'), ('\u{2c69}', '\u{2c6a}'),
- ('\u{2c6b}', '\u{2c6c}'), ('\u{2c6d}', '\u{251}'), ('\u{2c6e}', '\u{271}'), ('\u{2c6f}',
- '\u{250}'), ('\u{2c70}', '\u{252}'), ('\u{2c72}', '\u{2c73}'), ('\u{2c75}', '\u{2c76}'),
- ('\u{2c7e}', '\u{23f}'), ('\u{2c7f}', '\u{240}'), ('\u{2c80}', '\u{2c81}'), ('\u{2c82}',
- '\u{2c83}'), ('\u{2c84}', '\u{2c85}'), ('\u{2c86}', '\u{2c87}'), ('\u{2c88}', '\u{2c89}'),
- ('\u{2c8a}', '\u{2c8b}'), ('\u{2c8c}', '\u{2c8d}'), ('\u{2c8e}', '\u{2c8f}'), ('\u{2c90}',
- '\u{2c91}'), ('\u{2c92}', '\u{2c93}'), ('\u{2c94}', '\u{2c95}'), ('\u{2c96}', '\u{2c97}'),
- ('\u{2c98}', '\u{2c99}'), ('\u{2c9a}', '\u{2c9b}'), ('\u{2c9c}', '\u{2c9d}'), ('\u{2c9e}',
- '\u{2c9f}'), ('\u{2ca0}', '\u{2ca1}'), ('\u{2ca2}', '\u{2ca3}'), ('\u{2ca4}', '\u{2ca5}'),
- ('\u{2ca6}', '\u{2ca7}'), ('\u{2ca8}', '\u{2ca9}'), ('\u{2caa}', '\u{2cab}'), ('\u{2cac}',
- '\u{2cad}'), ('\u{2cae}', '\u{2caf}'), ('\u{2cb0}', '\u{2cb1}'), ('\u{2cb2}', '\u{2cb3}'),
- ('\u{2cb4}', '\u{2cb5}'), ('\u{2cb6}', '\u{2cb7}'), ('\u{2cb8}', '\u{2cb9}'), ('\u{2cba}',
- '\u{2cbb}'), ('\u{2cbc}', '\u{2cbd}'), ('\u{2cbe}', '\u{2cbf}'), ('\u{2cc0}', '\u{2cc1}'),
- ('\u{2cc2}', '\u{2cc3}'), ('\u{2cc4}', '\u{2cc5}'), ('\u{2cc6}', '\u{2cc7}'), ('\u{2cc8}',
- '\u{2cc9}'), ('\u{2cca}', '\u{2ccb}'), ('\u{2ccc}', '\u{2ccd}'), ('\u{2cce}', '\u{2ccf}'),
- ('\u{2cd0}', '\u{2cd1}'), ('\u{2cd2}', '\u{2cd3}'), ('\u{2cd4}', '\u{2cd5}'), ('\u{2cd6}',
- '\u{2cd7}'), ('\u{2cd8}', '\u{2cd9}'), ('\u{2cda}', '\u{2cdb}'), ('\u{2cdc}', '\u{2cdd}'),
- ('\u{2cde}', '\u{2cdf}'), ('\u{2ce0}', '\u{2ce1}'), ('\u{2ce2}', '\u{2ce3}'), ('\u{2ceb}',
- '\u{2cec}'), ('\u{2ced}', '\u{2cee}'), ('\u{2cf2}', '\u{2cf3}'), ('\u{a640}', '\u{a641}'),
- ('\u{a642}', '\u{a643}'), ('\u{a644}', '\u{a645}'), ('\u{a646}', '\u{a647}'), ('\u{a648}',
- '\u{a649}'), ('\u{a64a}', '\u{a64b}'), ('\u{a64c}', '\u{a64d}'), ('\u{a64e}', '\u{a64f}'),
- ('\u{a650}', '\u{a651}'), ('\u{a652}', '\u{a653}'), ('\u{a654}', '\u{a655}'), ('\u{a656}',
- '\u{a657}'), ('\u{a658}', '\u{a659}'), ('\u{a65a}', '\u{a65b}'), ('\u{a65c}', '\u{a65d}'),
- ('\u{a65e}', '\u{a65f}'), ('\u{a660}', '\u{a661}'), ('\u{a662}', '\u{a663}'), ('\u{a664}',
- '\u{a665}'), ('\u{a666}', '\u{a667}'), ('\u{a668}', '\u{a669}'), ('\u{a66a}', '\u{a66b}'),
- ('\u{a66c}', '\u{a66d}'), ('\u{a680}', '\u{a681}'), ('\u{a682}', '\u{a683}'), ('\u{a684}',
- '\u{a685}'), ('\u{a686}', '\u{a687}'), ('\u{a688}', '\u{a689}'), ('\u{a68a}', '\u{a68b}'),
- ('\u{a68c}', '\u{a68d}'), ('\u{a68e}', '\u{a68f}'), ('\u{a690}', '\u{a691}'), ('\u{a692}',
- '\u{a693}'), ('\u{a694}', '\u{a695}'), ('\u{a696}', '\u{a697}'), ('\u{a698}', '\u{a699}'),
- ('\u{a69a}', '\u{a69b}'), ('\u{a722}', '\u{a723}'), ('\u{a724}', '\u{a725}'), ('\u{a726}',
- '\u{a727}'), ('\u{a728}', '\u{a729}'), ('\u{a72a}', '\u{a72b}'), ('\u{a72c}', '\u{a72d}'),
- ('\u{a72e}', '\u{a72f}'), ('\u{a732}', '\u{a733}'), ('\u{a734}', '\u{a735}'), ('\u{a736}',
- '\u{a737}'), ('\u{a738}', '\u{a739}'), ('\u{a73a}', '\u{a73b}'), ('\u{a73c}', '\u{a73d}'),
- ('\u{a73e}', '\u{a73f}'), ('\u{a740}', '\u{a741}'), ('\u{a742}', '\u{a743}'), ('\u{a744}',
- '\u{a745}'), ('\u{a746}', '\u{a747}'), ('\u{a748}', '\u{a749}'), ('\u{a74a}', '\u{a74b}'),
- ('\u{a74c}', '\u{a74d}'), ('\u{a74e}', '\u{a74f}'), ('\u{a750}', '\u{a751}'), ('\u{a752}',
- '\u{a753}'), ('\u{a754}', '\u{a755}'), ('\u{a756}', '\u{a757}'), ('\u{a758}', '\u{a759}'),
- ('\u{a75a}', '\u{a75b}'), ('\u{a75c}', '\u{a75d}'), ('\u{a75e}', '\u{a75f}'), ('\u{a760}',
- '\u{a761}'), ('\u{a762}', '\u{a763}'), ('\u{a764}', '\u{a765}'), ('\u{a766}', '\u{a767}'),
- ('\u{a768}', '\u{a769}'), ('\u{a76a}', '\u{a76b}'), ('\u{a76c}', '\u{a76d}'), ('\u{a76e}',
- '\u{a76f}'), ('\u{a779}', '\u{a77a}'), ('\u{a77b}', '\u{a77c}'), ('\u{a77d}', '\u{1d79}'),
- ('\u{a77e}', '\u{a77f}'), ('\u{a780}', '\u{a781}'), ('\u{a782}', '\u{a783}'), ('\u{a784}',
- '\u{a785}'), ('\u{a786}', '\u{a787}'), ('\u{a78b}', '\u{a78c}'), ('\u{a78d}', '\u{265}'),
- ('\u{a790}', '\u{a791}'), ('\u{a792}', '\u{a793}'), ('\u{a796}', '\u{a797}'), ('\u{a798}',
- '\u{a799}'), ('\u{a79a}', '\u{a79b}'), ('\u{a79c}', '\u{a79d}'), ('\u{a79e}', '\u{a79f}'),
- ('\u{a7a0}', '\u{a7a1}'), ('\u{a7a2}', '\u{a7a3}'), ('\u{a7a4}', '\u{a7a5}'), ('\u{a7a6}',
- '\u{a7a7}'), ('\u{a7a8}', '\u{a7a9}'), ('\u{a7aa}', '\u{266}'), ('\u{a7ab}', '\u{25c}'),
- ('\u{a7ac}', '\u{261}'), ('\u{a7ad}', '\u{26c}'), ('\u{a7b0}', '\u{29e}'), ('\u{a7b1}',
- '\u{287}'), ('\u{ff21}', '\u{ff41}'), ('\u{ff22}', '\u{ff42}'), ('\u{ff23}', '\u{ff43}'),
- ('\u{ff24}', '\u{ff44}'), ('\u{ff25}', '\u{ff45}'), ('\u{ff26}', '\u{ff46}'), ('\u{ff27}',
- '\u{ff47}'), ('\u{ff28}', '\u{ff48}'), ('\u{ff29}', '\u{ff49}'), ('\u{ff2a}', '\u{ff4a}'),
- ('\u{ff2b}', '\u{ff4b}'), ('\u{ff2c}', '\u{ff4c}'), ('\u{ff2d}', '\u{ff4d}'), ('\u{ff2e}',
- '\u{ff4e}'), ('\u{ff2f}', '\u{ff4f}'), ('\u{ff30}', '\u{ff50}'), ('\u{ff31}', '\u{ff51}'),
- ('\u{ff32}', '\u{ff52}'), ('\u{ff33}', '\u{ff53}'), ('\u{ff34}', '\u{ff54}'), ('\u{ff35}',
- '\u{ff55}'), ('\u{ff36}', '\u{ff56}'), ('\u{ff37}', '\u{ff57}'), ('\u{ff38}', '\u{ff58}'),
- ('\u{ff39}', '\u{ff59}'), ('\u{ff3a}', '\u{ff5a}'), ('\u{10400}', '\u{10428}'),
- ('\u{10401}', '\u{10429}'), ('\u{10402}', '\u{1042a}'), ('\u{10403}', '\u{1042b}'),
- ('\u{10404}', '\u{1042c}'), ('\u{10405}', '\u{1042d}'), ('\u{10406}', '\u{1042e}'),
- ('\u{10407}', '\u{1042f}'), ('\u{10408}', '\u{10430}'), ('\u{10409}', '\u{10431}'),
- ('\u{1040a}', '\u{10432}'), ('\u{1040b}', '\u{10433}'), ('\u{1040c}', '\u{10434}'),
- ('\u{1040d}', '\u{10435}'), ('\u{1040e}', '\u{10436}'), ('\u{1040f}', '\u{10437}'),
- ('\u{10410}', '\u{10438}'), ('\u{10411}', '\u{10439}'), ('\u{10412}', '\u{1043a}'),
- ('\u{10413}', '\u{1043b}'), ('\u{10414}', '\u{1043c}'), ('\u{10415}', '\u{1043d}'),
- ('\u{10416}', '\u{1043e}'), ('\u{10417}', '\u{1043f}'), ('\u{10418}', '\u{10440}'),
- ('\u{10419}', '\u{10441}'), ('\u{1041a}', '\u{10442}'), ('\u{1041b}', '\u{10443}'),
- ('\u{1041c}', '\u{10444}'), ('\u{1041d}', '\u{10445}'), ('\u{1041e}', '\u{10446}'),
- ('\u{1041f}', '\u{10447}'), ('\u{10420}', '\u{10448}'), ('\u{10421}', '\u{10449}'),
- ('\u{10422}', '\u{1044a}'), ('\u{10423}', '\u{1044b}'), ('\u{10424}', '\u{1044c}'),
- ('\u{10425}', '\u{1044d}'), ('\u{10426}', '\u{1044e}'), ('\u{10427}', '\u{1044f}'),
- ('\u{118a0}', '\u{118c0}'), ('\u{118a1}', '\u{118c1}'), ('\u{118a2}', '\u{118c2}'),
- ('\u{118a3}', '\u{118c3}'), ('\u{118a4}', '\u{118c4}'), ('\u{118a5}', '\u{118c5}'),
- ('\u{118a6}', '\u{118c6}'), ('\u{118a7}', '\u{118c7}'), ('\u{118a8}', '\u{118c8}'),
- ('\u{118a9}', '\u{118c9}'), ('\u{118aa}', '\u{118ca}'), ('\u{118ab}', '\u{118cb}'),
- ('\u{118ac}', '\u{118cc}'), ('\u{118ad}', '\u{118cd}'), ('\u{118ae}', '\u{118ce}'),
- ('\u{118af}', '\u{118cf}'), ('\u{118b0}', '\u{118d0}'), ('\u{118b1}', '\u{118d1}'),
- ('\u{118b2}', '\u{118d2}'), ('\u{118b3}', '\u{118d3}'), ('\u{118b4}', '\u{118d4}'),
- ('\u{118b5}', '\u{118d5}'), ('\u{118b6}', '\u{118d6}'), ('\u{118b7}', '\u{118d7}'),
- ('\u{118b8}', '\u{118d8}'), ('\u{118b9}', '\u{118d9}'), ('\u{118ba}', '\u{118da}'),
- ('\u{118bb}', '\u{118db}'), ('\u{118bc}', '\u{118dc}'), ('\u{118bd}', '\u{118dd}'),
- ('\u{118be}', '\u{118de}'), ('\u{118bf}', '\u{118df}')
+ const to_lowercase_table: &'static [(char, [char; 3])] = &[
+ ('\u{41}', ['\u{61}', '\0', '\0']), ('\u{42}', ['\u{62}', '\0', '\0']), ('\u{43}',
+ ['\u{63}', '\0', '\0']), ('\u{44}', ['\u{64}', '\0', '\0']), ('\u{45}', ['\u{65}', '\0',
+ '\0']), ('\u{46}', ['\u{66}', '\0', '\0']), ('\u{47}', ['\u{67}', '\0', '\0']), ('\u{48}',
+ ['\u{68}', '\0', '\0']), ('\u{49}', ['\u{69}', '\0', '\0']), ('\u{4a}', ['\u{6a}', '\0',
+ '\0']), ('\u{4b}', ['\u{6b}', '\0', '\0']), ('\u{4c}', ['\u{6c}', '\0', '\0']), ('\u{4d}',
+ ['\u{6d}', '\0', '\0']), ('\u{4e}', ['\u{6e}', '\0', '\0']), ('\u{4f}', ['\u{6f}', '\0',
+ '\0']), ('\u{50}', ['\u{70}', '\0', '\0']), ('\u{51}', ['\u{71}', '\0', '\0']), ('\u{52}',
+ ['\u{72}', '\0', '\0']), ('\u{53}', ['\u{73}', '\0', '\0']), ('\u{54}', ['\u{74}', '\0',
+ '\0']), ('\u{55}', ['\u{75}', '\0', '\0']), ('\u{56}', ['\u{76}', '\0', '\0']), ('\u{57}',
+ ['\u{77}', '\0', '\0']), ('\u{58}', ['\u{78}', '\0', '\0']), ('\u{59}', ['\u{79}', '\0',
+ '\0']), ('\u{5a}', ['\u{7a}', '\0', '\0']), ('\u{c0}', ['\u{e0}', '\0', '\0']), ('\u{c1}',
+ ['\u{e1}', '\0', '\0']), ('\u{c2}', ['\u{e2}', '\0', '\0']), ('\u{c3}', ['\u{e3}', '\0',
+ '\0']), ('\u{c4}', ['\u{e4}', '\0', '\0']), ('\u{c5}', ['\u{e5}', '\0', '\0']), ('\u{c6}',
+ ['\u{e6}', '\0', '\0']), ('\u{c7}', ['\u{e7}', '\0', '\0']), ('\u{c8}', ['\u{e8}', '\0',
+ '\0']), ('\u{c9}', ['\u{e9}', '\0', '\0']), ('\u{ca}', ['\u{ea}', '\0', '\0']), ('\u{cb}',
+ ['\u{eb}', '\0', '\0']), ('\u{cc}', ['\u{ec}', '\0', '\0']), ('\u{cd}', ['\u{ed}', '\0',
+ '\0']), ('\u{ce}', ['\u{ee}', '\0', '\0']), ('\u{cf}', ['\u{ef}', '\0', '\0']), ('\u{d0}',
+ ['\u{f0}', '\0', '\0']), ('\u{d1}', ['\u{f1}', '\0', '\0']), ('\u{d2}', ['\u{f2}', '\0',
+ '\0']), ('\u{d3}', ['\u{f3}', '\0', '\0']), ('\u{d4}', ['\u{f4}', '\0', '\0']), ('\u{d5}',
+ ['\u{f5}', '\0', '\0']), ('\u{d6}', ['\u{f6}', '\0', '\0']), ('\u{d8}', ['\u{f8}', '\0',
+ '\0']), ('\u{d9}', ['\u{f9}', '\0', '\0']), ('\u{da}', ['\u{fa}', '\0', '\0']), ('\u{db}',
+ ['\u{fb}', '\0', '\0']), ('\u{dc}', ['\u{fc}', '\0', '\0']), ('\u{dd}', ['\u{fd}', '\0',
+ '\0']), ('\u{de}', ['\u{fe}', '\0', '\0']), ('\u{100}', ['\u{101}', '\0', '\0']),
+ ('\u{102}', ['\u{103}', '\0', '\0']), ('\u{104}', ['\u{105}', '\0', '\0']), ('\u{106}',
+ ['\u{107}', '\0', '\0']), ('\u{108}', ['\u{109}', '\0', '\0']), ('\u{10a}', ['\u{10b}',
+ '\0', '\0']), ('\u{10c}', ['\u{10d}', '\0', '\0']), ('\u{10e}', ['\u{10f}', '\0', '\0']),
+ ('\u{110}', ['\u{111}', '\0', '\0']), ('\u{112}', ['\u{113}', '\0', '\0']), ('\u{114}',
+ ['\u{115}', '\0', '\0']), ('\u{116}', ['\u{117}', '\0', '\0']), ('\u{118}', ['\u{119}',
+ '\0', '\0']), ('\u{11a}', ['\u{11b}', '\0', '\0']), ('\u{11c}', ['\u{11d}', '\0', '\0']),
+ ('\u{11e}', ['\u{11f}', '\0', '\0']), ('\u{120}', ['\u{121}', '\0', '\0']), ('\u{122}',
+ ['\u{123}', '\0', '\0']), ('\u{124}', ['\u{125}', '\0', '\0']), ('\u{126}', ['\u{127}',
+ '\0', '\0']), ('\u{128}', ['\u{129}', '\0', '\0']), ('\u{12a}', ['\u{12b}', '\0', '\0']),
+ ('\u{12c}', ['\u{12d}', '\0', '\0']), ('\u{12e}', ['\u{12f}', '\0', '\0']), ('\u{130}',
+ ['\u{69}', '\u{307}', '\0']), ('\u{132}', ['\u{133}', '\0', '\0']), ('\u{134}', ['\u{135}',
+ '\0', '\0']), ('\u{136}', ['\u{137}', '\0', '\0']), ('\u{139}', ['\u{13a}', '\0', '\0']),
+ ('\u{13b}', ['\u{13c}', '\0', '\0']), ('\u{13d}', ['\u{13e}', '\0', '\0']), ('\u{13f}',
+ ['\u{140}', '\0', '\0']), ('\u{141}', ['\u{142}', '\0', '\0']), ('\u{143}', ['\u{144}',
+ '\0', '\0']), ('\u{145}', ['\u{146}', '\0', '\0']), ('\u{147}', ['\u{148}', '\0', '\0']),
+ ('\u{14a}', ['\u{14b}', '\0', '\0']), ('\u{14c}', ['\u{14d}', '\0', '\0']), ('\u{14e}',
+ ['\u{14f}', '\0', '\0']), ('\u{150}', ['\u{151}', '\0', '\0']), ('\u{152}', ['\u{153}',
+ '\0', '\0']), ('\u{154}', ['\u{155}', '\0', '\0']), ('\u{156}', ['\u{157}', '\0', '\0']),
+ ('\u{158}', ['\u{159}', '\0', '\0']), ('\u{15a}', ['\u{15b}', '\0', '\0']), ('\u{15c}',
+ ['\u{15d}', '\0', '\0']), ('\u{15e}', ['\u{15f}', '\0', '\0']), ('\u{160}', ['\u{161}',
+ '\0', '\0']), ('\u{162}', ['\u{163}', '\0', '\0']), ('\u{164}', ['\u{165}', '\0', '\0']),
+ ('\u{166}', ['\u{167}', '\0', '\0']), ('\u{168}', ['\u{169}', '\0', '\0']), ('\u{16a}',
+ ['\u{16b}', '\0', '\0']), ('\u{16c}', ['\u{16d}', '\0', '\0']), ('\u{16e}', ['\u{16f}',
+ '\0', '\0']), ('\u{170}', ['\u{171}', '\0', '\0']), ('\u{172}', ['\u{173}', '\0', '\0']),
+ ('\u{174}', ['\u{175}', '\0', '\0']), ('\u{176}', ['\u{177}', '\0', '\0']), ('\u{178}',
+ ['\u{ff}', '\0', '\0']), ('\u{179}', ['\u{17a}', '\0', '\0']), ('\u{17b}', ['\u{17c}', '\0',
+ '\0']), ('\u{17d}', ['\u{17e}', '\0', '\0']), ('\u{181}', ['\u{253}', '\0', '\0']),
+ ('\u{182}', ['\u{183}', '\0', '\0']), ('\u{184}', ['\u{185}', '\0', '\0']), ('\u{186}',
+ ['\u{254}', '\0', '\0']), ('\u{187}', ['\u{188}', '\0', '\0']), ('\u{189}', ['\u{256}',
+ '\0', '\0']), ('\u{18a}', ['\u{257}', '\0', '\0']), ('\u{18b}', ['\u{18c}', '\0', '\0']),
+ ('\u{18e}', ['\u{1dd}', '\0', '\0']), ('\u{18f}', ['\u{259}', '\0', '\0']), ('\u{190}',
+ ['\u{25b}', '\0', '\0']), ('\u{191}', ['\u{192}', '\0', '\0']), ('\u{193}', ['\u{260}',
+ '\0', '\0']), ('\u{194}', ['\u{263}', '\0', '\0']), ('\u{196}', ['\u{269}', '\0', '\0']),
+ ('\u{197}', ['\u{268}', '\0', '\0']), ('\u{198}', ['\u{199}', '\0', '\0']), ('\u{19c}',
+ ['\u{26f}', '\0', '\0']), ('\u{19d}', ['\u{272}', '\0', '\0']), ('\u{19f}', ['\u{275}',
+ '\0', '\0']), ('\u{1a0}', ['\u{1a1}', '\0', '\0']), ('\u{1a2}', ['\u{1a3}', '\0', '\0']),
+ ('\u{1a4}', ['\u{1a5}', '\0', '\0']), ('\u{1a6}', ['\u{280}', '\0', '\0']), ('\u{1a7}',
+ ['\u{1a8}', '\0', '\0']), ('\u{1a9}', ['\u{283}', '\0', '\0']), ('\u{1ac}', ['\u{1ad}',
+ '\0', '\0']), ('\u{1ae}', ['\u{288}', '\0', '\0']), ('\u{1af}', ['\u{1b0}', '\0', '\0']),
+ ('\u{1b1}', ['\u{28a}', '\0', '\0']), ('\u{1b2}', ['\u{28b}', '\0', '\0']), ('\u{1b3}',
+ ['\u{1b4}', '\0', '\0']), ('\u{1b5}', ['\u{1b6}', '\0', '\0']), ('\u{1b7}', ['\u{292}',
+ '\0', '\0']), ('\u{1b8}', ['\u{1b9}', '\0', '\0']), ('\u{1bc}', ['\u{1bd}', '\0', '\0']),
+ ('\u{1c4}', ['\u{1c6}', '\0', '\0']), ('\u{1c5}', ['\u{1c6}', '\0', '\0']), ('\u{1c7}',
+ ['\u{1c9}', '\0', '\0']), ('\u{1c8}', ['\u{1c9}', '\0', '\0']), ('\u{1ca}', ['\u{1cc}',
+ '\0', '\0']), ('\u{1cb}', ['\u{1cc}', '\0', '\0']), ('\u{1cd}', ['\u{1ce}', '\0', '\0']),
+ ('\u{1cf}', ['\u{1d0}', '\0', '\0']), ('\u{1d1}', ['\u{1d2}', '\0', '\0']), ('\u{1d3}',
+ ['\u{1d4}', '\0', '\0']), ('\u{1d5}', ['\u{1d6}', '\0', '\0']), ('\u{1d7}', ['\u{1d8}',
+ '\0', '\0']), ('\u{1d9}', ['\u{1da}', '\0', '\0']), ('\u{1db}', ['\u{1dc}', '\0', '\0']),
+ ('\u{1de}', ['\u{1df}', '\0', '\0']), ('\u{1e0}', ['\u{1e1}', '\0', '\0']), ('\u{1e2}',
+ ['\u{1e3}', '\0', '\0']), ('\u{1e4}', ['\u{1e5}', '\0', '\0']), ('\u{1e6}', ['\u{1e7}',
+ '\0', '\0']), ('\u{1e8}', ['\u{1e9}', '\0', '\0']), ('\u{1ea}', ['\u{1eb}', '\0', '\0']),
+ ('\u{1ec}', ['\u{1ed}', '\0', '\0']), ('\u{1ee}', ['\u{1ef}', '\0', '\0']), ('\u{1f1}',
+ ['\u{1f3}', '\0', '\0']), ('\u{1f2}', ['\u{1f3}', '\0', '\0']), ('\u{1f4}', ['\u{1f5}',
+ '\0', '\0']), ('\u{1f6}', ['\u{195}', '\0', '\0']), ('\u{1f7}', ['\u{1bf}', '\0', '\0']),
+ ('\u{1f8}', ['\u{1f9}', '\0', '\0']), ('\u{1fa}', ['\u{1fb}', '\0', '\0']), ('\u{1fc}',
+ ['\u{1fd}', '\0', '\0']), ('\u{1fe}', ['\u{1ff}', '\0', '\0']), ('\u{200}', ['\u{201}',
+ '\0', '\0']), ('\u{202}', ['\u{203}', '\0', '\0']), ('\u{204}', ['\u{205}', '\0', '\0']),
+ ('\u{206}', ['\u{207}', '\0', '\0']), ('\u{208}', ['\u{209}', '\0', '\0']), ('\u{20a}',
+ ['\u{20b}', '\0', '\0']), ('\u{20c}', ['\u{20d}', '\0', '\0']), ('\u{20e}', ['\u{20f}',
+ '\0', '\0']), ('\u{210}', ['\u{211}', '\0', '\0']), ('\u{212}', ['\u{213}', '\0', '\0']),
+ ('\u{214}', ['\u{215}', '\0', '\0']), ('\u{216}', ['\u{217}', '\0', '\0']), ('\u{218}',
+ ['\u{219}', '\0', '\0']), ('\u{21a}', ['\u{21b}', '\0', '\0']), ('\u{21c}', ['\u{21d}',
+ '\0', '\0']), ('\u{21e}', ['\u{21f}', '\0', '\0']), ('\u{220}', ['\u{19e}', '\0', '\0']),
+ ('\u{222}', ['\u{223}', '\0', '\0']), ('\u{224}', ['\u{225}', '\0', '\0']), ('\u{226}',
+ ['\u{227}', '\0', '\0']), ('\u{228}', ['\u{229}', '\0', '\0']), ('\u{22a}', ['\u{22b}',
+ '\0', '\0']), ('\u{22c}', ['\u{22d}', '\0', '\0']), ('\u{22e}', ['\u{22f}', '\0', '\0']),
+ ('\u{230}', ['\u{231}', '\0', '\0']), ('\u{232}', ['\u{233}', '\0', '\0']), ('\u{23a}',
+ ['\u{2c65}', '\0', '\0']), ('\u{23b}', ['\u{23c}', '\0', '\0']), ('\u{23d}', ['\u{19a}',
+ '\0', '\0']), ('\u{23e}', ['\u{2c66}', '\0', '\0']), ('\u{241}', ['\u{242}', '\0', '\0']),
+ ('\u{243}', ['\u{180}', '\0', '\0']), ('\u{244}', ['\u{289}', '\0', '\0']), ('\u{245}',
+ ['\u{28c}', '\0', '\0']), ('\u{246}', ['\u{247}', '\0', '\0']), ('\u{248}', ['\u{249}',
+ '\0', '\0']), ('\u{24a}', ['\u{24b}', '\0', '\0']), ('\u{24c}', ['\u{24d}', '\0', '\0']),
+ ('\u{24e}', ['\u{24f}', '\0', '\0']), ('\u{370}', ['\u{371}', '\0', '\0']), ('\u{372}',
+ ['\u{373}', '\0', '\0']), ('\u{376}', ['\u{377}', '\0', '\0']), ('\u{37f}', ['\u{3f3}',
+ '\0', '\0']), ('\u{386}', ['\u{3ac}', '\0', '\0']), ('\u{388}', ['\u{3ad}', '\0', '\0']),
+ ('\u{389}', ['\u{3ae}', '\0', '\0']), ('\u{38a}', ['\u{3af}', '\0', '\0']), ('\u{38c}',
+ ['\u{3cc}', '\0', '\0']), ('\u{38e}', ['\u{3cd}', '\0', '\0']), ('\u{38f}', ['\u{3ce}',
+ '\0', '\0']), ('\u{391}', ['\u{3b1}', '\0', '\0']), ('\u{392}', ['\u{3b2}', '\0', '\0']),
+ ('\u{393}', ['\u{3b3}', '\0', '\0']), ('\u{394}', ['\u{3b4}', '\0', '\0']), ('\u{395}',
+ ['\u{3b5}', '\0', '\0']), ('\u{396}', ['\u{3b6}', '\0', '\0']), ('\u{397}', ['\u{3b7}',
+ '\0', '\0']), ('\u{398}', ['\u{3b8}', '\0', '\0']), ('\u{399}', ['\u{3b9}', '\0', '\0']),
+ ('\u{39a}', ['\u{3ba}', '\0', '\0']), ('\u{39b}', ['\u{3bb}', '\0', '\0']), ('\u{39c}',
+ ['\u{3bc}', '\0', '\0']), ('\u{39d}', ['\u{3bd}', '\0', '\0']), ('\u{39e}', ['\u{3be}',
+ '\0', '\0']), ('\u{39f}', ['\u{3bf}', '\0', '\0']), ('\u{3a0}', ['\u{3c0}', '\0', '\0']),
+ ('\u{3a1}', ['\u{3c1}', '\0', '\0']), ('\u{3a3}', ['\u{3c3}', '\0', '\0']), ('\u{3a4}',
+ ['\u{3c4}', '\0', '\0']), ('\u{3a5}', ['\u{3c5}', '\0', '\0']), ('\u{3a6}', ['\u{3c6}',
+ '\0', '\0']), ('\u{3a7}', ['\u{3c7}', '\0', '\0']), ('\u{3a8}', ['\u{3c8}', '\0', '\0']),
+ ('\u{3a9}', ['\u{3c9}', '\0', '\0']), ('\u{3aa}', ['\u{3ca}', '\0', '\0']), ('\u{3ab}',
+ ['\u{3cb}', '\0', '\0']), ('\u{3cf}', ['\u{3d7}', '\0', '\0']), ('\u{3d8}', ['\u{3d9}',
+ '\0', '\0']), ('\u{3da}', ['\u{3db}', '\0', '\0']), ('\u{3dc}', ['\u{3dd}', '\0', '\0']),
+ ('\u{3de}', ['\u{3df}', '\0', '\0']), ('\u{3e0}', ['\u{3e1}', '\0', '\0']), ('\u{3e2}',
+ ['\u{3e3}', '\0', '\0']), ('\u{3e4}', ['\u{3e5}', '\0', '\0']), ('\u{3e6}', ['\u{3e7}',
+ '\0', '\0']), ('\u{3e8}', ['\u{3e9}', '\0', '\0']), ('\u{3ea}', ['\u{3eb}', '\0', '\0']),
+ ('\u{3ec}', ['\u{3ed}', '\0', '\0']), ('\u{3ee}', ['\u{3ef}', '\0', '\0']), ('\u{3f4}',
+ ['\u{3b8}', '\0', '\0']), ('\u{3f7}', ['\u{3f8}', '\0', '\0']), ('\u{3f9}', ['\u{3f2}',
+ '\0', '\0']), ('\u{3fa}', ['\u{3fb}', '\0', '\0']), ('\u{3fd}', ['\u{37b}', '\0', '\0']),
+ ('\u{3fe}', ['\u{37c}', '\0', '\0']), ('\u{3ff}', ['\u{37d}', '\0', '\0']), ('\u{400}',
+ ['\u{450}', '\0', '\0']), ('\u{401}', ['\u{451}', '\0', '\0']), ('\u{402}', ['\u{452}',
+ '\0', '\0']), ('\u{403}', ['\u{453}', '\0', '\0']), ('\u{404}', ['\u{454}', '\0', '\0']),
+ ('\u{405}', ['\u{455}', '\0', '\0']), ('\u{406}', ['\u{456}', '\0', '\0']), ('\u{407}',
+ ['\u{457}', '\0', '\0']), ('\u{408}', ['\u{458}', '\0', '\0']), ('\u{409}', ['\u{459}',
+ '\0', '\0']), ('\u{40a}', ['\u{45a}', '\0', '\0']), ('\u{40b}', ['\u{45b}', '\0', '\0']),
+ ('\u{40c}', ['\u{45c}', '\0', '\0']), ('\u{40d}', ['\u{45d}', '\0', '\0']), ('\u{40e}',
+ ['\u{45e}', '\0', '\0']), ('\u{40f}', ['\u{45f}', '\0', '\0']), ('\u{410}', ['\u{430}',
+ '\0', '\0']), ('\u{411}', ['\u{431}', '\0', '\0']), ('\u{412}', ['\u{432}', '\0', '\0']),
+ ('\u{413}', ['\u{433}', '\0', '\0']), ('\u{414}', ['\u{434}', '\0', '\0']), ('\u{415}',
+ ['\u{435}', '\0', '\0']), ('\u{416}', ['\u{436}', '\0', '\0']), ('\u{417}', ['\u{437}',
+ '\0', '\0']), ('\u{418}', ['\u{438}', '\0', '\0']), ('\u{419}', ['\u{439}', '\0', '\0']),
+ ('\u{41a}', ['\u{43a}', '\0', '\0']), ('\u{41b}', ['\u{43b}', '\0', '\0']), ('\u{41c}',
+ ['\u{43c}', '\0', '\0']), ('\u{41d}', ['\u{43d}', '\0', '\0']), ('\u{41e}', ['\u{43e}',
+ '\0', '\0']), ('\u{41f}', ['\u{43f}', '\0', '\0']), ('\u{420}', ['\u{440}', '\0', '\0']),
+ ('\u{421}', ['\u{441}', '\0', '\0']), ('\u{422}', ['\u{442}', '\0', '\0']), ('\u{423}',
+ ['\u{443}', '\0', '\0']), ('\u{424}', ['\u{444}', '\0', '\0']), ('\u{425}', ['\u{445}',
+ '\0', '\0']), ('\u{426}', ['\u{446}', '\0', '\0']), ('\u{427}', ['\u{447}', '\0', '\0']),
+ ('\u{428}', ['\u{448}', '\0', '\0']), ('\u{429}', ['\u{449}', '\0', '\0']), ('\u{42a}',
+ ['\u{44a}', '\0', '\0']), ('\u{42b}', ['\u{44b}', '\0', '\0']), ('\u{42c}', ['\u{44c}',
+ '\0', '\0']), ('\u{42d}', ['\u{44d}', '\0', '\0']), ('\u{42e}', ['\u{44e}', '\0', '\0']),
+ ('\u{42f}', ['\u{44f}', '\0', '\0']), ('\u{460}', ['\u{461}', '\0', '\0']), ('\u{462}',
+ ['\u{463}', '\0', '\0']), ('\u{464}', ['\u{465}', '\0', '\0']), ('\u{466}', ['\u{467}',
+ '\0', '\0']), ('\u{468}', ['\u{469}', '\0', '\0']), ('\u{46a}', ['\u{46b}', '\0', '\0']),
+ ('\u{46c}', ['\u{46d}', '\0', '\0']), ('\u{46e}', ['\u{46f}', '\0', '\0']), ('\u{470}',
+ ['\u{471}', '\0', '\0']), ('\u{472}', ['\u{473}', '\0', '\0']), ('\u{474}', ['\u{475}',
+ '\0', '\0']), ('\u{476}', ['\u{477}', '\0', '\0']), ('\u{478}', ['\u{479}', '\0', '\0']),
+ ('\u{47a}', ['\u{47b}', '\0', '\0']), ('\u{47c}', ['\u{47d}', '\0', '\0']), ('\u{47e}',
+ ['\u{47f}', '\0', '\0']), ('\u{480}', ['\u{481}', '\0', '\0']), ('\u{48a}', ['\u{48b}',
+ '\0', '\0']), ('\u{48c}', ['\u{48d}', '\0', '\0']), ('\u{48e}', ['\u{48f}', '\0', '\0']),
+ ('\u{490}', ['\u{491}', '\0', '\0']), ('\u{492}', ['\u{493}', '\0', '\0']), ('\u{494}',
+ ['\u{495}', '\0', '\0']), ('\u{496}', ['\u{497}', '\0', '\0']), ('\u{498}', ['\u{499}',
+ '\0', '\0']), ('\u{49a}', ['\u{49b}', '\0', '\0']), ('\u{49c}', ['\u{49d}', '\0', '\0']),
+ ('\u{49e}', ['\u{49f}', '\0', '\0']), ('\u{4a0}', ['\u{4a1}', '\0', '\0']), ('\u{4a2}',
+ ['\u{4a3}', '\0', '\0']), ('\u{4a4}', ['\u{4a5}', '\0', '\0']), ('\u{4a6}', ['\u{4a7}',
+ '\0', '\0']), ('\u{4a8}', ['\u{4a9}', '\0', '\0']), ('\u{4aa}', ['\u{4ab}', '\0', '\0']),
+ ('\u{4ac}', ['\u{4ad}', '\0', '\0']), ('\u{4ae}', ['\u{4af}', '\0', '\0']), ('\u{4b0}',
+ ['\u{4b1}', '\0', '\0']), ('\u{4b2}', ['\u{4b3}', '\0', '\0']), ('\u{4b4}', ['\u{4b5}',
+ '\0', '\0']), ('\u{4b6}', ['\u{4b7}', '\0', '\0']), ('\u{4b8}', ['\u{4b9}', '\0', '\0']),
+ ('\u{4ba}', ['\u{4bb}', '\0', '\0']), ('\u{4bc}', ['\u{4bd}', '\0', '\0']), ('\u{4be}',
+ ['\u{4bf}', '\0', '\0']), ('\u{4c0}', ['\u{4cf}', '\0', '\0']), ('\u{4c1}', ['\u{4c2}',
+ '\0', '\0']), ('\u{4c3}', ['\u{4c4}', '\0', '\0']), ('\u{4c5}', ['\u{4c6}', '\0', '\0']),
+ ('\u{4c7}', ['\u{4c8}', '\0', '\0']), ('\u{4c9}', ['\u{4ca}', '\0', '\0']), ('\u{4cb}',
+ ['\u{4cc}', '\0', '\0']), ('\u{4cd}', ['\u{4ce}', '\0', '\0']), ('\u{4d0}', ['\u{4d1}',
+ '\0', '\0']), ('\u{4d2}', ['\u{4d3}', '\0', '\0']), ('\u{4d4}', ['\u{4d5}', '\0', '\0']),
+ ('\u{4d6}', ['\u{4d7}', '\0', '\0']), ('\u{4d8}', ['\u{4d9}', '\0', '\0']), ('\u{4da}',
+ ['\u{4db}', '\0', '\0']), ('\u{4dc}', ['\u{4dd}', '\0', '\0']), ('\u{4de}', ['\u{4df}',
+ '\0', '\0']), ('\u{4e0}', ['\u{4e1}', '\0', '\0']), ('\u{4e2}', ['\u{4e3}', '\0', '\0']),
+ ('\u{4e4}', ['\u{4e5}', '\0', '\0']), ('\u{4e6}', ['\u{4e7}', '\0', '\0']), ('\u{4e8}',
+ ['\u{4e9}', '\0', '\0']), ('\u{4ea}', ['\u{4eb}', '\0', '\0']), ('\u{4ec}', ['\u{4ed}',
+ '\0', '\0']), ('\u{4ee}', ['\u{4ef}', '\0', '\0']), ('\u{4f0}', ['\u{4f1}', '\0', '\0']),
+ ('\u{4f2}', ['\u{4f3}', '\0', '\0']), ('\u{4f4}', ['\u{4f5}', '\0', '\0']), ('\u{4f6}',
+ ['\u{4f7}', '\0', '\0']), ('\u{4f8}', ['\u{4f9}', '\0', '\0']), ('\u{4fa}', ['\u{4fb}',
+ '\0', '\0']), ('\u{4fc}', ['\u{4fd}', '\0', '\0']), ('\u{4fe}', ['\u{4ff}', '\0', '\0']),
+ ('\u{500}', ['\u{501}', '\0', '\0']), ('\u{502}', ['\u{503}', '\0', '\0']), ('\u{504}',
+ ['\u{505}', '\0', '\0']), ('\u{506}', ['\u{507}', '\0', '\0']), ('\u{508}', ['\u{509}',
+ '\0', '\0']), ('\u{50a}', ['\u{50b}', '\0', '\0']), ('\u{50c}', ['\u{50d}', '\0', '\0']),
+ ('\u{50e}', ['\u{50f}', '\0', '\0']), ('\u{510}', ['\u{511}', '\0', '\0']), ('\u{512}',
+ ['\u{513}', '\0', '\0']), ('\u{514}', ['\u{515}', '\0', '\0']), ('\u{516}', ['\u{517}',
+ '\0', '\0']), ('\u{518}', ['\u{519}', '\0', '\0']), ('\u{51a}', ['\u{51b}', '\0', '\0']),
+ ('\u{51c}', ['\u{51d}', '\0', '\0']), ('\u{51e}', ['\u{51f}', '\0', '\0']), ('\u{520}',
+ ['\u{521}', '\0', '\0']), ('\u{522}', ['\u{523}', '\0', '\0']), ('\u{524}', ['\u{525}',
+ '\0', '\0']), ('\u{526}', ['\u{527}', '\0', '\0']), ('\u{528}', ['\u{529}', '\0', '\0']),
+ ('\u{52a}', ['\u{52b}', '\0', '\0']), ('\u{52c}', ['\u{52d}', '\0', '\0']), ('\u{52e}',
+ ['\u{52f}', '\0', '\0']), ('\u{531}', ['\u{561}', '\0', '\0']), ('\u{532}', ['\u{562}',
+ '\0', '\0']), ('\u{533}', ['\u{563}', '\0', '\0']), ('\u{534}', ['\u{564}', '\0', '\0']),
+ ('\u{535}', ['\u{565}', '\0', '\0']), ('\u{536}', ['\u{566}', '\0', '\0']), ('\u{537}',
+ ['\u{567}', '\0', '\0']), ('\u{538}', ['\u{568}', '\0', '\0']), ('\u{539}', ['\u{569}',
+ '\0', '\0']), ('\u{53a}', ['\u{56a}', '\0', '\0']), ('\u{53b}', ['\u{56b}', '\0', '\0']),
+ ('\u{53c}', ['\u{56c}', '\0', '\0']), ('\u{53d}', ['\u{56d}', '\0', '\0']), ('\u{53e}',
+ ['\u{56e}', '\0', '\0']), ('\u{53f}', ['\u{56f}', '\0', '\0']), ('\u{540}', ['\u{570}',
+ '\0', '\0']), ('\u{541}', ['\u{571}', '\0', '\0']), ('\u{542}', ['\u{572}', '\0', '\0']),
+ ('\u{543}', ['\u{573}', '\0', '\0']), ('\u{544}', ['\u{574}', '\0', '\0']), ('\u{545}',
+ ['\u{575}', '\0', '\0']), ('\u{546}', ['\u{576}', '\0', '\0']), ('\u{547}', ['\u{577}',
+ '\0', '\0']), ('\u{548}', ['\u{578}', '\0', '\0']), ('\u{549}', ['\u{579}', '\0', '\0']),
+ ('\u{54a}', ['\u{57a}', '\0', '\0']), ('\u{54b}', ['\u{57b}', '\0', '\0']), ('\u{54c}',
+ ['\u{57c}', '\0', '\0']), ('\u{54d}', ['\u{57d}', '\0', '\0']), ('\u{54e}', ['\u{57e}',
+ '\0', '\0']), ('\u{54f}', ['\u{57f}', '\0', '\0']), ('\u{550}', ['\u{580}', '\0', '\0']),
+ ('\u{551}', ['\u{581}', '\0', '\0']), ('\u{552}', ['\u{582}', '\0', '\0']), ('\u{553}',
+ ['\u{583}', '\0', '\0']), ('\u{554}', ['\u{584}', '\0', '\0']), ('\u{555}', ['\u{585}',
+ '\0', '\0']), ('\u{556}', ['\u{586}', '\0', '\0']), ('\u{10a0}', ['\u{2d00}', '\0', '\0']),
+ ('\u{10a1}', ['\u{2d01}', '\0', '\0']), ('\u{10a2}', ['\u{2d02}', '\0', '\0']), ('\u{10a3}',
+ ['\u{2d03}', '\0', '\0']), ('\u{10a4}', ['\u{2d04}', '\0', '\0']), ('\u{10a5}', ['\u{2d05}',
+ '\0', '\0']), ('\u{10a6}', ['\u{2d06}', '\0', '\0']), ('\u{10a7}', ['\u{2d07}', '\0',
+ '\0']), ('\u{10a8}', ['\u{2d08}', '\0', '\0']), ('\u{10a9}', ['\u{2d09}', '\0', '\0']),
+ ('\u{10aa}', ['\u{2d0a}', '\0', '\0']), ('\u{10ab}', ['\u{2d0b}', '\0', '\0']), ('\u{10ac}',
+ ['\u{2d0c}', '\0', '\0']), ('\u{10ad}', ['\u{2d0d}', '\0', '\0']), ('\u{10ae}', ['\u{2d0e}',
+ '\0', '\0']), ('\u{10af}', ['\u{2d0f}', '\0', '\0']), ('\u{10b0}', ['\u{2d10}', '\0',
+ '\0']), ('\u{10b1}', ['\u{2d11}', '\0', '\0']), ('\u{10b2}', ['\u{2d12}', '\0', '\0']),
+ ('\u{10b3}', ['\u{2d13}', '\0', '\0']), ('\u{10b4}', ['\u{2d14}', '\0', '\0']), ('\u{10b5}',
+ ['\u{2d15}', '\0', '\0']), ('\u{10b6}', ['\u{2d16}', '\0', '\0']), ('\u{10b7}', ['\u{2d17}',
+ '\0', '\0']), ('\u{10b8}', ['\u{2d18}', '\0', '\0']), ('\u{10b9}', ['\u{2d19}', '\0',
+ '\0']), ('\u{10ba}', ['\u{2d1a}', '\0', '\0']), ('\u{10bb}', ['\u{2d1b}', '\0', '\0']),
+ ('\u{10bc}', ['\u{2d1c}', '\0', '\0']), ('\u{10bd}', ['\u{2d1d}', '\0', '\0']), ('\u{10be}',
+ ['\u{2d1e}', '\0', '\0']), ('\u{10bf}', ['\u{2d1f}', '\0', '\0']), ('\u{10c0}', ['\u{2d20}',
+ '\0', '\0']), ('\u{10c1}', ['\u{2d21}', '\0', '\0']), ('\u{10c2}', ['\u{2d22}', '\0',
+ '\0']), ('\u{10c3}', ['\u{2d23}', '\0', '\0']), ('\u{10c4}', ['\u{2d24}', '\0', '\0']),
+ ('\u{10c5}', ['\u{2d25}', '\0', '\0']), ('\u{10c7}', ['\u{2d27}', '\0', '\0']), ('\u{10cd}',
+ ['\u{2d2d}', '\0', '\0']), ('\u{1e00}', ['\u{1e01}', '\0', '\0']), ('\u{1e02}', ['\u{1e03}',
+ '\0', '\0']), ('\u{1e04}', ['\u{1e05}', '\0', '\0']), ('\u{1e06}', ['\u{1e07}', '\0',
+ '\0']), ('\u{1e08}', ['\u{1e09}', '\0', '\0']), ('\u{1e0a}', ['\u{1e0b}', '\0', '\0']),
+ ('\u{1e0c}', ['\u{1e0d}', '\0', '\0']), ('\u{1e0e}', ['\u{1e0f}', '\0', '\0']), ('\u{1e10}',
+ ['\u{1e11}', '\0', '\0']), ('\u{1e12}', ['\u{1e13}', '\0', '\0']), ('\u{1e14}', ['\u{1e15}',
+ '\0', '\0']), ('\u{1e16}', ['\u{1e17}', '\0', '\0']), ('\u{1e18}', ['\u{1e19}', '\0',
+ '\0']), ('\u{1e1a}', ['\u{1e1b}', '\0', '\0']), ('\u{1e1c}', ['\u{1e1d}', '\0', '\0']),
+ ('\u{1e1e}', ['\u{1e1f}', '\0', '\0']), ('\u{1e20}', ['\u{1e21}', '\0', '\0']), ('\u{1e22}',
+ ['\u{1e23}', '\0', '\0']), ('\u{1e24}', ['\u{1e25}', '\0', '\0']), ('\u{1e26}', ['\u{1e27}',
+ '\0', '\0']), ('\u{1e28}', ['\u{1e29}', '\0', '\0']), ('\u{1e2a}', ['\u{1e2b}', '\0',
+ '\0']), ('\u{1e2c}', ['\u{1e2d}', '\0', '\0']), ('\u{1e2e}', ['\u{1e2f}', '\0', '\0']),
+ ('\u{1e30}', ['\u{1e31}', '\0', '\0']), ('\u{1e32}', ['\u{1e33}', '\0', '\0']), ('\u{1e34}',
+ ['\u{1e35}', '\0', '\0']), ('\u{1e36}', ['\u{1e37}', '\0', '\0']), ('\u{1e38}', ['\u{1e39}',
+ '\0', '\0']), ('\u{1e3a}', ['\u{1e3b}', '\0', '\0']), ('\u{1e3c}', ['\u{1e3d}', '\0',
+ '\0']), ('\u{1e3e}', ['\u{1e3f}', '\0', '\0']), ('\u{1e40}', ['\u{1e41}', '\0', '\0']),
+ ('\u{1e42}', ['\u{1e43}', '\0', '\0']), ('\u{1e44}', ['\u{1e45}', '\0', '\0']), ('\u{1e46}',
+ ['\u{1e47}', '\0', '\0']), ('\u{1e48}', ['\u{1e49}', '\0', '\0']), ('\u{1e4a}', ['\u{1e4b}',
+ '\0', '\0']), ('\u{1e4c}', ['\u{1e4d}', '\0', '\0']), ('\u{1e4e}', ['\u{1e4f}', '\0',
+ '\0']), ('\u{1e50}', ['\u{1e51}', '\0', '\0']), ('\u{1e52}', ['\u{1e53}', '\0', '\0']),
+ ('\u{1e54}', ['\u{1e55}', '\0', '\0']), ('\u{1e56}', ['\u{1e57}', '\0', '\0']), ('\u{1e58}',
+ ['\u{1e59}', '\0', '\0']), ('\u{1e5a}', ['\u{1e5b}', '\0', '\0']), ('\u{1e5c}', ['\u{1e5d}',
+ '\0', '\0']), ('\u{1e5e}', ['\u{1e5f}', '\0', '\0']), ('\u{1e60}', ['\u{1e61}', '\0',
+ '\0']), ('\u{1e62}', ['\u{1e63}', '\0', '\0']), ('\u{1e64}', ['\u{1e65}', '\0', '\0']),
+ ('\u{1e66}', ['\u{1e67}', '\0', '\0']), ('\u{1e68}', ['\u{1e69}', '\0', '\0']), ('\u{1e6a}',
+ ['\u{1e6b}', '\0', '\0']), ('\u{1e6c}', ['\u{1e6d}', '\0', '\0']), ('\u{1e6e}', ['\u{1e6f}',
+ '\0', '\0']), ('\u{1e70}', ['\u{1e71}', '\0', '\0']), ('\u{1e72}', ['\u{1e73}', '\0',
+ '\0']), ('\u{1e74}', ['\u{1e75}', '\0', '\0']), ('\u{1e76}', ['\u{1e77}', '\0', '\0']),
+ ('\u{1e78}', ['\u{1e79}', '\0', '\0']), ('\u{1e7a}', ['\u{1e7b}', '\0', '\0']), ('\u{1e7c}',
+ ['\u{1e7d}', '\0', '\0']), ('\u{1e7e}', ['\u{1e7f}', '\0', '\0']), ('\u{1e80}', ['\u{1e81}',
+ '\0', '\0']), ('\u{1e82}', ['\u{1e83}', '\0', '\0']), ('\u{1e84}', ['\u{1e85}', '\0',
+ '\0']), ('\u{1e86}', ['\u{1e87}', '\0', '\0']), ('\u{1e88}', ['\u{1e89}', '\0', '\0']),
+ ('\u{1e8a}', ['\u{1e8b}', '\0', '\0']), ('\u{1e8c}', ['\u{1e8d}', '\0', '\0']), ('\u{1e8e}',
+ ['\u{1e8f}', '\0', '\0']), ('\u{1e90}', ['\u{1e91}', '\0', '\0']), ('\u{1e92}', ['\u{1e93}',
+ '\0', '\0']), ('\u{1e94}', ['\u{1e95}', '\0', '\0']), ('\u{1e9e}', ['\u{df}', '\0', '\0']),
+ ('\u{1ea0}', ['\u{1ea1}', '\0', '\0']), ('\u{1ea2}', ['\u{1ea3}', '\0', '\0']), ('\u{1ea4}',
+ ['\u{1ea5}', '\0', '\0']), ('\u{1ea6}', ['\u{1ea7}', '\0', '\0']), ('\u{1ea8}', ['\u{1ea9}',
+ '\0', '\0']), ('\u{1eaa}', ['\u{1eab}', '\0', '\0']), ('\u{1eac}', ['\u{1ead}', '\0',
+ '\0']), ('\u{1eae}', ['\u{1eaf}', '\0', '\0']), ('\u{1eb0}', ['\u{1eb1}', '\0', '\0']),
+ ('\u{1eb2}', ['\u{1eb3}', '\0', '\0']), ('\u{1eb4}', ['\u{1eb5}', '\0', '\0']), ('\u{1eb6}',
+ ['\u{1eb7}', '\0', '\0']), ('\u{1eb8}', ['\u{1eb9}', '\0', '\0']), ('\u{1eba}', ['\u{1ebb}',
+ '\0', '\0']), ('\u{1ebc}', ['\u{1ebd}', '\0', '\0']), ('\u{1ebe}', ['\u{1ebf}', '\0',
+ '\0']), ('\u{1ec0}', ['\u{1ec1}', '\0', '\0']), ('\u{1ec2}', ['\u{1ec3}', '\0', '\0']),
+ ('\u{1ec4}', ['\u{1ec5}', '\0', '\0']), ('\u{1ec6}', ['\u{1ec7}', '\0', '\0']), ('\u{1ec8}',
+ ['\u{1ec9}', '\0', '\0']), ('\u{1eca}', ['\u{1ecb}', '\0', '\0']), ('\u{1ecc}', ['\u{1ecd}',
+ '\0', '\0']), ('\u{1ece}', ['\u{1ecf}', '\0', '\0']), ('\u{1ed0}', ['\u{1ed1}', '\0',
+ '\0']), ('\u{1ed2}', ['\u{1ed3}', '\0', '\0']), ('\u{1ed4}', ['\u{1ed5}', '\0', '\0']),
+ ('\u{1ed6}', ['\u{1ed7}', '\0', '\0']), ('\u{1ed8}', ['\u{1ed9}', '\0', '\0']), ('\u{1eda}',
+ ['\u{1edb}', '\0', '\0']), ('\u{1edc}', ['\u{1edd}', '\0', '\0']), ('\u{1ede}', ['\u{1edf}',
+ '\0', '\0']), ('\u{1ee0}', ['\u{1ee1}', '\0', '\0']), ('\u{1ee2}', ['\u{1ee3}', '\0',
+ '\0']), ('\u{1ee4}', ['\u{1ee5}', '\0', '\0']), ('\u{1ee6}', ['\u{1ee7}', '\0', '\0']),
+ ('\u{1ee8}', ['\u{1ee9}', '\0', '\0']), ('\u{1eea}', ['\u{1eeb}', '\0', '\0']), ('\u{1eec}',
+ ['\u{1eed}', '\0', '\0']), ('\u{1eee}', ['\u{1eef}', '\0', '\0']), ('\u{1ef0}', ['\u{1ef1}',
+ '\0', '\0']), ('\u{1ef2}', ['\u{1ef3}', '\0', '\0']), ('\u{1ef4}', ['\u{1ef5}', '\0',
+ '\0']), ('\u{1ef6}', ['\u{1ef7}', '\0', '\0']), ('\u{1ef8}', ['\u{1ef9}', '\0', '\0']),
+ ('\u{1efa}', ['\u{1efb}', '\0', '\0']), ('\u{1efc}', ['\u{1efd}', '\0', '\0']), ('\u{1efe}',
+ ['\u{1eff}', '\0', '\0']), ('\u{1f08}', ['\u{1f00}', '\0', '\0']), ('\u{1f09}', ['\u{1f01}',
+ '\0', '\0']), ('\u{1f0a}', ['\u{1f02}', '\0', '\0']), ('\u{1f0b}', ['\u{1f03}', '\0',
+ '\0']), ('\u{1f0c}', ['\u{1f04}', '\0', '\0']), ('\u{1f0d}', ['\u{1f05}', '\0', '\0']),
+ ('\u{1f0e}', ['\u{1f06}', '\0', '\0']), ('\u{1f0f}', ['\u{1f07}', '\0', '\0']), ('\u{1f18}',
+ ['\u{1f10}', '\0', '\0']), ('\u{1f19}', ['\u{1f11}', '\0', '\0']), ('\u{1f1a}', ['\u{1f12}',
+ '\0', '\0']), ('\u{1f1b}', ['\u{1f13}', '\0', '\0']), ('\u{1f1c}', ['\u{1f14}', '\0',
+ '\0']), ('\u{1f1d}', ['\u{1f15}', '\0', '\0']), ('\u{1f28}', ['\u{1f20}', '\0', '\0']),
+ ('\u{1f29}', ['\u{1f21}', '\0', '\0']), ('\u{1f2a}', ['\u{1f22}', '\0', '\0']), ('\u{1f2b}',
+ ['\u{1f23}', '\0', '\0']), ('\u{1f2c}', ['\u{1f24}', '\0', '\0']), ('\u{1f2d}', ['\u{1f25}',
+ '\0', '\0']), ('\u{1f2e}', ['\u{1f26}', '\0', '\0']), ('\u{1f2f}', ['\u{1f27}', '\0',
+ '\0']), ('\u{1f38}', ['\u{1f30}', '\0', '\0']), ('\u{1f39}', ['\u{1f31}', '\0', '\0']),
+ ('\u{1f3a}', ['\u{1f32}', '\0', '\0']), ('\u{1f3b}', ['\u{1f33}', '\0', '\0']), ('\u{1f3c}',
+ ['\u{1f34}', '\0', '\0']), ('\u{1f3d}', ['\u{1f35}', '\0', '\0']), ('\u{1f3e}', ['\u{1f36}',
+ '\0', '\0']), ('\u{1f3f}', ['\u{1f37}', '\0', '\0']), ('\u{1f48}', ['\u{1f40}', '\0',
+ '\0']), ('\u{1f49}', ['\u{1f41}', '\0', '\0']), ('\u{1f4a}', ['\u{1f42}', '\0', '\0']),
+ ('\u{1f4b}', ['\u{1f43}', '\0', '\0']), ('\u{1f4c}', ['\u{1f44}', '\0', '\0']), ('\u{1f4d}',
+ ['\u{1f45}', '\0', '\0']), ('\u{1f59}', ['\u{1f51}', '\0', '\0']), ('\u{1f5b}', ['\u{1f53}',
+ '\0', '\0']), ('\u{1f5d}', ['\u{1f55}', '\0', '\0']), ('\u{1f5f}', ['\u{1f57}', '\0',
+ '\0']), ('\u{1f68}', ['\u{1f60}', '\0', '\0']), ('\u{1f69}', ['\u{1f61}', '\0', '\0']),
+ ('\u{1f6a}', ['\u{1f62}', '\0', '\0']), ('\u{1f6b}', ['\u{1f63}', '\0', '\0']), ('\u{1f6c}',
+ ['\u{1f64}', '\0', '\0']), ('\u{1f6d}', ['\u{1f65}', '\0', '\0']), ('\u{1f6e}', ['\u{1f66}',
+ '\0', '\0']), ('\u{1f6f}', ['\u{1f67}', '\0', '\0']), ('\u{1f88}', ['\u{1f80}', '\0',
+ '\0']), ('\u{1f89}', ['\u{1f81}', '\0', '\0']), ('\u{1f8a}', ['\u{1f82}', '\0', '\0']),
+ ('\u{1f8b}', ['\u{1f83}', '\0', '\0']), ('\u{1f8c}', ['\u{1f84}', '\0', '\0']), ('\u{1f8d}',
+ ['\u{1f85}', '\0', '\0']), ('\u{1f8e}', ['\u{1f86}', '\0', '\0']), ('\u{1f8f}', ['\u{1f87}',
+ '\0', '\0']), ('\u{1f98}', ['\u{1f90}', '\0', '\0']), ('\u{1f99}', ['\u{1f91}', '\0',
+ '\0']), ('\u{1f9a}', ['\u{1f92}', '\0', '\0']), ('\u{1f9b}', ['\u{1f93}', '\0', '\0']),
+ ('\u{1f9c}', ['\u{1f94}', '\0', '\0']), ('\u{1f9d}', ['\u{1f95}', '\0', '\0']), ('\u{1f9e}',
+ ['\u{1f96}', '\0', '\0']), ('\u{1f9f}', ['\u{1f97}', '\0', '\0']), ('\u{1fa8}', ['\u{1fa0}',
+ '\0', '\0']), ('\u{1fa9}', ['\u{1fa1}', '\0', '\0']), ('\u{1faa}', ['\u{1fa2}', '\0',
+ '\0']), ('\u{1fab}', ['\u{1fa3}', '\0', '\0']), ('\u{1fac}', ['\u{1fa4}', '\0', '\0']),
+ ('\u{1fad}', ['\u{1fa5}', '\0', '\0']), ('\u{1fae}', ['\u{1fa6}', '\0', '\0']), ('\u{1faf}',
+ ['\u{1fa7}', '\0', '\0']), ('\u{1fb8}', ['\u{1fb0}', '\0', '\0']), ('\u{1fb9}', ['\u{1fb1}',
+ '\0', '\0']), ('\u{1fba}', ['\u{1f70}', '\0', '\0']), ('\u{1fbb}', ['\u{1f71}', '\0',
+ '\0']), ('\u{1fbc}', ['\u{1fb3}', '\0', '\0']), ('\u{1fc8}', ['\u{1f72}', '\0', '\0']),
+ ('\u{1fc9}', ['\u{1f73}', '\0', '\0']), ('\u{1fca}', ['\u{1f74}', '\0', '\0']), ('\u{1fcb}',
+ ['\u{1f75}', '\0', '\0']), ('\u{1fcc}', ['\u{1fc3}', '\0', '\0']), ('\u{1fd8}', ['\u{1fd0}',
+ '\0', '\0']), ('\u{1fd9}', ['\u{1fd1}', '\0', '\0']), ('\u{1fda}', ['\u{1f76}', '\0',
+ '\0']), ('\u{1fdb}', ['\u{1f77}', '\0', '\0']), ('\u{1fe8}', ['\u{1fe0}', '\0', '\0']),
+ ('\u{1fe9}', ['\u{1fe1}', '\0', '\0']), ('\u{1fea}', ['\u{1f7a}', '\0', '\0']), ('\u{1feb}',
+ ['\u{1f7b}', '\0', '\0']), ('\u{1fec}', ['\u{1fe5}', '\0', '\0']), ('\u{1ff8}', ['\u{1f78}',
+ '\0', '\0']), ('\u{1ff9}', ['\u{1f79}', '\0', '\0']), ('\u{1ffa}', ['\u{1f7c}', '\0',
+ '\0']), ('\u{1ffb}', ['\u{1f7d}', '\0', '\0']), ('\u{1ffc}', ['\u{1ff3}', '\0', '\0']),
+ ('\u{2126}', ['\u{3c9}', '\0', '\0']), ('\u{212a}', ['\u{6b}', '\0', '\0']), ('\u{212b}',
+ ['\u{e5}', '\0', '\0']), ('\u{2132}', ['\u{214e}', '\0', '\0']), ('\u{2160}', ['\u{2170}',
+ '\0', '\0']), ('\u{2161}', ['\u{2171}', '\0', '\0']), ('\u{2162}', ['\u{2172}', '\0',
+ '\0']), ('\u{2163}', ['\u{2173}', '\0', '\0']), ('\u{2164}', ['\u{2174}', '\0', '\0']),
+ ('\u{2165}', ['\u{2175}', '\0', '\0']), ('\u{2166}', ['\u{2176}', '\0', '\0']), ('\u{2167}',
+ ['\u{2177}', '\0', '\0']), ('\u{2168}', ['\u{2178}', '\0', '\0']), ('\u{2169}', ['\u{2179}',
+ '\0', '\0']), ('\u{216a}', ['\u{217a}', '\0', '\0']), ('\u{216b}', ['\u{217b}', '\0',
+ '\0']), ('\u{216c}', ['\u{217c}', '\0', '\0']), ('\u{216d}', ['\u{217d}', '\0', '\0']),
+ ('\u{216e}', ['\u{217e}', '\0', '\0']), ('\u{216f}', ['\u{217f}', '\0', '\0']), ('\u{2183}',
+ ['\u{2184}', '\0', '\0']), ('\u{24b6}', ['\u{24d0}', '\0', '\0']), ('\u{24b7}', ['\u{24d1}',
+ '\0', '\0']), ('\u{24b8}', ['\u{24d2}', '\0', '\0']), ('\u{24b9}', ['\u{24d3}', '\0',
+ '\0']), ('\u{24ba}', ['\u{24d4}', '\0', '\0']), ('\u{24bb}', ['\u{24d5}', '\0', '\0']),
+ ('\u{24bc}', ['\u{24d6}', '\0', '\0']), ('\u{24bd}', ['\u{24d7}', '\0', '\0']), ('\u{24be}',
+ ['\u{24d8}', '\0', '\0']), ('\u{24bf}', ['\u{24d9}', '\0', '\0']), ('\u{24c0}', ['\u{24da}',
+ '\0', '\0']), ('\u{24c1}', ['\u{24db}', '\0', '\0']), ('\u{24c2}', ['\u{24dc}', '\0',
+ '\0']), ('\u{24c3}', ['\u{24dd}', '\0', '\0']), ('\u{24c4}', ['\u{24de}', '\0', '\0']),
+ ('\u{24c5}', ['\u{24df}', '\0', '\0']), ('\u{24c6}', ['\u{24e0}', '\0', '\0']), ('\u{24c7}',
+ ['\u{24e1}', '\0', '\0']), ('\u{24c8}', ['\u{24e2}', '\0', '\0']), ('\u{24c9}', ['\u{24e3}',
+ '\0', '\0']), ('\u{24ca}', ['\u{24e4}', '\0', '\0']), ('\u{24cb}', ['\u{24e5}', '\0',
+ '\0']), ('\u{24cc}', ['\u{24e6}', '\0', '\0']), ('\u{24cd}', ['\u{24e7}', '\0', '\0']),
+ ('\u{24ce}', ['\u{24e8}', '\0', '\0']), ('\u{24cf}', ['\u{24e9}', '\0', '\0']), ('\u{2c00}',
+ ['\u{2c30}', '\0', '\0']), ('\u{2c01}', ['\u{2c31}', '\0', '\0']), ('\u{2c02}', ['\u{2c32}',
+ '\0', '\0']), ('\u{2c03}', ['\u{2c33}', '\0', '\0']), ('\u{2c04}', ['\u{2c34}', '\0',
+ '\0']), ('\u{2c05}', ['\u{2c35}', '\0', '\0']), ('\u{2c06}', ['\u{2c36}', '\0', '\0']),
+ ('\u{2c07}', ['\u{2c37}', '\0', '\0']), ('\u{2c08}', ['\u{2c38}', '\0', '\0']), ('\u{2c09}',
+ ['\u{2c39}', '\0', '\0']), ('\u{2c0a}', ['\u{2c3a}', '\0', '\0']), ('\u{2c0b}', ['\u{2c3b}',
+ '\0', '\0']), ('\u{2c0c}', ['\u{2c3c}', '\0', '\0']), ('\u{2c0d}', ['\u{2c3d}', '\0',
+ '\0']), ('\u{2c0e}', ['\u{2c3e}', '\0', '\0']), ('\u{2c0f}', ['\u{2c3f}', '\0', '\0']),
+ ('\u{2c10}', ['\u{2c40}', '\0', '\0']), ('\u{2c11}', ['\u{2c41}', '\0', '\0']), ('\u{2c12}',
+ ['\u{2c42}', '\0', '\0']), ('\u{2c13}', ['\u{2c43}', '\0', '\0']), ('\u{2c14}', ['\u{2c44}',
+ '\0', '\0']), ('\u{2c15}', ['\u{2c45}', '\0', '\0']), ('\u{2c16}', ['\u{2c46}', '\0',
+ '\0']), ('\u{2c17}', ['\u{2c47}', '\0', '\0']), ('\u{2c18}', ['\u{2c48}', '\0', '\0']),
+ ('\u{2c19}', ['\u{2c49}', '\0', '\0']), ('\u{2c1a}', ['\u{2c4a}', '\0', '\0']), ('\u{2c1b}',
+ ['\u{2c4b}', '\0', '\0']), ('\u{2c1c}', ['\u{2c4c}', '\0', '\0']), ('\u{2c1d}', ['\u{2c4d}',
+ '\0', '\0']), ('\u{2c1e}', ['\u{2c4e}', '\0', '\0']), ('\u{2c1f}', ['\u{2c4f}', '\0',
+ '\0']), ('\u{2c20}', ['\u{2c50}', '\0', '\0']), ('\u{2c21}', ['\u{2c51}', '\0', '\0']),
+ ('\u{2c22}', ['\u{2c52}', '\0', '\0']), ('\u{2c23}', ['\u{2c53}', '\0', '\0']), ('\u{2c24}',
+ ['\u{2c54}', '\0', '\0']), ('\u{2c25}', ['\u{2c55}', '\0', '\0']), ('\u{2c26}', ['\u{2c56}',
+ '\0', '\0']), ('\u{2c27}', ['\u{2c57}', '\0', '\0']), ('\u{2c28}', ['\u{2c58}', '\0',
+ '\0']), ('\u{2c29}', ['\u{2c59}', '\0', '\0']), ('\u{2c2a}', ['\u{2c5a}', '\0', '\0']),
+ ('\u{2c2b}', ['\u{2c5b}', '\0', '\0']), ('\u{2c2c}', ['\u{2c5c}', '\0', '\0']), ('\u{2c2d}',
+ ['\u{2c5d}', '\0', '\0']), ('\u{2c2e}', ['\u{2c5e}', '\0', '\0']), ('\u{2c60}', ['\u{2c61}',
+ '\0', '\0']), ('\u{2c62}', ['\u{26b}', '\0', '\0']), ('\u{2c63}', ['\u{1d7d}', '\0', '\0']),
+ ('\u{2c64}', ['\u{27d}', '\0', '\0']), ('\u{2c67}', ['\u{2c68}', '\0', '\0']), ('\u{2c69}',
+ ['\u{2c6a}', '\0', '\0']), ('\u{2c6b}', ['\u{2c6c}', '\0', '\0']), ('\u{2c6d}', ['\u{251}',
+ '\0', '\0']), ('\u{2c6e}', ['\u{271}', '\0', '\0']), ('\u{2c6f}', ['\u{250}', '\0', '\0']),
+ ('\u{2c70}', ['\u{252}', '\0', '\0']), ('\u{2c72}', ['\u{2c73}', '\0', '\0']), ('\u{2c75}',
+ ['\u{2c76}', '\0', '\0']), ('\u{2c7e}', ['\u{23f}', '\0', '\0']), ('\u{2c7f}', ['\u{240}',
+ '\0', '\0']), ('\u{2c80}', ['\u{2c81}', '\0', '\0']), ('\u{2c82}', ['\u{2c83}', '\0',
+ '\0']), ('\u{2c84}', ['\u{2c85}', '\0', '\0']), ('\u{2c86}', ['\u{2c87}', '\0', '\0']),
+ ('\u{2c88}', ['\u{2c89}', '\0', '\0']), ('\u{2c8a}', ['\u{2c8b}', '\0', '\0']), ('\u{2c8c}',
+ ['\u{2c8d}', '\0', '\0']), ('\u{2c8e}', ['\u{2c8f}', '\0', '\0']), ('\u{2c90}', ['\u{2c91}',
+ '\0', '\0']), ('\u{2c92}', ['\u{2c93}', '\0', '\0']), ('\u{2c94}', ['\u{2c95}', '\0',
+ '\0']), ('\u{2c96}', ['\u{2c97}', '\0', '\0']), ('\u{2c98}', ['\u{2c99}', '\0', '\0']),
+ ('\u{2c9a}', ['\u{2c9b}', '\0', '\0']), ('\u{2c9c}', ['\u{2c9d}', '\0', '\0']), ('\u{2c9e}',
+ ['\u{2c9f}', '\0', '\0']), ('\u{2ca0}', ['\u{2ca1}', '\0', '\0']), ('\u{2ca2}', ['\u{2ca3}',
+ '\0', '\0']), ('\u{2ca4}', ['\u{2ca5}', '\0', '\0']), ('\u{2ca6}', ['\u{2ca7}', '\0',
+ '\0']), ('\u{2ca8}', ['\u{2ca9}', '\0', '\0']), ('\u{2caa}', ['\u{2cab}', '\0', '\0']),
+ ('\u{2cac}', ['\u{2cad}', '\0', '\0']), ('\u{2cae}', ['\u{2caf}', '\0', '\0']), ('\u{2cb0}',
+ ['\u{2cb1}', '\0', '\0']), ('\u{2cb2}', ['\u{2cb3}', '\0', '\0']), ('\u{2cb4}', ['\u{2cb5}',
+ '\0', '\0']), ('\u{2cb6}', ['\u{2cb7}', '\0', '\0']), ('\u{2cb8}', ['\u{2cb9}', '\0',
+ '\0']), ('\u{2cba}', ['\u{2cbb}', '\0', '\0']), ('\u{2cbc}', ['\u{2cbd}', '\0', '\0']),
+ ('\u{2cbe}', ['\u{2cbf}', '\0', '\0']), ('\u{2cc0}', ['\u{2cc1}', '\0', '\0']), ('\u{2cc2}',
+ ['\u{2cc3}', '\0', '\0']), ('\u{2cc4}', ['\u{2cc5}', '\0', '\0']), ('\u{2cc6}', ['\u{2cc7}',
+ '\0', '\0']), ('\u{2cc8}', ['\u{2cc9}', '\0', '\0']), ('\u{2cca}', ['\u{2ccb}', '\0',
+ '\0']), ('\u{2ccc}', ['\u{2ccd}', '\0', '\0']), ('\u{2cce}', ['\u{2ccf}', '\0', '\0']),
+ ('\u{2cd0}', ['\u{2cd1}', '\0', '\0']), ('\u{2cd2}', ['\u{2cd3}', '\0', '\0']), ('\u{2cd4}',
+ ['\u{2cd5}', '\0', '\0']), ('\u{2cd6}', ['\u{2cd7}', '\0', '\0']), ('\u{2cd8}', ['\u{2cd9}',
+ '\0', '\0']), ('\u{2cda}', ['\u{2cdb}', '\0', '\0']), ('\u{2cdc}', ['\u{2cdd}', '\0',
+ '\0']), ('\u{2cde}', ['\u{2cdf}', '\0', '\0']), ('\u{2ce0}', ['\u{2ce1}', '\0', '\0']),
+ ('\u{2ce2}', ['\u{2ce3}', '\0', '\0']), ('\u{2ceb}', ['\u{2cec}', '\0', '\0']), ('\u{2ced}',
+ ['\u{2cee}', '\0', '\0']), ('\u{2cf2}', ['\u{2cf3}', '\0', '\0']), ('\u{a640}', ['\u{a641}',
+ '\0', '\0']), ('\u{a642}', ['\u{a643}', '\0', '\0']), ('\u{a644}', ['\u{a645}', '\0',
+ '\0']), ('\u{a646}', ['\u{a647}', '\0', '\0']), ('\u{a648}', ['\u{a649}', '\0', '\0']),
+ ('\u{a64a}', ['\u{a64b}', '\0', '\0']), ('\u{a64c}', ['\u{a64d}', '\0', '\0']), ('\u{a64e}',
+ ['\u{a64f}', '\0', '\0']), ('\u{a650}', ['\u{a651}', '\0', '\0']), ('\u{a652}', ['\u{a653}',
+ '\0', '\0']), ('\u{a654}', ['\u{a655}', '\0', '\0']), ('\u{a656}', ['\u{a657}', '\0',
+ '\0']), ('\u{a658}', ['\u{a659}', '\0', '\0']), ('\u{a65a}', ['\u{a65b}', '\0', '\0']),
+ ('\u{a65c}', ['\u{a65d}', '\0', '\0']), ('\u{a65e}', ['\u{a65f}', '\0', '\0']), ('\u{a660}',
+ ['\u{a661}', '\0', '\0']), ('\u{a662}', ['\u{a663}', '\0', '\0']), ('\u{a664}', ['\u{a665}',
+ '\0', '\0']), ('\u{a666}', ['\u{a667}', '\0', '\0']), ('\u{a668}', ['\u{a669}', '\0',
+ '\0']), ('\u{a66a}', ['\u{a66b}', '\0', '\0']), ('\u{a66c}', ['\u{a66d}', '\0', '\0']),
+ ('\u{a680}', ['\u{a681}', '\0', '\0']), ('\u{a682}', ['\u{a683}', '\0', '\0']), ('\u{a684}',
+ ['\u{a685}', '\0', '\0']), ('\u{a686}', ['\u{a687}', '\0', '\0']), ('\u{a688}', ['\u{a689}',
+ '\0', '\0']), ('\u{a68a}', ['\u{a68b}', '\0', '\0']), ('\u{a68c}', ['\u{a68d}', '\0',
+ '\0']), ('\u{a68e}', ['\u{a68f}', '\0', '\0']), ('\u{a690}', ['\u{a691}', '\0', '\0']),
+ ('\u{a692}', ['\u{a693}', '\0', '\0']), ('\u{a694}', ['\u{a695}', '\0', '\0']), ('\u{a696}',
+ ['\u{a697}', '\0', '\0']), ('\u{a698}', ['\u{a699}', '\0', '\0']), ('\u{a69a}', ['\u{a69b}',
+ '\0', '\0']), ('\u{a722}', ['\u{a723}', '\0', '\0']), ('\u{a724}', ['\u{a725}', '\0',
+ '\0']), ('\u{a726}', ['\u{a727}', '\0', '\0']), ('\u{a728}', ['\u{a729}', '\0', '\0']),
+ ('\u{a72a}', ['\u{a72b}', '\0', '\0']), ('\u{a72c}', ['\u{a72d}', '\0', '\0']), ('\u{a72e}',
+ ['\u{a72f}', '\0', '\0']), ('\u{a732}', ['\u{a733}', '\0', '\0']), ('\u{a734}', ['\u{a735}',
+ '\0', '\0']), ('\u{a736}', ['\u{a737}', '\0', '\0']), ('\u{a738}', ['\u{a739}', '\0',
+ '\0']), ('\u{a73a}', ['\u{a73b}', '\0', '\0']), ('\u{a73c}', ['\u{a73d}', '\0', '\0']),
+ ('\u{a73e}', ['\u{a73f}', '\0', '\0']), ('\u{a740}', ['\u{a741}', '\0', '\0']), ('\u{a742}',
+ ['\u{a743}', '\0', '\0']), ('\u{a744}', ['\u{a745}', '\0', '\0']), ('\u{a746}', ['\u{a747}',
+ '\0', '\0']), ('\u{a748}', ['\u{a749}', '\0', '\0']), ('\u{a74a}', ['\u{a74b}', '\0',
+ '\0']), ('\u{a74c}', ['\u{a74d}', '\0', '\0']), ('\u{a74e}', ['\u{a74f}', '\0', '\0']),
+ ('\u{a750}', ['\u{a751}', '\0', '\0']), ('\u{a752}', ['\u{a753}', '\0', '\0']), ('\u{a754}',
+ ['\u{a755}', '\0', '\0']), ('\u{a756}', ['\u{a757}', '\0', '\0']), ('\u{a758}', ['\u{a759}',
+ '\0', '\0']), ('\u{a75a}', ['\u{a75b}', '\0', '\0']), ('\u{a75c}', ['\u{a75d}', '\0',
+ '\0']), ('\u{a75e}', ['\u{a75f}', '\0', '\0']), ('\u{a760}', ['\u{a761}', '\0', '\0']),
+ ('\u{a762}', ['\u{a763}', '\0', '\0']), ('\u{a764}', ['\u{a765}', '\0', '\0']), ('\u{a766}',
+ ['\u{a767}', '\0', '\0']), ('\u{a768}', ['\u{a769}', '\0', '\0']), ('\u{a76a}', ['\u{a76b}',
+ '\0', '\0']), ('\u{a76c}', ['\u{a76d}', '\0', '\0']), ('\u{a76e}', ['\u{a76f}', '\0',
+ '\0']), ('\u{a779}', ['\u{a77a}', '\0', '\0']), ('\u{a77b}', ['\u{a77c}', '\0', '\0']),
+ ('\u{a77d}', ['\u{1d79}', '\0', '\0']), ('\u{a77e}', ['\u{a77f}', '\0', '\0']), ('\u{a780}',
+ ['\u{a781}', '\0', '\0']), ('\u{a782}', ['\u{a783}', '\0', '\0']), ('\u{a784}', ['\u{a785}',
+ '\0', '\0']), ('\u{a786}', ['\u{a787}', '\0', '\0']), ('\u{a78b}', ['\u{a78c}', '\0',
+ '\0']), ('\u{a78d}', ['\u{265}', '\0', '\0']), ('\u{a790}', ['\u{a791}', '\0', '\0']),
+ ('\u{a792}', ['\u{a793}', '\0', '\0']), ('\u{a796}', ['\u{a797}', '\0', '\0']), ('\u{a798}',
+ ['\u{a799}', '\0', '\0']), ('\u{a79a}', ['\u{a79b}', '\0', '\0']), ('\u{a79c}', ['\u{a79d}',
+ '\0', '\0']), ('\u{a79e}', ['\u{a79f}', '\0', '\0']), ('\u{a7a0}', ['\u{a7a1}', '\0',
+ '\0']), ('\u{a7a2}', ['\u{a7a3}', '\0', '\0']), ('\u{a7a4}', ['\u{a7a5}', '\0', '\0']),
+ ('\u{a7a6}', ['\u{a7a7}', '\0', '\0']), ('\u{a7a8}', ['\u{a7a9}', '\0', '\0']), ('\u{a7aa}',
+ ['\u{266}', '\0', '\0']), ('\u{a7ab}', ['\u{25c}', '\0', '\0']), ('\u{a7ac}', ['\u{261}',
+ '\0', '\0']), ('\u{a7ad}', ['\u{26c}', '\0', '\0']), ('\u{a7b0}', ['\u{29e}', '\0', '\0']),
+ ('\u{a7b1}', ['\u{287}', '\0', '\0']), ('\u{ff21}', ['\u{ff41}', '\0', '\0']), ('\u{ff22}',
+ ['\u{ff42}', '\0', '\0']), ('\u{ff23}', ['\u{ff43}', '\0', '\0']), ('\u{ff24}', ['\u{ff44}',
+ '\0', '\0']), ('\u{ff25}', ['\u{ff45}', '\0', '\0']), ('\u{ff26}', ['\u{ff46}', '\0',
+ '\0']), ('\u{ff27}', ['\u{ff47}', '\0', '\0']), ('\u{ff28}', ['\u{ff48}', '\0', '\0']),
+ ('\u{ff29}', ['\u{ff49}', '\0', '\0']), ('\u{ff2a}', ['\u{ff4a}', '\0', '\0']), ('\u{ff2b}',
+ ['\u{ff4b}', '\0', '\0']), ('\u{ff2c}', ['\u{ff4c}', '\0', '\0']), ('\u{ff2d}', ['\u{ff4d}',
+ '\0', '\0']), ('\u{ff2e}', ['\u{ff4e}', '\0', '\0']), ('\u{ff2f}', ['\u{ff4f}', '\0',
+ '\0']), ('\u{ff30}', ['\u{ff50}', '\0', '\0']), ('\u{ff31}', ['\u{ff51}', '\0', '\0']),
+ ('\u{ff32}', ['\u{ff52}', '\0', '\0']), ('\u{ff33}', ['\u{ff53}', '\0', '\0']), ('\u{ff34}',
+ ['\u{ff54}', '\0', '\0']), ('\u{ff35}', ['\u{ff55}', '\0', '\0']), ('\u{ff36}', ['\u{ff56}',
+ '\0', '\0']), ('\u{ff37}', ['\u{ff57}', '\0', '\0']), ('\u{ff38}', ['\u{ff58}', '\0',
+ '\0']), ('\u{ff39}', ['\u{ff59}', '\0', '\0']), ('\u{ff3a}', ['\u{ff5a}', '\0', '\0']),
+ ('\u{10400}', ['\u{10428}', '\0', '\0']), ('\u{10401}', ['\u{10429}', '\0', '\0']),
+ ('\u{10402}', ['\u{1042a}', '\0', '\0']), ('\u{10403}', ['\u{1042b}', '\0', '\0']),
+ ('\u{10404}', ['\u{1042c}', '\0', '\0']), ('\u{10405}', ['\u{1042d}', '\0', '\0']),
+ ('\u{10406}', ['\u{1042e}', '\0', '\0']), ('\u{10407}', ['\u{1042f}', '\0', '\0']),
+ ('\u{10408}', ['\u{10430}', '\0', '\0']), ('\u{10409}', ['\u{10431}', '\0', '\0']),
+ ('\u{1040a}', ['\u{10432}', '\0', '\0']), ('\u{1040b}', ['\u{10433}', '\0', '\0']),
+ ('\u{1040c}', ['\u{10434}', '\0', '\0']), ('\u{1040d}', ['\u{10435}', '\0', '\0']),
+ ('\u{1040e}', ['\u{10436}', '\0', '\0']), ('\u{1040f}', ['\u{10437}', '\0', '\0']),
+ ('\u{10410}', ['\u{10438}', '\0', '\0']), ('\u{10411}', ['\u{10439}', '\0', '\0']),
+ ('\u{10412}', ['\u{1043a}', '\0', '\0']), ('\u{10413}', ['\u{1043b}', '\0', '\0']),
+ ('\u{10414}', ['\u{1043c}', '\0', '\0']), ('\u{10415}', ['\u{1043d}', '\0', '\0']),
+ ('\u{10416}', ['\u{1043e}', '\0', '\0']), ('\u{10417}', ['\u{1043f}', '\0', '\0']),
+ ('\u{10418}', ['\u{10440}', '\0', '\0']), ('\u{10419}', ['\u{10441}', '\0', '\0']),
+ ('\u{1041a}', ['\u{10442}', '\0', '\0']), ('\u{1041b}', ['\u{10443}', '\0', '\0']),
+ ('\u{1041c}', ['\u{10444}', '\0', '\0']), ('\u{1041d}', ['\u{10445}', '\0', '\0']),
+ ('\u{1041e}', ['\u{10446}', '\0', '\0']), ('\u{1041f}', ['\u{10447}', '\0', '\0']),
+ ('\u{10420}', ['\u{10448}', '\0', '\0']), ('\u{10421}', ['\u{10449}', '\0', '\0']),
+ ('\u{10422}', ['\u{1044a}', '\0', '\0']), ('\u{10423}', ['\u{1044b}', '\0', '\0']),
+ ('\u{10424}', ['\u{1044c}', '\0', '\0']), ('\u{10425}', ['\u{1044d}', '\0', '\0']),
+ ('\u{10426}', ['\u{1044e}', '\0', '\0']), ('\u{10427}', ['\u{1044f}', '\0', '\0']),
+ ('\u{118a0}', ['\u{118c0}', '\0', '\0']), ('\u{118a1}', ['\u{118c1}', '\0', '\0']),
+ ('\u{118a2}', ['\u{118c2}', '\0', '\0']), ('\u{118a3}', ['\u{118c3}', '\0', '\0']),
+ ('\u{118a4}', ['\u{118c4}', '\0', '\0']), ('\u{118a5}', ['\u{118c5}', '\0', '\0']),
+ ('\u{118a6}', ['\u{118c6}', '\0', '\0']), ('\u{118a7}', ['\u{118c7}', '\0', '\0']),
+ ('\u{118a8}', ['\u{118c8}', '\0', '\0']), ('\u{118a9}', ['\u{118c9}', '\0', '\0']),
+ ('\u{118aa}', ['\u{118ca}', '\0', '\0']), ('\u{118ab}', ['\u{118cb}', '\0', '\0']),
+ ('\u{118ac}', ['\u{118cc}', '\0', '\0']), ('\u{118ad}', ['\u{118cd}', '\0', '\0']),
+ ('\u{118ae}', ['\u{118ce}', '\0', '\0']), ('\u{118af}', ['\u{118cf}', '\0', '\0']),
+ ('\u{118b0}', ['\u{118d0}', '\0', '\0']), ('\u{118b1}', ['\u{118d1}', '\0', '\0']),
+ ('\u{118b2}', ['\u{118d2}', '\0', '\0']), ('\u{118b3}', ['\u{118d3}', '\0', '\0']),
+ ('\u{118b4}', ['\u{118d4}', '\0', '\0']), ('\u{118b5}', ['\u{118d5}', '\0', '\0']),
+ ('\u{118b6}', ['\u{118d6}', '\0', '\0']), ('\u{118b7}', ['\u{118d7}', '\0', '\0']),
+ ('\u{118b8}', ['\u{118d8}', '\0', '\0']), ('\u{118b9}', ['\u{118d9}', '\0', '\0']),
+ ('\u{118ba}', ['\u{118da}', '\0', '\0']), ('\u{118bb}', ['\u{118db}', '\0', '\0']),
+ ('\u{118bc}', ['\u{118dc}', '\0', '\0']), ('\u{118bd}', ['\u{118dd}', '\0', '\0']),
+ ('\u{118be}', ['\u{118de}', '\0', '\0']), ('\u{118bf}', ['\u{118df}', '\0', '\0'])
+ ];
+
+ const to_uppercase_table: &'static [(char, [char; 3])] = &[
+ ('\u{61}', ['\u{41}', '\0', '\0']), ('\u{62}', ['\u{42}', '\0', '\0']), ('\u{63}',
+ ['\u{43}', '\0', '\0']), ('\u{64}', ['\u{44}', '\0', '\0']), ('\u{65}', ['\u{45}', '\0',
+ '\0']), ('\u{66}', ['\u{46}', '\0', '\0']), ('\u{67}', ['\u{47}', '\0', '\0']), ('\u{68}',
+ ['\u{48}', '\0', '\0']), ('\u{69}', ['\u{49}', '\0', '\0']), ('\u{6a}', ['\u{4a}', '\0',
+ '\0']), ('\u{6b}', ['\u{4b}', '\0', '\0']), ('\u{6c}', ['\u{4c}', '\0', '\0']), ('\u{6d}',
+ ['\u{4d}', '\0', '\0']), ('\u{6e}', ['\u{4e}', '\0', '\0']), ('\u{6f}', ['\u{4f}', '\0',
+ '\0']), ('\u{70}', ['\u{50}', '\0', '\0']), ('\u{71}', ['\u{51}', '\0', '\0']), ('\u{72}',
+ ['\u{52}', '\0', '\0']), ('\u{73}', ['\u{53}', '\0', '\0']), ('\u{74}', ['\u{54}', '\0',
+ '\0']), ('\u{75}', ['\u{55}', '\0', '\0']), ('\u{76}', ['\u{56}', '\0', '\0']), ('\u{77}',
+ ['\u{57}', '\0', '\0']), ('\u{78}', ['\u{58}', '\0', '\0']), ('\u{79}', ['\u{59}', '\0',
+ '\0']), ('\u{7a}', ['\u{5a}', '\0', '\0']), ('\u{b5}', ['\u{39c}', '\0', '\0']), ('\u{df}',
+ ['\u{53}', '\u{53}', '\0']), ('\u{e0}', ['\u{c0}', '\0', '\0']), ('\u{e1}', ['\u{c1}', '\0',
+ '\0']), ('\u{e2}', ['\u{c2}', '\0', '\0']), ('\u{e3}', ['\u{c3}', '\0', '\0']), ('\u{e4}',
+ ['\u{c4}', '\0', '\0']), ('\u{e5}', ['\u{c5}', '\0', '\0']), ('\u{e6}', ['\u{c6}', '\0',
+ '\0']), ('\u{e7}', ['\u{c7}', '\0', '\0']), ('\u{e8}', ['\u{c8}', '\0', '\0']), ('\u{e9}',
+ ['\u{c9}', '\0', '\0']), ('\u{ea}', ['\u{ca}', '\0', '\0']), ('\u{eb}', ['\u{cb}', '\0',
+ '\0']), ('\u{ec}', ['\u{cc}', '\0', '\0']), ('\u{ed}', ['\u{cd}', '\0', '\0']), ('\u{ee}',
+ ['\u{ce}', '\0', '\0']), ('\u{ef}', ['\u{cf}', '\0', '\0']), ('\u{f0}', ['\u{d0}', '\0',
+ '\0']), ('\u{f1}', ['\u{d1}', '\0', '\0']), ('\u{f2}', ['\u{d2}', '\0', '\0']), ('\u{f3}',
+ ['\u{d3}', '\0', '\0']), ('\u{f4}', ['\u{d4}', '\0', '\0']), ('\u{f5}', ['\u{d5}', '\0',
+ '\0']), ('\u{f6}', ['\u{d6}', '\0', '\0']), ('\u{f8}', ['\u{d8}', '\0', '\0']), ('\u{f9}',
+ ['\u{d9}', '\0', '\0']), ('\u{fa}', ['\u{da}', '\0', '\0']), ('\u{fb}', ['\u{db}', '\0',
+ '\0']), ('\u{fc}', ['\u{dc}', '\0', '\0']), ('\u{fd}', ['\u{dd}', '\0', '\0']), ('\u{fe}',
+ ['\u{de}', '\0', '\0']), ('\u{ff}', ['\u{178}', '\0', '\0']), ('\u{101}', ['\u{100}', '\0',
+ '\0']), ('\u{103}', ['\u{102}', '\0', '\0']), ('\u{105}', ['\u{104}', '\0', '\0']),
+ ('\u{107}', ['\u{106}', '\0', '\0']), ('\u{109}', ['\u{108}', '\0', '\0']), ('\u{10b}',
+ ['\u{10a}', '\0', '\0']), ('\u{10d}', ['\u{10c}', '\0', '\0']), ('\u{10f}', ['\u{10e}',
+ '\0', '\0']), ('\u{111}', ['\u{110}', '\0', '\0']), ('\u{113}', ['\u{112}', '\0', '\0']),
+ ('\u{115}', ['\u{114}', '\0', '\0']), ('\u{117}', ['\u{116}', '\0', '\0']), ('\u{119}',
+ ['\u{118}', '\0', '\0']), ('\u{11b}', ['\u{11a}', '\0', '\0']), ('\u{11d}', ['\u{11c}',
+ '\0', '\0']), ('\u{11f}', ['\u{11e}', '\0', '\0']), ('\u{121}', ['\u{120}', '\0', '\0']),
+ ('\u{123}', ['\u{122}', '\0', '\0']), ('\u{125}', ['\u{124}', '\0', '\0']), ('\u{127}',
+ ['\u{126}', '\0', '\0']), ('\u{129}', ['\u{128}', '\0', '\0']), ('\u{12b}', ['\u{12a}',
+ '\0', '\0']), ('\u{12d}', ['\u{12c}', '\0', '\0']), ('\u{12f}', ['\u{12e}', '\0', '\0']),
+ ('\u{131}', ['\u{49}', '\0', '\0']), ('\u{133}', ['\u{132}', '\0', '\0']), ('\u{135}',
+ ['\u{134}', '\0', '\0']), ('\u{137}', ['\u{136}', '\0', '\0']), ('\u{13a}', ['\u{139}',
+ '\0', '\0']), ('\u{13c}', ['\u{13b}', '\0', '\0']), ('\u{13e}', ['\u{13d}', '\0', '\0']),
+ ('\u{140}', ['\u{13f}', '\0', '\0']), ('\u{142}', ['\u{141}', '\0', '\0']), ('\u{144}',
+ ['\u{143}', '\0', '\0']), ('\u{146}', ['\u{145}', '\0', '\0']), ('\u{148}', ['\u{147}',
+ '\0', '\0']), ('\u{149}', ['\u{2bc}', '\u{4e}', '\0']), ('\u{14b}', ['\u{14a}', '\0',
+ '\0']), ('\u{14d}', ['\u{14c}', '\0', '\0']), ('\u{14f}', ['\u{14e}', '\0', '\0']),
+ ('\u{151}', ['\u{150}', '\0', '\0']), ('\u{153}', ['\u{152}', '\0', '\0']), ('\u{155}',
+ ['\u{154}', '\0', '\0']), ('\u{157}', ['\u{156}', '\0', '\0']), ('\u{159}', ['\u{158}',
+ '\0', '\0']), ('\u{15b}', ['\u{15a}', '\0', '\0']), ('\u{15d}', ['\u{15c}', '\0', '\0']),
+ ('\u{15f}', ['\u{15e}', '\0', '\0']), ('\u{161}', ['\u{160}', '\0', '\0']), ('\u{163}',
+ ['\u{162}', '\0', '\0']), ('\u{165}', ['\u{164}', '\0', '\0']), ('\u{167}', ['\u{166}',
+ '\0', '\0']), ('\u{169}', ['\u{168}', '\0', '\0']), ('\u{16b}', ['\u{16a}', '\0', '\0']),
+ ('\u{16d}', ['\u{16c}', '\0', '\0']), ('\u{16f}', ['\u{16e}', '\0', '\0']), ('\u{171}',
+ ['\u{170}', '\0', '\0']), ('\u{173}', ['\u{172}', '\0', '\0']), ('\u{175}', ['\u{174}',
+ '\0', '\0']), ('\u{177}', ['\u{176}', '\0', '\0']), ('\u{17a}', ['\u{179}', '\0', '\0']),
+ ('\u{17c}', ['\u{17b}', '\0', '\0']), ('\u{17e}', ['\u{17d}', '\0', '\0']), ('\u{17f}',
+ ['\u{53}', '\0', '\0']), ('\u{180}', ['\u{243}', '\0', '\0']), ('\u{183}', ['\u{182}', '\0',
+ '\0']), ('\u{185}', ['\u{184}', '\0', '\0']), ('\u{188}', ['\u{187}', '\0', '\0']),
+ ('\u{18c}', ['\u{18b}', '\0', '\0']), ('\u{192}', ['\u{191}', '\0', '\0']), ('\u{195}',
+ ['\u{1f6}', '\0', '\0']), ('\u{199}', ['\u{198}', '\0', '\0']), ('\u{19a}', ['\u{23d}',
+ '\0', '\0']), ('\u{19e}', ['\u{220}', '\0', '\0']), ('\u{1a1}', ['\u{1a0}', '\0', '\0']),
+ ('\u{1a3}', ['\u{1a2}', '\0', '\0']), ('\u{1a5}', ['\u{1a4}', '\0', '\0']), ('\u{1a8}',
+ ['\u{1a7}', '\0', '\0']), ('\u{1ad}', ['\u{1ac}', '\0', '\0']), ('\u{1b0}', ['\u{1af}',
+ '\0', '\0']), ('\u{1b4}', ['\u{1b3}', '\0', '\0']), ('\u{1b6}', ['\u{1b5}', '\0', '\0']),
+ ('\u{1b9}', ['\u{1b8}', '\0', '\0']), ('\u{1bd}', ['\u{1bc}', '\0', '\0']), ('\u{1bf}',
+ ['\u{1f7}', '\0', '\0']), ('\u{1c5}', ['\u{1c4}', '\0', '\0']), ('\u{1c6}', ['\u{1c4}',
+ '\0', '\0']), ('\u{1c8}', ['\u{1c7}', '\0', '\0']), ('\u{1c9}', ['\u{1c7}', '\0', '\0']),
+ ('\u{1cb}', ['\u{1ca}', '\0', '\0']), ('\u{1cc}', ['\u{1ca}', '\0', '\0']), ('\u{1ce}',
+ ['\u{1cd}', '\0', '\0']), ('\u{1d0}', ['\u{1cf}', '\0', '\0']), ('\u{1d2}', ['\u{1d1}',
+ '\0', '\0']), ('\u{1d4}', ['\u{1d3}', '\0', '\0']), ('\u{1d6}', ['\u{1d5}', '\0', '\0']),
+ ('\u{1d8}', ['\u{1d7}', '\0', '\0']), ('\u{1da}', ['\u{1d9}', '\0', '\0']), ('\u{1dc}',
+ ['\u{1db}', '\0', '\0']), ('\u{1dd}', ['\u{18e}', '\0', '\0']), ('\u{1df}', ['\u{1de}',
+ '\0', '\0']), ('\u{1e1}', ['\u{1e0}', '\0', '\0']), ('\u{1e3}', ['\u{1e2}', '\0', '\0']),
+ ('\u{1e5}', ['\u{1e4}', '\0', '\0']), ('\u{1e7}', ['\u{1e6}', '\0', '\0']), ('\u{1e9}',
+ ['\u{1e8}', '\0', '\0']), ('\u{1eb}', ['\u{1ea}', '\0', '\0']), ('\u{1ed}', ['\u{1ec}',
+ '\0', '\0']), ('\u{1ef}', ['\u{1ee}', '\0', '\0']), ('\u{1f0}', ['\u{4a}', '\u{30c}',
+ '\0']), ('\u{1f2}', ['\u{1f1}', '\0', '\0']), ('\u{1f3}', ['\u{1f1}', '\0', '\0']),
+ ('\u{1f5}', ['\u{1f4}', '\0', '\0']), ('\u{1f9}', ['\u{1f8}', '\0', '\0']), ('\u{1fb}',
+ ['\u{1fa}', '\0', '\0']), ('\u{1fd}', ['\u{1fc}', '\0', '\0']), ('\u{1ff}', ['\u{1fe}',
+ '\0', '\0']), ('\u{201}', ['\u{200}', '\0', '\0']), ('\u{203}', ['\u{202}', '\0', '\0']),
+ ('\u{205}', ['\u{204}', '\0', '\0']), ('\u{207}', ['\u{206}', '\0', '\0']), ('\u{209}',
+ ['\u{208}', '\0', '\0']), ('\u{20b}', ['\u{20a}', '\0', '\0']), ('\u{20d}', ['\u{20c}',
+ '\0', '\0']), ('\u{20f}', ['\u{20e}', '\0', '\0']), ('\u{211}', ['\u{210}', '\0', '\0']),
+ ('\u{213}', ['\u{212}', '\0', '\0']), ('\u{215}', ['\u{214}', '\0', '\0']), ('\u{217}',
+ ['\u{216}', '\0', '\0']), ('\u{219}', ['\u{218}', '\0', '\0']), ('\u{21b}', ['\u{21a}',
+ '\0', '\0']), ('\u{21d}', ['\u{21c}', '\0', '\0']), ('\u{21f}', ['\u{21e}', '\0', '\0']),
+ ('\u{223}', ['\u{222}', '\0', '\0']), ('\u{225}', ['\u{224}', '\0', '\0']), ('\u{227}',
+ ['\u{226}', '\0', '\0']), ('\u{229}', ['\u{228}', '\0', '\0']), ('\u{22b}', ['\u{22a}',
+ '\0', '\0']), ('\u{22d}', ['\u{22c}', '\0', '\0']), ('\u{22f}', ['\u{22e}', '\0', '\0']),
+ ('\u{231}', ['\u{230}', '\0', '\0']), ('\u{233}', ['\u{232}', '\0', '\0']), ('\u{23c}',
+ ['\u{23b}', '\0', '\0']), ('\u{23f}', ['\u{2c7e}', '\0', '\0']), ('\u{240}', ['\u{2c7f}',
+ '\0', '\0']), ('\u{242}', ['\u{241}', '\0', '\0']), ('\u{247}', ['\u{246}', '\0', '\0']),
+ ('\u{249}', ['\u{248}', '\0', '\0']), ('\u{24b}', ['\u{24a}', '\0', '\0']), ('\u{24d}',
+ ['\u{24c}', '\0', '\0']), ('\u{24f}', ['\u{24e}', '\0', '\0']), ('\u{250}', ['\u{2c6f}',
+ '\0', '\0']), ('\u{251}', ['\u{2c6d}', '\0', '\0']), ('\u{252}', ['\u{2c70}', '\0', '\0']),
+ ('\u{253}', ['\u{181}', '\0', '\0']), ('\u{254}', ['\u{186}', '\0', '\0']), ('\u{256}',
+ ['\u{189}', '\0', '\0']), ('\u{257}', ['\u{18a}', '\0', '\0']), ('\u{259}', ['\u{18f}',
+ '\0', '\0']), ('\u{25b}', ['\u{190}', '\0', '\0']), ('\u{25c}', ['\u{a7ab}', '\0', '\0']),
+ ('\u{260}', ['\u{193}', '\0', '\0']), ('\u{261}', ['\u{a7ac}', '\0', '\0']), ('\u{263}',
+ ['\u{194}', '\0', '\0']), ('\u{265}', ['\u{a78d}', '\0', '\0']), ('\u{266}', ['\u{a7aa}',
+ '\0', '\0']), ('\u{268}', ['\u{197}', '\0', '\0']), ('\u{269}', ['\u{196}', '\0', '\0']),
+ ('\u{26b}', ['\u{2c62}', '\0', '\0']), ('\u{26c}', ['\u{a7ad}', '\0', '\0']), ('\u{26f}',
+ ['\u{19c}', '\0', '\0']), ('\u{271}', ['\u{2c6e}', '\0', '\0']), ('\u{272}', ['\u{19d}',
+ '\0', '\0']), ('\u{275}', ['\u{19f}', '\0', '\0']), ('\u{27d}', ['\u{2c64}', '\0', '\0']),
+ ('\u{280}', ['\u{1a6}', '\0', '\0']), ('\u{283}', ['\u{1a9}', '\0', '\0']), ('\u{287}',
+ ['\u{a7b1}', '\0', '\0']), ('\u{288}', ['\u{1ae}', '\0', '\0']), ('\u{289}', ['\u{244}',
+ '\0', '\0']), ('\u{28a}', ['\u{1b1}', '\0', '\0']), ('\u{28b}', ['\u{1b2}', '\0', '\0']),
+ ('\u{28c}', ['\u{245}', '\0', '\0']), ('\u{292}', ['\u{1b7}', '\0', '\0']), ('\u{29e}',
+ ['\u{a7b0}', '\0', '\0']), ('\u{345}', ['\u{399}', '\0', '\0']), ('\u{371}', ['\u{370}',
+ '\0', '\0']), ('\u{373}', ['\u{372}', '\0', '\0']), ('\u{377}', ['\u{376}', '\0', '\0']),
+ ('\u{37b}', ['\u{3fd}', '\0', '\0']), ('\u{37c}', ['\u{3fe}', '\0', '\0']), ('\u{37d}',
+ ['\u{3ff}', '\0', '\0']), ('\u{390}', ['\u{399}', '\u{308}', '\u{301}']), ('\u{3ac}',
+ ['\u{386}', '\0', '\0']), ('\u{3ad}', ['\u{388}', '\0', '\0']), ('\u{3ae}', ['\u{389}',
+ '\0', '\0']), ('\u{3af}', ['\u{38a}', '\0', '\0']), ('\u{3b0}', ['\u{3a5}', '\u{308}',
+ '\u{301}']), ('\u{3b1}', ['\u{391}', '\0', '\0']), ('\u{3b2}', ['\u{392}', '\0', '\0']),
+ ('\u{3b3}', ['\u{393}', '\0', '\0']), ('\u{3b4}', ['\u{394}', '\0', '\0']), ('\u{3b5}',
+ ['\u{395}', '\0', '\0']), ('\u{3b6}', ['\u{396}', '\0', '\0']), ('\u{3b7}', ['\u{397}',
+ '\0', '\0']), ('\u{3b8}', ['\u{398}', '\0', '\0']), ('\u{3b9}', ['\u{399}', '\0', '\0']),
+ ('\u{3ba}', ['\u{39a}', '\0', '\0']), ('\u{3bb}', ['\u{39b}', '\0', '\0']), ('\u{3bc}',
+ ['\u{39c}', '\0', '\0']), ('\u{3bd}', ['\u{39d}', '\0', '\0']), ('\u{3be}', ['\u{39e}',
+ '\0', '\0']), ('\u{3bf}', ['\u{39f}', '\0', '\0']), ('\u{3c0}', ['\u{3a0}', '\0', '\0']),
+ ('\u{3c1}', ['\u{3a1}', '\0', '\0']), ('\u{3c2}', ['\u{3a3}', '\0', '\0']), ('\u{3c3}',
+ ['\u{3a3}', '\0', '\0']), ('\u{3c4}', ['\u{3a4}', '\0', '\0']), ('\u{3c5}', ['\u{3a5}',
+ '\0', '\0']), ('\u{3c6}', ['\u{3a6}', '\0', '\0']), ('\u{3c7}', ['\u{3a7}', '\0', '\0']),
+ ('\u{3c8}', ['\u{3a8}', '\0', '\0']), ('\u{3c9}', ['\u{3a9}', '\0', '\0']), ('\u{3ca}',
+ ['\u{3aa}', '\0', '\0']), ('\u{3cb}', ['\u{3ab}', '\0', '\0']), ('\u{3cc}', ['\u{38c}',
+ '\0', '\0']), ('\u{3cd}', ['\u{38e}', '\0', '\0']), ('\u{3ce}', ['\u{38f}', '\0', '\0']),
+ ('\u{3d0}', ['\u{392}', '\0', '\0']), ('\u{3d1}', ['\u{398}', '\0', '\0']), ('\u{3d5}',
+ ['\u{3a6}', '\0', '\0']), ('\u{3d6}', ['\u{3a0}', '\0', '\0']), ('\u{3d7}', ['\u{3cf}',
+ '\0', '\0']), ('\u{3d9}', ['\u{3d8}', '\0', '\0']), ('\u{3db}', ['\u{3da}', '\0', '\0']),
+ ('\u{3dd}', ['\u{3dc}', '\0', '\0']), ('\u{3df}', ['\u{3de}', '\0', '\0']), ('\u{3e1}',
+ ['\u{3e0}', '\0', '\0']), ('\u{3e3}', ['\u{3e2}', '\0', '\0']), ('\u{3e5}', ['\u{3e4}',
+ '\0', '\0']), ('\u{3e7}', ['\u{3e6}', '\0', '\0']), ('\u{3e9}', ['\u{3e8}', '\0', '\0']),
+ ('\u{3eb}', ['\u{3ea}', '\0', '\0']), ('\u{3ed}', ['\u{3ec}', '\0', '\0']), ('\u{3ef}',
+ ['\u{3ee}', '\0', '\0']), ('\u{3f0}', ['\u{39a}', '\0', '\0']), ('\u{3f1}', ['\u{3a1}',
+ '\0', '\0']), ('\u{3f2}', ['\u{3f9}', '\0', '\0']), ('\u{3f3}', ['\u{37f}', '\0', '\0']),
+ ('\u{3f5}', ['\u{395}', '\0', '\0']), ('\u{3f8}', ['\u{3f7}', '\0', '\0']), ('\u{3fb}',
+ ['\u{3fa}', '\0', '\0']), ('\u{430}', ['\u{410}', '\0', '\0']), ('\u{431}', ['\u{411}',
+ '\0', '\0']), ('\u{432}', ['\u{412}', '\0', '\0']), ('\u{433}', ['\u{413}', '\0', '\0']),
+ ('\u{434}', ['\u{414}', '\0', '\0']), ('\u{435}', ['\u{415}', '\0', '\0']), ('\u{436}',
+ ['\u{416}', '\0', '\0']), ('\u{437}', ['\u{417}', '\0', '\0']), ('\u{438}', ['\u{418}',
+ '\0', '\0']), ('\u{439}', ['\u{419}', '\0', '\0']), ('\u{43a}', ['\u{41a}', '\0', '\0']),
+ ('\u{43b}', ['\u{41b}', '\0', '\0']), ('\u{43c}', ['\u{41c}', '\0', '\0']), ('\u{43d}',
+ ['\u{41d}', '\0', '\0']), ('\u{43e}', ['\u{41e}', '\0', '\0']), ('\u{43f}', ['\u{41f}',
+ '\0', '\0']), ('\u{440}', ['\u{420}', '\0', '\0']), ('\u{441}', ['\u{421}', '\0', '\0']),
+ ('\u{442}', ['\u{422}', '\0', '\0']), ('\u{443}', ['\u{423}', '\0', '\0']), ('\u{444}',
+ ['\u{424}', '\0', '\0']), ('\u{445}', ['\u{425}', '\0', '\0']), ('\u{446}', ['\u{426}',
+ '\0', '\0']), ('\u{447}', ['\u{427}', '\0', '\0']), ('\u{448}', ['\u{428}', '\0', '\0']),
+ ('\u{449}', ['\u{429}', '\0', '\0']), ('\u{44a}', ['\u{42a}', '\0', '\0']), ('\u{44b}',
+ ['\u{42b}', '\0', '\0']), ('\u{44c}', ['\u{42c}', '\0', '\0']), ('\u{44d}', ['\u{42d}',
+ '\0', '\0']), ('\u{44e}', ['\u{42e}', '\0', '\0']), ('\u{44f}', ['\u{42f}', '\0', '\0']),
+ ('\u{450}', ['\u{400}', '\0', '\0']), ('\u{451}', ['\u{401}', '\0', '\0']), ('\u{452}',
+ ['\u{402}', '\0', '\0']), ('\u{453}', ['\u{403}', '\0', '\0']), ('\u{454}', ['\u{404}',
+ '\0', '\0']), ('\u{455}', ['\u{405}', '\0', '\0']), ('\u{456}', ['\u{406}', '\0', '\0']),
+ ('\u{457}', ['\u{407}', '\0', '\0']), ('\u{458}', ['\u{408}', '\0', '\0']), ('\u{459}',
+ ['\u{409}', '\0', '\0']), ('\u{45a}', ['\u{40a}', '\0', '\0']), ('\u{45b}', ['\u{40b}',
+ '\0', '\0']), ('\u{45c}', ['\u{40c}', '\0', '\0']), ('\u{45d}', ['\u{40d}', '\0', '\0']),
+ ('\u{45e}', ['\u{40e}', '\0', '\0']), ('\u{45f}', ['\u{40f}', '\0', '\0']), ('\u{461}',
+ ['\u{460}', '\0', '\0']), ('\u{463}', ['\u{462}', '\0', '\0']), ('\u{465}', ['\u{464}',
+ '\0', '\0']), ('\u{467}', ['\u{466}', '\0', '\0']), ('\u{469}', ['\u{468}', '\0', '\0']),
+ ('\u{46b}', ['\u{46a}', '\0', '\0']), ('\u{46d}', ['\u{46c}', '\0', '\0']), ('\u{46f}',
+ ['\u{46e}', '\0', '\0']), ('\u{471}', ['\u{470}', '\0', '\0']), ('\u{473}', ['\u{472}',
+ '\0', '\0']), ('\u{475}', ['\u{474}', '\0', '\0']), ('\u{477}', ['\u{476}', '\0', '\0']),
+ ('\u{479}', ['\u{478}', '\0', '\0']), ('\u{47b}', ['\u{47a}', '\0', '\0']), ('\u{47d}',
+ ['\u{47c}', '\0', '\0']), ('\u{47f}', ['\u{47e}', '\0', '\0']), ('\u{481}', ['\u{480}',
+ '\0', '\0']), ('\u{48b}', ['\u{48a}', '\0', '\0']), ('\u{48d}', ['\u{48c}', '\0', '\0']),
+ ('\u{48f}', ['\u{48e}', '\0', '\0']), ('\u{491}', ['\u{490}', '\0', '\0']), ('\u{493}',
+ ['\u{492}', '\0', '\0']), ('\u{495}', ['\u{494}', '\0', '\0']), ('\u{497}', ['\u{496}',
+ '\0', '\0']), ('\u{499}', ['\u{498}', '\0', '\0']), ('\u{49b}', ['\u{49a}', '\0', '\0']),
+ ('\u{49d}', ['\u{49c}', '\0', '\0']), ('\u{49f}', ['\u{49e}', '\0', '\0']), ('\u{4a1}',
+ ['\u{4a0}', '\0', '\0']), ('\u{4a3}', ['\u{4a2}', '\0', '\0']), ('\u{4a5}', ['\u{4a4}',
+ '\0', '\0']), ('\u{4a7}', ['\u{4a6}', '\0', '\0']), ('\u{4a9}', ['\u{4a8}', '\0', '\0']),
+ ('\u{4ab}', ['\u{4aa}', '\0', '\0']), ('\u{4ad}', ['\u{4ac}', '\0', '\0']), ('\u{4af}',
+ ['\u{4ae}', '\0', '\0']), ('\u{4b1}', ['\u{4b0}', '\0', '\0']), ('\u{4b3}', ['\u{4b2}',
+ '\0', '\0']), ('\u{4b5}', ['\u{4b4}', '\0', '\0']), ('\u{4b7}', ['\u{4b6}', '\0', '\0']),
+ ('\u{4b9}', ['\u{4b8}', '\0', '\0']), ('\u{4bb}', ['\u{4ba}', '\0', '\0']), ('\u{4bd}',
+ ['\u{4bc}', '\0', '\0']), ('\u{4bf}', ['\u{4be}', '\0', '\0']), ('\u{4c2}', ['\u{4c1}',
+ '\0', '\0']), ('\u{4c4}', ['\u{4c3}', '\0', '\0']), ('\u{4c6}', ['\u{4c5}', '\0', '\0']),
+ ('\u{4c8}', ['\u{4c7}', '\0', '\0']), ('\u{4ca}', ['\u{4c9}', '\0', '\0']), ('\u{4cc}',
+ ['\u{4cb}', '\0', '\0']), ('\u{4ce}', ['\u{4cd}', '\0', '\0']), ('\u{4cf}', ['\u{4c0}',
+ '\0', '\0']), ('\u{4d1}', ['\u{4d0}', '\0', '\0']), ('\u{4d3}', ['\u{4d2}', '\0', '\0']),
+ ('\u{4d5}', ['\u{4d4}', '\0', '\0']), ('\u{4d7}', ['\u{4d6}', '\0', '\0']), ('\u{4d9}',
+ ['\u{4d8}', '\0', '\0']), ('\u{4db}', ['\u{4da}', '\0', '\0']), ('\u{4dd}', ['\u{4dc}',
+ '\0', '\0']), ('\u{4df}', ['\u{4de}', '\0', '\0']), ('\u{4e1}', ['\u{4e0}', '\0', '\0']),
+ ('\u{4e3}', ['\u{4e2}', '\0', '\0']), ('\u{4e5}', ['\u{4e4}', '\0', '\0']), ('\u{4e7}',
+ ['\u{4e6}', '\0', '\0']), ('\u{4e9}', ['\u{4e8}', '\0', '\0']), ('\u{4eb}', ['\u{4ea}',
+ '\0', '\0']), ('\u{4ed}', ['\u{4ec}', '\0', '\0']), ('\u{4ef}', ['\u{4ee}', '\0', '\0']),
+ ('\u{4f1}', ['\u{4f0}', '\0', '\0']), ('\u{4f3}', ['\u{4f2}', '\0', '\0']), ('\u{4f5}',
+ ['\u{4f4}', '\0', '\0']), ('\u{4f7}', ['\u{4f6}', '\0', '\0']), ('\u{4f9}', ['\u{4f8}',
+ '\0', '\0']), ('\u{4fb}', ['\u{4fa}', '\0', '\0']), ('\u{4fd}', ['\u{4fc}', '\0', '\0']),
+ ('\u{4ff}', ['\u{4fe}', '\0', '\0']), ('\u{501}', ['\u{500}', '\0', '\0']), ('\u{503}',
+ ['\u{502}', '\0', '\0']), ('\u{505}', ['\u{504}', '\0', '\0']), ('\u{507}', ['\u{506}',
+ '\0', '\0']), ('\u{509}', ['\u{508}', '\0', '\0']), ('\u{50b}', ['\u{50a}', '\0', '\0']),
+ ('\u{50d}', ['\u{50c}', '\0', '\0']), ('\u{50f}', ['\u{50e}', '\0', '\0']), ('\u{511}',
+ ['\u{510}', '\0', '\0']), ('\u{513}', ['\u{512}', '\0', '\0']), ('\u{515}', ['\u{514}',
+ '\0', '\0']), ('\u{517}', ['\u{516}', '\0', '\0']), ('\u{519}', ['\u{518}', '\0', '\0']),
+ ('\u{51b}', ['\u{51a}', '\0', '\0']), ('\u{51d}', ['\u{51c}', '\0', '\0']), ('\u{51f}',
+ ['\u{51e}', '\0', '\0']), ('\u{521}', ['\u{520}', '\0', '\0']), ('\u{523}', ['\u{522}',
+ '\0', '\0']), ('\u{525}', ['\u{524}', '\0', '\0']), ('\u{527}', ['\u{526}', '\0', '\0']),
+ ('\u{529}', ['\u{528}', '\0', '\0']), ('\u{52b}', ['\u{52a}', '\0', '\0']), ('\u{52d}',
+ ['\u{52c}', '\0', '\0']), ('\u{52f}', ['\u{52e}', '\0', '\0']), ('\u{561}', ['\u{531}',
+ '\0', '\0']), ('\u{562}', ['\u{532}', '\0', '\0']), ('\u{563}', ['\u{533}', '\0', '\0']),
+ ('\u{564}', ['\u{534}', '\0', '\0']), ('\u{565}', ['\u{535}', '\0', '\0']), ('\u{566}',
+ ['\u{536}', '\0', '\0']), ('\u{567}', ['\u{537}', '\0', '\0']), ('\u{568}', ['\u{538}',
+ '\0', '\0']), ('\u{569}', ['\u{539}', '\0', '\0']), ('\u{56a}', ['\u{53a}', '\0', '\0']),
+ ('\u{56b}', ['\u{53b}', '\0', '\0']), ('\u{56c}', ['\u{53c}', '\0', '\0']), ('\u{56d}',
+ ['\u{53d}', '\0', '\0']), ('\u{56e}', ['\u{53e}', '\0', '\0']), ('\u{56f}', ['\u{53f}',
+ '\0', '\0']), ('\u{570}', ['\u{540}', '\0', '\0']), ('\u{571}', ['\u{541}', '\0', '\0']),
+ ('\u{572}', ['\u{542}', '\0', '\0']), ('\u{573}', ['\u{543}', '\0', '\0']), ('\u{574}',
+ ['\u{544}', '\0', '\0']), ('\u{575}', ['\u{545}', '\0', '\0']), ('\u{576}', ['\u{546}',
+ '\0', '\0']), ('\u{577}', ['\u{547}', '\0', '\0']), ('\u{578}', ['\u{548}', '\0', '\0']),
+ ('\u{579}', ['\u{549}', '\0', '\0']), ('\u{57a}', ['\u{54a}', '\0', '\0']), ('\u{57b}',
+ ['\u{54b}', '\0', '\0']), ('\u{57c}', ['\u{54c}', '\0', '\0']), ('\u{57d}', ['\u{54d}',
+ '\0', '\0']), ('\u{57e}', ['\u{54e}', '\0', '\0']), ('\u{57f}', ['\u{54f}', '\0', '\0']),
+ ('\u{580}', ['\u{550}', '\0', '\0']), ('\u{581}', ['\u{551}', '\0', '\0']), ('\u{582}',
+ ['\u{552}', '\0', '\0']), ('\u{583}', ['\u{553}', '\0', '\0']), ('\u{584}', ['\u{554}',
+ '\0', '\0']), ('\u{585}', ['\u{555}', '\0', '\0']), ('\u{586}', ['\u{556}', '\0', '\0']),
+ ('\u{587}', ['\u{535}', '\u{552}', '\0']), ('\u{1d79}', ['\u{a77d}', '\0', '\0']),
+ ('\u{1d7d}', ['\u{2c63}', '\0', '\0']), ('\u{1e01}', ['\u{1e00}', '\0', '\0']), ('\u{1e03}',
+ ['\u{1e02}', '\0', '\0']), ('\u{1e05}', ['\u{1e04}', '\0', '\0']), ('\u{1e07}', ['\u{1e06}',
+ '\0', '\0']), ('\u{1e09}', ['\u{1e08}', '\0', '\0']), ('\u{1e0b}', ['\u{1e0a}', '\0',
+ '\0']), ('\u{1e0d}', ['\u{1e0c}', '\0', '\0']), ('\u{1e0f}', ['\u{1e0e}', '\0', '\0']),
+ ('\u{1e11}', ['\u{1e10}', '\0', '\0']), ('\u{1e13}', ['\u{1e12}', '\0', '\0']), ('\u{1e15}',
+ ['\u{1e14}', '\0', '\0']), ('\u{1e17}', ['\u{1e16}', '\0', '\0']), ('\u{1e19}', ['\u{1e18}',
+ '\0', '\0']), ('\u{1e1b}', ['\u{1e1a}', '\0', '\0']), ('\u{1e1d}', ['\u{1e1c}', '\0',
+ '\0']), ('\u{1e1f}', ['\u{1e1e}', '\0', '\0']), ('\u{1e21}', ['\u{1e20}', '\0', '\0']),
+ ('\u{1e23}', ['\u{1e22}', '\0', '\0']), ('\u{1e25}', ['\u{1e24}', '\0', '\0']), ('\u{1e27}',
+ ['\u{1e26}', '\0', '\0']), ('\u{1e29}', ['\u{1e28}', '\0', '\0']), ('\u{1e2b}', ['\u{1e2a}',
+ '\0', '\0']), ('\u{1e2d}', ['\u{1e2c}', '\0', '\0']), ('\u{1e2f}', ['\u{1e2e}', '\0',
+ '\0']), ('\u{1e31}', ['\u{1e30}', '\0', '\0']), ('\u{1e33}', ['\u{1e32}', '\0', '\0']),
+ ('\u{1e35}', ['\u{1e34}', '\0', '\0']), ('\u{1e37}', ['\u{1e36}', '\0', '\0']), ('\u{1e39}',
+ ['\u{1e38}', '\0', '\0']), ('\u{1e3b}', ['\u{1e3a}', '\0', '\0']), ('\u{1e3d}', ['\u{1e3c}',
+ '\0', '\0']), ('\u{1e3f}', ['\u{1e3e}', '\0', '\0']), ('\u{1e41}', ['\u{1e40}', '\0',
+ '\0']), ('\u{1e43}', ['\u{1e42}', '\0', '\0']), ('\u{1e45}', ['\u{1e44}', '\0', '\0']),
+ ('\u{1e47}', ['\u{1e46}', '\0', '\0']), ('\u{1e49}', ['\u{1e48}', '\0', '\0']), ('\u{1e4b}',
+ ['\u{1e4a}', '\0', '\0']), ('\u{1e4d}', ['\u{1e4c}', '\0', '\0']), ('\u{1e4f}', ['\u{1e4e}',
+ '\0', '\0']), ('\u{1e51}', ['\u{1e50}', '\0', '\0']), ('\u{1e53}', ['\u{1e52}', '\0',
+ '\0']), ('\u{1e55}', ['\u{1e54}', '\0', '\0']), ('\u{1e57}', ['\u{1e56}', '\0', '\0']),
+ ('\u{1e59}', ['\u{1e58}', '\0', '\0']), ('\u{1e5b}', ['\u{1e5a}', '\0', '\0']), ('\u{1e5d}',
+ ['\u{1e5c}', '\0', '\0']), ('\u{1e5f}', ['\u{1e5e}', '\0', '\0']), ('\u{1e61}', ['\u{1e60}',
+ '\0', '\0']), ('\u{1e63}', ['\u{1e62}', '\0', '\0']), ('\u{1e65}', ['\u{1e64}', '\0',
+ '\0']), ('\u{1e67}', ['\u{1e66}', '\0', '\0']), ('\u{1e69}', ['\u{1e68}', '\0', '\0']),
+ ('\u{1e6b}', ['\u{1e6a}', '\0', '\0']), ('\u{1e6d}', ['\u{1e6c}', '\0', '\0']), ('\u{1e6f}',
+ ['\u{1e6e}', '\0', '\0']), ('\u{1e71}', ['\u{1e70}', '\0', '\0']), ('\u{1e73}', ['\u{1e72}',
+ '\0', '\0']), ('\u{1e75}', ['\u{1e74}', '\0', '\0']), ('\u{1e77}', ['\u{1e76}', '\0',
+ '\0']), ('\u{1e79}', ['\u{1e78}', '\0', '\0']), ('\u{1e7b}', ['\u{1e7a}', '\0', '\0']),
+ ('\u{1e7d}', ['\u{1e7c}', '\0', '\0']), ('\u{1e7f}', ['\u{1e7e}', '\0', '\0']), ('\u{1e81}',
+ ['\u{1e80}', '\0', '\0']), ('\u{1e83}', ['\u{1e82}', '\0', '\0']), ('\u{1e85}', ['\u{1e84}',
+ '\0', '\0']), ('\u{1e87}', ['\u{1e86}', '\0', '\0']), ('\u{1e89}', ['\u{1e88}', '\0',
+ '\0']), ('\u{1e8b}', ['\u{1e8a}', '\0', '\0']), ('\u{1e8d}', ['\u{1e8c}', '\0', '\0']),
+ ('\u{1e8f}', ['\u{1e8e}', '\0', '\0']), ('\u{1e91}', ['\u{1e90}', '\0', '\0']), ('\u{1e93}',
+ ['\u{1e92}', '\0', '\0']), ('\u{1e95}', ['\u{1e94}', '\0', '\0']), ('\u{1e96}', ['\u{48}',
+ '\u{331}', '\0']), ('\u{1e97}', ['\u{54}', '\u{308}', '\0']), ('\u{1e98}', ['\u{57}',
+ '\u{30a}', '\0']), ('\u{1e99}', ['\u{59}', '\u{30a}', '\0']), ('\u{1e9a}', ['\u{41}',
+ '\u{2be}', '\0']), ('\u{1e9b}', ['\u{1e60}', '\0', '\0']), ('\u{1ea1}', ['\u{1ea0}', '\0',
+ '\0']), ('\u{1ea3}', ['\u{1ea2}', '\0', '\0']), ('\u{1ea5}', ['\u{1ea4}', '\0', '\0']),
+ ('\u{1ea7}', ['\u{1ea6}', '\0', '\0']), ('\u{1ea9}', ['\u{1ea8}', '\0', '\0']), ('\u{1eab}',
+ ['\u{1eaa}', '\0', '\0']), ('\u{1ead}', ['\u{1eac}', '\0', '\0']), ('\u{1eaf}', ['\u{1eae}',
+ '\0', '\0']), ('\u{1eb1}', ['\u{1eb0}', '\0', '\0']), ('\u{1eb3}', ['\u{1eb2}', '\0',
+ '\0']), ('\u{1eb5}', ['\u{1eb4}', '\0', '\0']), ('\u{1eb7}', ['\u{1eb6}', '\0', '\0']),
+ ('\u{1eb9}', ['\u{1eb8}', '\0', '\0']), ('\u{1ebb}', ['\u{1eba}', '\0', '\0']), ('\u{1ebd}',
+ ['\u{1ebc}', '\0', '\0']), ('\u{1ebf}', ['\u{1ebe}', '\0', '\0']), ('\u{1ec1}', ['\u{1ec0}',
+ '\0', '\0']), ('\u{1ec3}', ['\u{1ec2}', '\0', '\0']), ('\u{1ec5}', ['\u{1ec4}', '\0',
+ '\0']), ('\u{1ec7}', ['\u{1ec6}', '\0', '\0']), ('\u{1ec9}', ['\u{1ec8}', '\0', '\0']),
+ ('\u{1ecb}', ['\u{1eca}', '\0', '\0']), ('\u{1ecd}', ['\u{1ecc}', '\0', '\0']), ('\u{1ecf}',
+ ['\u{1ece}', '\0', '\0']), ('\u{1ed1}', ['\u{1ed0}', '\0', '\0']), ('\u{1ed3}', ['\u{1ed2}',
+ '\0', '\0']), ('\u{1ed5}', ['\u{1ed4}', '\0', '\0']), ('\u{1ed7}', ['\u{1ed6}', '\0',
+ '\0']), ('\u{1ed9}', ['\u{1ed8}', '\0', '\0']), ('\u{1edb}', ['\u{1eda}', '\0', '\0']),
+ ('\u{1edd}', ['\u{1edc}', '\0', '\0']), ('\u{1edf}', ['\u{1ede}', '\0', '\0']), ('\u{1ee1}',
+ ['\u{1ee0}', '\0', '\0']), ('\u{1ee3}', ['\u{1ee2}', '\0', '\0']), ('\u{1ee5}', ['\u{1ee4}',
+ '\0', '\0']), ('\u{1ee7}', ['\u{1ee6}', '\0', '\0']), ('\u{1ee9}', ['\u{1ee8}', '\0',
+ '\0']), ('\u{1eeb}', ['\u{1eea}', '\0', '\0']), ('\u{1eed}', ['\u{1eec}', '\0', '\0']),
+ ('\u{1eef}', ['\u{1eee}', '\0', '\0']), ('\u{1ef1}', ['\u{1ef0}', '\0', '\0']), ('\u{1ef3}',
+ ['\u{1ef2}', '\0', '\0']), ('\u{1ef5}', ['\u{1ef4}', '\0', '\0']), ('\u{1ef7}', ['\u{1ef6}',
+ '\0', '\0']), ('\u{1ef9}', ['\u{1ef8}', '\0', '\0']), ('\u{1efb}', ['\u{1efa}', '\0',
+ '\0']), ('\u{1efd}', ['\u{1efc}', '\0', '\0']), ('\u{1eff}', ['\u{1efe}', '\0', '\0']),
+ ('\u{1f00}', ['\u{1f08}', '\0', '\0']), ('\u{1f01}', ['\u{1f09}', '\0', '\0']), ('\u{1f02}',
+ ['\u{1f0a}', '\0', '\0']), ('\u{1f03}', ['\u{1f0b}', '\0', '\0']), ('\u{1f04}', ['\u{1f0c}',
+ '\0', '\0']), ('\u{1f05}', ['\u{1f0d}', '\0', '\0']), ('\u{1f06}', ['\u{1f0e}', '\0',
+ '\0']), ('\u{1f07}', ['\u{1f0f}', '\0', '\0']), ('\u{1f10}', ['\u{1f18}', '\0', '\0']),
+ ('\u{1f11}', ['\u{1f19}', '\0', '\0']), ('\u{1f12}', ['\u{1f1a}', '\0', '\0']), ('\u{1f13}',
+ ['\u{1f1b}', '\0', '\0']), ('\u{1f14}', ['\u{1f1c}', '\0', '\0']), ('\u{1f15}', ['\u{1f1d}',
+ '\0', '\0']), ('\u{1f20}', ['\u{1f28}', '\0', '\0']), ('\u{1f21}', ['\u{1f29}', '\0',
+ '\0']), ('\u{1f22}', ['\u{1f2a}', '\0', '\0']), ('\u{1f23}', ['\u{1f2b}', '\0', '\0']),
+ ('\u{1f24}', ['\u{1f2c}', '\0', '\0']), ('\u{1f25}', ['\u{1f2d}', '\0', '\0']), ('\u{1f26}',
+ ['\u{1f2e}', '\0', '\0']), ('\u{1f27}', ['\u{1f2f}', '\0', '\0']), ('\u{1f30}', ['\u{1f38}',
+ '\0', '\0']), ('\u{1f31}', ['\u{1f39}', '\0', '\0']), ('\u{1f32}', ['\u{1f3a}', '\0',
+ '\0']), ('\u{1f33}', ['\u{1f3b}', '\0', '\0']), ('\u{1f34}', ['\u{1f3c}', '\0', '\0']),
+ ('\u{1f35}', ['\u{1f3d}', '\0', '\0']), ('\u{1f36}', ['\u{1f3e}', '\0', '\0']), ('\u{1f37}',
+ ['\u{1f3f}', '\0', '\0']), ('\u{1f40}', ['\u{1f48}', '\0', '\0']), ('\u{1f41}', ['\u{1f49}',
+ '\0', '\0']), ('\u{1f42}', ['\u{1f4a}', '\0', '\0']), ('\u{1f43}', ['\u{1f4b}', '\0',
+ '\0']), ('\u{1f44}', ['\u{1f4c}', '\0', '\0']), ('\u{1f45}', ['\u{1f4d}', '\0', '\0']),
+ ('\u{1f50}', ['\u{3a5}', '\u{313}', '\0']), ('\u{1f51}', ['\u{1f59}', '\0', '\0']),
+ ('\u{1f52}', ['\u{3a5}', '\u{313}', '\u{300}']), ('\u{1f53}', ['\u{1f5b}', '\0', '\0']),
+ ('\u{1f54}', ['\u{3a5}', '\u{313}', '\u{301}']), ('\u{1f55}', ['\u{1f5d}', '\0', '\0']),
+ ('\u{1f56}', ['\u{3a5}', '\u{313}', '\u{342}']), ('\u{1f57}', ['\u{1f5f}', '\0', '\0']),
+ ('\u{1f60}', ['\u{1f68}', '\0', '\0']), ('\u{1f61}', ['\u{1f69}', '\0', '\0']), ('\u{1f62}',
+ ['\u{1f6a}', '\0', '\0']), ('\u{1f63}', ['\u{1f6b}', '\0', '\0']), ('\u{1f64}', ['\u{1f6c}',
+ '\0', '\0']), ('\u{1f65}', ['\u{1f6d}', '\0', '\0']), ('\u{1f66}', ['\u{1f6e}', '\0',
+ '\0']), ('\u{1f67}', ['\u{1f6f}', '\0', '\0']), ('\u{1f70}', ['\u{1fba}', '\0', '\0']),
+ ('\u{1f71}', ['\u{1fbb}', '\0', '\0']), ('\u{1f72}', ['\u{1fc8}', '\0', '\0']), ('\u{1f73}',
+ ['\u{1fc9}', '\0', '\0']), ('\u{1f74}', ['\u{1fca}', '\0', '\0']), ('\u{1f75}', ['\u{1fcb}',
+ '\0', '\0']), ('\u{1f76}', ['\u{1fda}', '\0', '\0']), ('\u{1f77}', ['\u{1fdb}', '\0',
+ '\0']), ('\u{1f78}', ['\u{1ff8}', '\0', '\0']), ('\u{1f79}', ['\u{1ff9}', '\0', '\0']),
+ ('\u{1f7a}', ['\u{1fea}', '\0', '\0']), ('\u{1f7b}', ['\u{1feb}', '\0', '\0']), ('\u{1f7c}',
+ ['\u{1ffa}', '\0', '\0']), ('\u{1f7d}', ['\u{1ffb}', '\0', '\0']), ('\u{1f80}', ['\u{1f08}',
+ '\u{399}', '\0']), ('\u{1f81}', ['\u{1f09}', '\u{399}', '\0']), ('\u{1f82}', ['\u{1f0a}',
+ '\u{399}', '\0']), ('\u{1f83}', ['\u{1f0b}', '\u{399}', '\0']), ('\u{1f84}', ['\u{1f0c}',
+ '\u{399}', '\0']), ('\u{1f85}', ['\u{1f0d}', '\u{399}', '\0']), ('\u{1f86}', ['\u{1f0e}',
+ '\u{399}', '\0']), ('\u{1f87}', ['\u{1f0f}', '\u{399}', '\0']), ('\u{1f88}', ['\u{1f08}',
+ '\u{399}', '\0']), ('\u{1f89}', ['\u{1f09}', '\u{399}', '\0']), ('\u{1f8a}', ['\u{1f0a}',
+ '\u{399}', '\0']), ('\u{1f8b}', ['\u{1f0b}', '\u{399}', '\0']), ('\u{1f8c}', ['\u{1f0c}',
+ '\u{399}', '\0']), ('\u{1f8d}', ['\u{1f0d}', '\u{399}', '\0']), ('\u{1f8e}', ['\u{1f0e}',
+ '\u{399}', '\0']), ('\u{1f8f}', ['\u{1f0f}', '\u{399}', '\0']), ('\u{1f90}', ['\u{1f28}',
+ '\u{399}', '\0']), ('\u{1f91}', ['\u{1f29}', '\u{399}', '\0']), ('\u{1f92}', ['\u{1f2a}',
+ '\u{399}', '\0']), ('\u{1f93}', ['\u{1f2b}', '\u{399}', '\0']), ('\u{1f94}', ['\u{1f2c}',
+ '\u{399}', '\0']), ('\u{1f95}', ['\u{1f2d}', '\u{399}', '\0']), ('\u{1f96}', ['\u{1f2e}',
+ '\u{399}', '\0']), ('\u{1f97}', ['\u{1f2f}', '\u{399}', '\0']), ('\u{1f98}', ['\u{1f28}',
+ '\u{399}', '\0']), ('\u{1f99}', ['\u{1f29}', '\u{399}', '\0']), ('\u{1f9a}', ['\u{1f2a}',
+ '\u{399}', '\0']), ('\u{1f9b}', ['\u{1f2b}', '\u{399}', '\0']), ('\u{1f9c}', ['\u{1f2c}',
+ '\u{399}', '\0']), ('\u{1f9d}', ['\u{1f2d}', '\u{399}', '\0']), ('\u{1f9e}', ['\u{1f2e}',
+ '\u{399}', '\0']), ('\u{1f9f}', ['\u{1f2f}', '\u{399}', '\0']), ('\u{1fa0}', ['\u{1f68}',
+ '\u{399}', '\0']), ('\u{1fa1}', ['\u{1f69}', '\u{399}', '\0']), ('\u{1fa2}', ['\u{1f6a}',
+ '\u{399}', '\0']), ('\u{1fa3}', ['\u{1f6b}', '\u{399}', '\0']), ('\u{1fa4}', ['\u{1f6c}',
+ '\u{399}', '\0']), ('\u{1fa5}', ['\u{1f6d}', '\u{399}', '\0']), ('\u{1fa6}', ['\u{1f6e}',
+ '\u{399}', '\0']), ('\u{1fa7}', ['\u{1f6f}', '\u{399}', '\0']), ('\u{1fa8}', ['\u{1f68}',
+ '\u{399}', '\0']), ('\u{1fa9}', ['\u{1f69}', '\u{399}', '\0']), ('\u{1faa}', ['\u{1f6a}',
+ '\u{399}', '\0']), ('\u{1fab}', ['\u{1f6b}', '\u{399}', '\0']), ('\u{1fac}', ['\u{1f6c}',
+ '\u{399}', '\0']), ('\u{1fad}', ['\u{1f6d}', '\u{399}', '\0']), ('\u{1fae}', ['\u{1f6e}',
+ '\u{399}', '\0']), ('\u{1faf}', ['\u{1f6f}', '\u{399}', '\0']), ('\u{1fb0}', ['\u{1fb8}',
+ '\0', '\0']), ('\u{1fb1}', ['\u{1fb9}', '\0', '\0']), ('\u{1fb2}', ['\u{1fba}', '\u{399}',
+ '\0']), ('\u{1fb3}', ['\u{391}', '\u{399}', '\0']), ('\u{1fb4}', ['\u{386}', '\u{399}',
+ '\0']), ('\u{1fb6}', ['\u{391}', '\u{342}', '\0']), ('\u{1fb7}', ['\u{391}', '\u{342}',
+ '\u{399}']), ('\u{1fbc}', ['\u{391}', '\u{399}', '\0']), ('\u{1fbe}', ['\u{399}', '\0',
+ '\0']), ('\u{1fc2}', ['\u{1fca}', '\u{399}', '\0']), ('\u{1fc3}', ['\u{397}', '\u{399}',
+ '\0']), ('\u{1fc4}', ['\u{389}', '\u{399}', '\0']), ('\u{1fc6}', ['\u{397}', '\u{342}',
+ '\0']), ('\u{1fc7}', ['\u{397}', '\u{342}', '\u{399}']), ('\u{1fcc}', ['\u{397}', '\u{399}',
+ '\0']), ('\u{1fd0}', ['\u{1fd8}', '\0', '\0']), ('\u{1fd1}', ['\u{1fd9}', '\0', '\0']),
+ ('\u{1fd2}', ['\u{399}', '\u{308}', '\u{300}']), ('\u{1fd3}', ['\u{399}', '\u{308}',
+ '\u{301}']), ('\u{1fd6}', ['\u{399}', '\u{342}', '\0']), ('\u{1fd7}', ['\u{399}', '\u{308}',
+ '\u{342}']), ('\u{1fe0}', ['\u{1fe8}', '\0', '\0']), ('\u{1fe1}', ['\u{1fe9}', '\0', '\0']),
+ ('\u{1fe2}', ['\u{3a5}', '\u{308}', '\u{300}']), ('\u{1fe3}', ['\u{3a5}', '\u{308}',
+ '\u{301}']), ('\u{1fe4}', ['\u{3a1}', '\u{313}', '\0']), ('\u{1fe5}', ['\u{1fec}', '\0',
+ '\0']), ('\u{1fe6}', ['\u{3a5}', '\u{342}', '\0']), ('\u{1fe7}', ['\u{3a5}', '\u{308}',
+ '\u{342}']), ('\u{1ff2}', ['\u{1ffa}', '\u{399}', '\0']), ('\u{1ff3}', ['\u{3a9}',
+ '\u{399}', '\0']), ('\u{1ff4}', ['\u{38f}', '\u{399}', '\0']), ('\u{1ff6}', ['\u{3a9}',
+ '\u{342}', '\0']), ('\u{1ff7}', ['\u{3a9}', '\u{342}', '\u{399}']), ('\u{1ffc}', ['\u{3a9}',
+ '\u{399}', '\0']), ('\u{214e}', ['\u{2132}', '\0', '\0']), ('\u{2170}', ['\u{2160}', '\0',
+ '\0']), ('\u{2171}', ['\u{2161}', '\0', '\0']), ('\u{2172}', ['\u{2162}', '\0', '\0']),
+ ('\u{2173}', ['\u{2163}', '\0', '\0']), ('\u{2174}', ['\u{2164}', '\0', '\0']), ('\u{2175}',
+ ['\u{2165}', '\0', '\0']), ('\u{2176}', ['\u{2166}', '\0', '\0']), ('\u{2177}', ['\u{2167}',
+ '\0', '\0']), ('\u{2178}', ['\u{2168}', '\0', '\0']), ('\u{2179}', ['\u{2169}', '\0',
+ '\0']), ('\u{217a}', ['\u{216a}', '\0', '\0']), ('\u{217b}', ['\u{216b}', '\0', '\0']),
+ ('\u{217c}', ['\u{216c}', '\0', '\0']), ('\u{217d}', ['\u{216d}', '\0', '\0']), ('\u{217e}',
+ ['\u{216e}', '\0', '\0']), ('\u{217f}', ['\u{216f}', '\0', '\0']), ('\u{2184}', ['\u{2183}',
+ '\0', '\0']), ('\u{24d0}', ['\u{24b6}', '\0', '\0']), ('\u{24d1}', ['\u{24b7}', '\0',
+ '\0']), ('\u{24d2}', ['\u{24b8}', '\0', '\0']), ('\u{24d3}', ['\u{24b9}', '\0', '\0']),
+ ('\u{24d4}', ['\u{24ba}', '\0', '\0']), ('\u{24d5}', ['\u{24bb}', '\0', '\0']), ('\u{24d6}',
+ ['\u{24bc}', '\0', '\0']), ('\u{24d7}', ['\u{24bd}', '\0', '\0']), ('\u{24d8}', ['\u{24be}',
+ '\0', '\0']), ('\u{24d9}', ['\u{24bf}', '\0', '\0']), ('\u{24da}', ['\u{24c0}', '\0',
+ '\0']), ('\u{24db}', ['\u{24c1}', '\0', '\0']), ('\u{24dc}', ['\u{24c2}', '\0', '\0']),
+ ('\u{24dd}', ['\u{24c3}', '\0', '\0']), ('\u{24de}', ['\u{24c4}', '\0', '\0']), ('\u{24df}',
+ ['\u{24c5}', '\0', '\0']), ('\u{24e0}', ['\u{24c6}', '\0', '\0']), ('\u{24e1}', ['\u{24c7}',
+ '\0', '\0']), ('\u{24e2}', ['\u{24c8}', '\0', '\0']), ('\u{24e3}', ['\u{24c9}', '\0',
+ '\0']), ('\u{24e4}', ['\u{24ca}', '\0', '\0']), ('\u{24e5}', ['\u{24cb}', '\0', '\0']),
+ ('\u{24e6}', ['\u{24cc}', '\0', '\0']), ('\u{24e7}', ['\u{24cd}', '\0', '\0']), ('\u{24e8}',
+ ['\u{24ce}', '\0', '\0']), ('\u{24e9}', ['\u{24cf}', '\0', '\0']), ('\u{2c30}', ['\u{2c00}',
+ '\0', '\0']), ('\u{2c31}', ['\u{2c01}', '\0', '\0']), ('\u{2c32}', ['\u{2c02}', '\0',
+ '\0']), ('\u{2c33}', ['\u{2c03}', '\0', '\0']), ('\u{2c34}', ['\u{2c04}', '\0', '\0']),
+ ('\u{2c35}', ['\u{2c05}', '\0', '\0']), ('\u{2c36}', ['\u{2c06}', '\0', '\0']), ('\u{2c37}',
+ ['\u{2c07}', '\0', '\0']), ('\u{2c38}', ['\u{2c08}', '\0', '\0']), ('\u{2c39}', ['\u{2c09}',
+ '\0', '\0']), ('\u{2c3a}', ['\u{2c0a}', '\0', '\0']), ('\u{2c3b}', ['\u{2c0b}', '\0',
+ '\0']), ('\u{2c3c}', ['\u{2c0c}', '\0', '\0']), ('\u{2c3d}', ['\u{2c0d}', '\0', '\0']),
+ ('\u{2c3e}', ['\u{2c0e}', '\0', '\0']), ('\u{2c3f}', ['\u{2c0f}', '\0', '\0']), ('\u{2c40}',
+ ['\u{2c10}', '\0', '\0']), ('\u{2c41}', ['\u{2c11}', '\0', '\0']), ('\u{2c42}', ['\u{2c12}',
+ '\0', '\0']), ('\u{2c43}', ['\u{2c13}', '\0', '\0']), ('\u{2c44}', ['\u{2c14}', '\0',
+ '\0']), ('\u{2c45}', ['\u{2c15}', '\0', '\0']), ('\u{2c46}', ['\u{2c16}', '\0', '\0']),
+ ('\u{2c47}', ['\u{2c17}', '\0', '\0']), ('\u{2c48}', ['\u{2c18}', '\0', '\0']), ('\u{2c49}',
+ ['\u{2c19}', '\0', '\0']), ('\u{2c4a}', ['\u{2c1a}', '\0', '\0']), ('\u{2c4b}', ['\u{2c1b}',
+ '\0', '\0']), ('\u{2c4c}', ['\u{2c1c}', '\0', '\0']), ('\u{2c4d}', ['\u{2c1d}', '\0',
+ '\0']), ('\u{2c4e}', ['\u{2c1e}', '\0', '\0']), ('\u{2c4f}', ['\u{2c1f}', '\0', '\0']),
+ ('\u{2c50}', ['\u{2c20}', '\0', '\0']), ('\u{2c51}', ['\u{2c21}', '\0', '\0']), ('\u{2c52}',
+ ['\u{2c22}', '\0', '\0']), ('\u{2c53}', ['\u{2c23}', '\0', '\0']), ('\u{2c54}', ['\u{2c24}',
+ '\0', '\0']), ('\u{2c55}', ['\u{2c25}', '\0', '\0']), ('\u{2c56}', ['\u{2c26}', '\0',
+ '\0']), ('\u{2c57}', ['\u{2c27}', '\0', '\0']), ('\u{2c58}', ['\u{2c28}', '\0', '\0']),
+ ('\u{2c59}', ['\u{2c29}', '\0', '\0']), ('\u{2c5a}', ['\u{2c2a}', '\0', '\0']), ('\u{2c5b}',
+ ['\u{2c2b}', '\0', '\0']), ('\u{2c5c}', ['\u{2c2c}', '\0', '\0']), ('\u{2c5d}', ['\u{2c2d}',
+ '\0', '\0']), ('\u{2c5e}', ['\u{2c2e}', '\0', '\0']), ('\u{2c61}', ['\u{2c60}', '\0',
+ '\0']), ('\u{2c65}', ['\u{23a}', '\0', '\0']), ('\u{2c66}', ['\u{23e}', '\0', '\0']),
+ ('\u{2c68}', ['\u{2c67}', '\0', '\0']), ('\u{2c6a}', ['\u{2c69}', '\0', '\0']), ('\u{2c6c}',
+ ['\u{2c6b}', '\0', '\0']), ('\u{2c73}', ['\u{2c72}', '\0', '\0']), ('\u{2c76}', ['\u{2c75}',
+ '\0', '\0']), ('\u{2c81}', ['\u{2c80}', '\0', '\0']), ('\u{2c83}', ['\u{2c82}', '\0',
+ '\0']), ('\u{2c85}', ['\u{2c84}', '\0', '\0']), ('\u{2c87}', ['\u{2c86}', '\0', '\0']),
+ ('\u{2c89}', ['\u{2c88}', '\0', '\0']), ('\u{2c8b}', ['\u{2c8a}', '\0', '\0']), ('\u{2c8d}',
+ ['\u{2c8c}', '\0', '\0']), ('\u{2c8f}', ['\u{2c8e}', '\0', '\0']), ('\u{2c91}', ['\u{2c90}',
+ '\0', '\0']), ('\u{2c93}', ['\u{2c92}', '\0', '\0']), ('\u{2c95}', ['\u{2c94}', '\0',
+ '\0']), ('\u{2c97}', ['\u{2c96}', '\0', '\0']), ('\u{2c99}', ['\u{2c98}', '\0', '\0']),
+ ('\u{2c9b}', ['\u{2c9a}', '\0', '\0']), ('\u{2c9d}', ['\u{2c9c}', '\0', '\0']), ('\u{2c9f}',
+ ['\u{2c9e}', '\0', '\0']), ('\u{2ca1}', ['\u{2ca0}', '\0', '\0']), ('\u{2ca3}', ['\u{2ca2}',
+ '\0', '\0']), ('\u{2ca5}', ['\u{2ca4}', '\0', '\0']), ('\u{2ca7}', ['\u{2ca6}', '\0',
+ '\0']), ('\u{2ca9}', ['\u{2ca8}', '\0', '\0']), ('\u{2cab}', ['\u{2caa}', '\0', '\0']),
+ ('\u{2cad}', ['\u{2cac}', '\0', '\0']), ('\u{2caf}', ['\u{2cae}', '\0', '\0']), ('\u{2cb1}',
+ ['\u{2cb0}', '\0', '\0']), ('\u{2cb3}', ['\u{2cb2}', '\0', '\0']), ('\u{2cb5}', ['\u{2cb4}',
+ '\0', '\0']), ('\u{2cb7}', ['\u{2cb6}', '\0', '\0']), ('\u{2cb9}', ['\u{2cb8}', '\0',
+ '\0']), ('\u{2cbb}', ['\u{2cba}', '\0', '\0']), ('\u{2cbd}', ['\u{2cbc}', '\0', '\0']),
+ ('\u{2cbf}', ['\u{2cbe}', '\0', '\0']), ('\u{2cc1}', ['\u{2cc0}', '\0', '\0']), ('\u{2cc3}',
+ ['\u{2cc2}', '\0', '\0']), ('\u{2cc5}', ['\u{2cc4}', '\0', '\0']), ('\u{2cc7}', ['\u{2cc6}',
+ '\0', '\0']), ('\u{2cc9}', ['\u{2cc8}', '\0', '\0']), ('\u{2ccb}', ['\u{2cca}', '\0',
+ '\0']), ('\u{2ccd}', ['\u{2ccc}', '\0', '\0']), ('\u{2ccf}', ['\u{2cce}', '\0', '\0']),
+ ('\u{2cd1}', ['\u{2cd0}', '\0', '\0']), ('\u{2cd3}', ['\u{2cd2}', '\0', '\0']), ('\u{2cd5}',
+ ['\u{2cd4}', '\0', '\0']), ('\u{2cd7}', ['\u{2cd6}', '\0', '\0']), ('\u{2cd9}', ['\u{2cd8}',
+ '\0', '\0']), ('\u{2cdb}', ['\u{2cda}', '\0', '\0']), ('\u{2cdd}', ['\u{2cdc}', '\0',
+ '\0']), ('\u{2cdf}', ['\u{2cde}', '\0', '\0']), ('\u{2ce1}', ['\u{2ce0}', '\0', '\0']),
+ ('\u{2ce3}', ['\u{2ce2}', '\0', '\0']), ('\u{2cec}', ['\u{2ceb}', '\0', '\0']), ('\u{2cee}',
+ ['\u{2ced}', '\0', '\0']), ('\u{2cf3}', ['\u{2cf2}', '\0', '\0']), ('\u{2d00}', ['\u{10a0}',
+ '\0', '\0']), ('\u{2d01}', ['\u{10a1}', '\0', '\0']), ('\u{2d02}', ['\u{10a2}', '\0',
+ '\0']), ('\u{2d03}', ['\u{10a3}', '\0', '\0']), ('\u{2d04}', ['\u{10a4}', '\0', '\0']),
+ ('\u{2d05}', ['\u{10a5}', '\0', '\0']), ('\u{2d06}', ['\u{10a6}', '\0', '\0']), ('\u{2d07}',
+ ['\u{10a7}', '\0', '\0']), ('\u{2d08}', ['\u{10a8}', '\0', '\0']), ('\u{2d09}', ['\u{10a9}',
+ '\0', '\0']), ('\u{2d0a}', ['\u{10aa}', '\0', '\0']), ('\u{2d0b}', ['\u{10ab}', '\0',
+ '\0']), ('\u{2d0c}', ['\u{10ac}', '\0', '\0']), ('\u{2d0d}', ['\u{10ad}', '\0', '\0']),
+ ('\u{2d0e}', ['\u{10ae}', '\0', '\0']), ('\u{2d0f}', ['\u{10af}', '\0', '\0']), ('\u{2d10}',
+ ['\u{10b0}', '\0', '\0']), ('\u{2d11}', ['\u{10b1}', '\0', '\0']), ('\u{2d12}', ['\u{10b2}',
+ '\0', '\0']), ('\u{2d13}', ['\u{10b3}', '\0', '\0']), ('\u{2d14}', ['\u{10b4}', '\0',
+ '\0']), ('\u{2d15}', ['\u{10b5}', '\0', '\0']), ('\u{2d16}', ['\u{10b6}', '\0', '\0']),
+ ('\u{2d17}', ['\u{10b7}', '\0', '\0']), ('\u{2d18}', ['\u{10b8}', '\0', '\0']), ('\u{2d19}',
+ ['\u{10b9}', '\0', '\0']), ('\u{2d1a}', ['\u{10ba}', '\0', '\0']), ('\u{2d1b}', ['\u{10bb}',
+ '\0', '\0']), ('\u{2d1c}', ['\u{10bc}', '\0', '\0']), ('\u{2d1d}', ['\u{10bd}', '\0',
+ '\0']), ('\u{2d1e}', ['\u{10be}', '\0', '\0']), ('\u{2d1f}', ['\u{10bf}', '\0', '\0']),
+ ('\u{2d20}', ['\u{10c0}', '\0', '\0']), ('\u{2d21}', ['\u{10c1}', '\0', '\0']), ('\u{2d22}',
+ ['\u{10c2}', '\0', '\0']), ('\u{2d23}', ['\u{10c3}', '\0', '\0']), ('\u{2d24}', ['\u{10c4}',
+ '\0', '\0']), ('\u{2d25}', ['\u{10c5}', '\0', '\0']), ('\u{2d27}', ['\u{10c7}', '\0',
+ '\0']), ('\u{2d2d}', ['\u{10cd}', '\0', '\0']), ('\u{a641}', ['\u{a640}', '\0', '\0']),
+ ('\u{a643}', ['\u{a642}', '\0', '\0']), ('\u{a645}', ['\u{a644}', '\0', '\0']), ('\u{a647}',
+ ['\u{a646}', '\0', '\0']), ('\u{a649}', ['\u{a648}', '\0', '\0']), ('\u{a64b}', ['\u{a64a}',
+ '\0', '\0']), ('\u{a64d}', ['\u{a64c}', '\0', '\0']), ('\u{a64f}', ['\u{a64e}', '\0',
+ '\0']), ('\u{a651}', ['\u{a650}', '\0', '\0']), ('\u{a653}', ['\u{a652}', '\0', '\0']),
+ ('\u{a655}', ['\u{a654}', '\0', '\0']), ('\u{a657}', ['\u{a656}', '\0', '\0']), ('\u{a659}',
+ ['\u{a658}', '\0', '\0']), ('\u{a65b}', ['\u{a65a}', '\0', '\0']), ('\u{a65d}', ['\u{a65c}',
+ '\0', '\0']), ('\u{a65f}', ['\u{a65e}', '\0', '\0']), ('\u{a661}', ['\u{a660}', '\0',
+ '\0']), ('\u{a663}', ['\u{a662}', '\0', '\0']), ('\u{a665}', ['\u{a664}', '\0', '\0']),
+ ('\u{a667}', ['\u{a666}', '\0', '\0']), ('\u{a669}', ['\u{a668}', '\0', '\0']), ('\u{a66b}',
+ ['\u{a66a}', '\0', '\0']), ('\u{a66d}', ['\u{a66c}', '\0', '\0']), ('\u{a681}', ['\u{a680}',
+ '\0', '\0']), ('\u{a683}', ['\u{a682}', '\0', '\0']), ('\u{a685}', ['\u{a684}', '\0',
+ '\0']), ('\u{a687}', ['\u{a686}', '\0', '\0']), ('\u{a689}', ['\u{a688}', '\0', '\0']),
+ ('\u{a68b}', ['\u{a68a}', '\0', '\0']), ('\u{a68d}', ['\u{a68c}', '\0', '\0']), ('\u{a68f}',
+ ['\u{a68e}', '\0', '\0']), ('\u{a691}', ['\u{a690}', '\0', '\0']), ('\u{a693}', ['\u{a692}',
+ '\0', '\0']), ('\u{a695}', ['\u{a694}', '\0', '\0']), ('\u{a697}', ['\u{a696}', '\0',
+ '\0']), ('\u{a699}', ['\u{a698}', '\0', '\0']), ('\u{a69b}', ['\u{a69a}', '\0', '\0']),
+ ('\u{a723}', ['\u{a722}', '\0', '\0']), ('\u{a725}', ['\u{a724}', '\0', '\0']), ('\u{a727}',
+ ['\u{a726}', '\0', '\0']), ('\u{a729}', ['\u{a728}', '\0', '\0']), ('\u{a72b}', ['\u{a72a}',
+ '\0', '\0']), ('\u{a72d}', ['\u{a72c}', '\0', '\0']), ('\u{a72f}', ['\u{a72e}', '\0',
+ '\0']), ('\u{a733}', ['\u{a732}', '\0', '\0']), ('\u{a735}', ['\u{a734}', '\0', '\0']),
+ ('\u{a737}', ['\u{a736}', '\0', '\0']), ('\u{a739}', ['\u{a738}', '\0', '\0']), ('\u{a73b}',
+ ['\u{a73a}', '\0', '\0']), ('\u{a73d}', ['\u{a73c}', '\0', '\0']), ('\u{a73f}', ['\u{a73e}',
+ '\0', '\0']), ('\u{a741}', ['\u{a740}', '\0', '\0']), ('\u{a743}', ['\u{a742}', '\0',
+ '\0']), ('\u{a745}', ['\u{a744}', '\0', '\0']), ('\u{a747}', ['\u{a746}', '\0', '\0']),
+ ('\u{a749}', ['\u{a748}', '\0', '\0']), ('\u{a74b}', ['\u{a74a}', '\0', '\0']), ('\u{a74d}',
+ ['\u{a74c}', '\0', '\0']), ('\u{a74f}', ['\u{a74e}', '\0', '\0']), ('\u{a751}', ['\u{a750}',
+ '\0', '\0']), ('\u{a753}', ['\u{a752}', '\0', '\0']), ('\u{a755}', ['\u{a754}', '\0',
+ '\0']), ('\u{a757}', ['\u{a756}', '\0', '\0']), ('\u{a759}', ['\u{a758}', '\0', '\0']),
+ ('\u{a75b}', ['\u{a75a}', '\0', '\0']), ('\u{a75d}', ['\u{a75c}', '\0', '\0']), ('\u{a75f}',
+ ['\u{a75e}', '\0', '\0']), ('\u{a761}', ['\u{a760}', '\0', '\0']), ('\u{a763}', ['\u{a762}',
+ '\0', '\0']), ('\u{a765}', ['\u{a764}', '\0', '\0']), ('\u{a767}', ['\u{a766}', '\0',
+ '\0']), ('\u{a769}', ['\u{a768}', '\0', '\0']), ('\u{a76b}', ['\u{a76a}', '\0', '\0']),
+ ('\u{a76d}', ['\u{a76c}', '\0', '\0']), ('\u{a76f}', ['\u{a76e}', '\0', '\0']), ('\u{a77a}',
+ ['\u{a779}', '\0', '\0']), ('\u{a77c}', ['\u{a77b}', '\0', '\0']), ('\u{a77f}', ['\u{a77e}',
+ '\0', '\0']), ('\u{a781}', ['\u{a780}', '\0', '\0']), ('\u{a783}', ['\u{a782}', '\0',
+ '\0']), ('\u{a785}', ['\u{a784}', '\0', '\0']), ('\u{a787}', ['\u{a786}', '\0', '\0']),
+ ('\u{a78c}', ['\u{a78b}', '\0', '\0']), ('\u{a791}', ['\u{a790}', '\0', '\0']), ('\u{a793}',
+ ['\u{a792}', '\0', '\0']), ('\u{a797}', ['\u{a796}', '\0', '\0']), ('\u{a799}', ['\u{a798}',
+ '\0', '\0']), ('\u{a79b}', ['\u{a79a}', '\0', '\0']), ('\u{a79d}', ['\u{a79c}', '\0',
+ '\0']), ('\u{a79f}', ['\u{a79e}', '\0', '\0']), ('\u{a7a1}', ['\u{a7a0}', '\0', '\0']),
+ ('\u{a7a3}', ['\u{a7a2}', '\0', '\0']), ('\u{a7a5}', ['\u{a7a4}', '\0', '\0']), ('\u{a7a7}',
+ ['\u{a7a6}', '\0', '\0']), ('\u{a7a9}', ['\u{a7a8}', '\0', '\0']), ('\u{fb00}', ['\u{46}',
+ '\u{46}', '\0']), ('\u{fb01}', ['\u{46}', '\u{49}', '\0']), ('\u{fb02}', ['\u{46}',
+ '\u{4c}', '\0']), ('\u{fb03}', ['\u{46}', '\u{46}', '\u{49}']), ('\u{fb04}', ['\u{46}',
+ '\u{46}', '\u{4c}']), ('\u{fb05}', ['\u{53}', '\u{54}', '\0']), ('\u{fb06}', ['\u{53}',
+ '\u{54}', '\0']), ('\u{fb13}', ['\u{544}', '\u{546}', '\0']), ('\u{fb14}', ['\u{544}',
+ '\u{535}', '\0']), ('\u{fb15}', ['\u{544}', '\u{53b}', '\0']), ('\u{fb16}', ['\u{54e}',
+ '\u{546}', '\0']), ('\u{fb17}', ['\u{544}', '\u{53d}', '\0']), ('\u{ff41}', ['\u{ff21}',
+ '\0', '\0']), ('\u{ff42}', ['\u{ff22}', '\0', '\0']), ('\u{ff43}', ['\u{ff23}', '\0',
+ '\0']), ('\u{ff44}', ['\u{ff24}', '\0', '\0']), ('\u{ff45}', ['\u{ff25}', '\0', '\0']),
+ ('\u{ff46}', ['\u{ff26}', '\0', '\0']), ('\u{ff47}', ['\u{ff27}', '\0', '\0']), ('\u{ff48}',
+ ['\u{ff28}', '\0', '\0']), ('\u{ff49}', ['\u{ff29}', '\0', '\0']), ('\u{ff4a}', ['\u{ff2a}',
+ '\0', '\0']), ('\u{ff4b}', ['\u{ff2b}', '\0', '\0']), ('\u{ff4c}', ['\u{ff2c}', '\0',
+ '\0']), ('\u{ff4d}', ['\u{ff2d}', '\0', '\0']), ('\u{ff4e}', ['\u{ff2e}', '\0', '\0']),
+ ('\u{ff4f}', ['\u{ff2f}', '\0', '\0']), ('\u{ff50}', ['\u{ff30}', '\0', '\0']), ('\u{ff51}',
+ ['\u{ff31}', '\0', '\0']), ('\u{ff52}', ['\u{ff32}', '\0', '\0']), ('\u{ff53}', ['\u{ff33}',
+ '\0', '\0']), ('\u{ff54}', ['\u{ff34}', '\0', '\0']), ('\u{ff55}', ['\u{ff35}', '\0',
+ '\0']), ('\u{ff56}', ['\u{ff36}', '\0', '\0']), ('\u{ff57}', ['\u{ff37}', '\0', '\0']),
+ ('\u{ff58}', ['\u{ff38}', '\0', '\0']), ('\u{ff59}', ['\u{ff39}', '\0', '\0']), ('\u{ff5a}',
+ ['\u{ff3a}', '\0', '\0']), ('\u{10428}', ['\u{10400}', '\0', '\0']), ('\u{10429}',
+ ['\u{10401}', '\0', '\0']), ('\u{1042a}', ['\u{10402}', '\0', '\0']), ('\u{1042b}',
+ ['\u{10403}', '\0', '\0']), ('\u{1042c}', ['\u{10404}', '\0', '\0']), ('\u{1042d}',
+ ['\u{10405}', '\0', '\0']), ('\u{1042e}', ['\u{10406}', '\0', '\0']), ('\u{1042f}',
+ ['\u{10407}', '\0', '\0']), ('\u{10430}', ['\u{10408}', '\0', '\0']), ('\u{10431}',
+ ['\u{10409}', '\0', '\0']), ('\u{10432}', ['\u{1040a}', '\0', '\0']), ('\u{10433}',
+ ['\u{1040b}', '\0', '\0']), ('\u{10434}', ['\u{1040c}', '\0', '\0']), ('\u{10435}',
+ ['\u{1040d}', '\0', '\0']), ('\u{10436}', ['\u{1040e}', '\0', '\0']), ('\u{10437}',
+ ['\u{1040f}', '\0', '\0']), ('\u{10438}', ['\u{10410}', '\0', '\0']), ('\u{10439}',
+ ['\u{10411}', '\0', '\0']), ('\u{1043a}', ['\u{10412}', '\0', '\0']), ('\u{1043b}',
+ ['\u{10413}', '\0', '\0']), ('\u{1043c}', ['\u{10414}', '\0', '\0']), ('\u{1043d}',
+ ['\u{10415}', '\0', '\0']), ('\u{1043e}', ['\u{10416}', '\0', '\0']), ('\u{1043f}',
+ ['\u{10417}', '\0', '\0']), ('\u{10440}', ['\u{10418}', '\0', '\0']), ('\u{10441}',
+ ['\u{10419}', '\0', '\0']), ('\u{10442}', ['\u{1041a}', '\0', '\0']), ('\u{10443}',
+ ['\u{1041b}', '\0', '\0']), ('\u{10444}', ['\u{1041c}', '\0', '\0']), ('\u{10445}',
+ ['\u{1041d}', '\0', '\0']), ('\u{10446}', ['\u{1041e}', '\0', '\0']), ('\u{10447}',
+ ['\u{1041f}', '\0', '\0']), ('\u{10448}', ['\u{10420}', '\0', '\0']), ('\u{10449}',
+ ['\u{10421}', '\0', '\0']), ('\u{1044a}', ['\u{10422}', '\0', '\0']), ('\u{1044b}',
+ ['\u{10423}', '\0', '\0']), ('\u{1044c}', ['\u{10424}', '\0', '\0']), ('\u{1044d}',
+ ['\u{10425}', '\0', '\0']), ('\u{1044e}', ['\u{10426}', '\0', '\0']), ('\u{1044f}',
+ ['\u{10427}', '\0', '\0']), ('\u{118c0}', ['\u{118a0}', '\0', '\0']), ('\u{118c1}',
+ ['\u{118a1}', '\0', '\0']), ('\u{118c2}', ['\u{118a2}', '\0', '\0']), ('\u{118c3}',
+ ['\u{118a3}', '\0', '\0']), ('\u{118c4}', ['\u{118a4}', '\0', '\0']), ('\u{118c5}',
+ ['\u{118a5}', '\0', '\0']), ('\u{118c6}', ['\u{118a6}', '\0', '\0']), ('\u{118c7}',
+ ['\u{118a7}', '\0', '\0']), ('\u{118c8}', ['\u{118a8}', '\0', '\0']), ('\u{118c9}',
+ ['\u{118a9}', '\0', '\0']), ('\u{118ca}', ['\u{118aa}', '\0', '\0']), ('\u{118cb}',
+ ['\u{118ab}', '\0', '\0']), ('\u{118cc}', ['\u{118ac}', '\0', '\0']), ('\u{118cd}',
+ ['\u{118ad}', '\0', '\0']), ('\u{118ce}', ['\u{118ae}', '\0', '\0']), ('\u{118cf}',
+ ['\u{118af}', '\0', '\0']), ('\u{118d0}', ['\u{118b0}', '\0', '\0']), ('\u{118d1}',
+ ['\u{118b1}', '\0', '\0']), ('\u{118d2}', ['\u{118b2}', '\0', '\0']), ('\u{118d3}',
+ ['\u{118b3}', '\0', '\0']), ('\u{118d4}', ['\u{118b4}', '\0', '\0']), ('\u{118d5}',
+ ['\u{118b5}', '\0', '\0']), ('\u{118d6}', ['\u{118b6}', '\0', '\0']), ('\u{118d7}',
+ ['\u{118b7}', '\0', '\0']), ('\u{118d8}', ['\u{118b8}', '\0', '\0']), ('\u{118d9}',
+ ['\u{118b9}', '\0', '\0']), ('\u{118da}', ['\u{118ba}', '\0', '\0']), ('\u{118db}',
+ ['\u{118bb}', '\0', '\0']), ('\u{118dc}', ['\u{118bc}', '\0', '\0']), ('\u{118dd}',
+ ['\u{118bd}', '\0', '\0']), ('\u{118de}', ['\u{118be}', '\0', '\0']), ('\u{118df}',
+ ['\u{118bf}', '\0', '\0'])
];
- const LlLu_table: &'static [(char, char)] = &[
- ('\u{61}', '\u{41}'), ('\u{62}', '\u{42}'), ('\u{63}', '\u{43}'), ('\u{64}', '\u{44}'),
- ('\u{65}', '\u{45}'), ('\u{66}', '\u{46}'), ('\u{67}', '\u{47}'), ('\u{68}', '\u{48}'),
- ('\u{69}', '\u{49}'), ('\u{6a}', '\u{4a}'), ('\u{6b}', '\u{4b}'), ('\u{6c}', '\u{4c}'),
- ('\u{6d}', '\u{4d}'), ('\u{6e}', '\u{4e}'), ('\u{6f}', '\u{4f}'), ('\u{70}', '\u{50}'),
- ('\u{71}', '\u{51}'), ('\u{72}', '\u{52}'), ('\u{73}', '\u{53}'), ('\u{74}', '\u{54}'),
- ('\u{75}', '\u{55}'), ('\u{76}', '\u{56}'), ('\u{77}', '\u{57}'), ('\u{78}', '\u{58}'),
- ('\u{79}', '\u{59}'), ('\u{7a}', '\u{5a}'), ('\u{b5}', '\u{39c}'), ('\u{e0}', '\u{c0}'),
- ('\u{e1}', '\u{c1}'), ('\u{e2}', '\u{c2}'), ('\u{e3}', '\u{c3}'), ('\u{e4}', '\u{c4}'),
- ('\u{e5}', '\u{c5}'), ('\u{e6}', '\u{c6}'), ('\u{e7}', '\u{c7}'), ('\u{e8}', '\u{c8}'),
- ('\u{e9}', '\u{c9}'), ('\u{ea}', '\u{ca}'), ('\u{eb}', '\u{cb}'), ('\u{ec}', '\u{cc}'),
- ('\u{ed}', '\u{cd}'), ('\u{ee}', '\u{ce}'), ('\u{ef}', '\u{cf}'), ('\u{f0}', '\u{d0}'),
- ('\u{f1}', '\u{d1}'), ('\u{f2}', '\u{d2}'), ('\u{f3}', '\u{d3}'), ('\u{f4}', '\u{d4}'),
- ('\u{f5}', '\u{d5}'), ('\u{f6}', '\u{d6}'), ('\u{f8}', '\u{d8}'), ('\u{f9}', '\u{d9}'),
- ('\u{fa}', '\u{da}'), ('\u{fb}', '\u{db}'), ('\u{fc}', '\u{dc}'), ('\u{fd}', '\u{dd}'),
- ('\u{fe}', '\u{de}'), ('\u{ff}', '\u{178}'), ('\u{101}', '\u{100}'), ('\u{103}', '\u{102}'),
- ('\u{105}', '\u{104}'), ('\u{107}', '\u{106}'), ('\u{109}', '\u{108}'), ('\u{10b}',
- '\u{10a}'), ('\u{10d}', '\u{10c}'), ('\u{10f}', '\u{10e}'), ('\u{111}', '\u{110}'),
- ('\u{113}', '\u{112}'), ('\u{115}', '\u{114}'), ('\u{117}', '\u{116}'), ('\u{119}',
- '\u{118}'), ('\u{11b}', '\u{11a}'), ('\u{11d}', '\u{11c}'), ('\u{11f}', '\u{11e}'),
- ('\u{121}', '\u{120}'), ('\u{123}', '\u{122}'), ('\u{125}', '\u{124}'), ('\u{127}',
- '\u{126}'), ('\u{129}', '\u{128}'), ('\u{12b}', '\u{12a}'), ('\u{12d}', '\u{12c}'),
- ('\u{12f}', '\u{12e}'), ('\u{131}', '\u{49}'), ('\u{133}', '\u{132}'), ('\u{135}',
- '\u{134}'), ('\u{137}', '\u{136}'), ('\u{13a}', '\u{139}'), ('\u{13c}', '\u{13b}'),
- ('\u{13e}', '\u{13d}'), ('\u{140}', '\u{13f}'), ('\u{142}', '\u{141}'), ('\u{144}',
- '\u{143}'), ('\u{146}', '\u{145}'), ('\u{148}', '\u{147}'), ('\u{14b}', '\u{14a}'),
- ('\u{14d}', '\u{14c}'), ('\u{14f}', '\u{14e}'), ('\u{151}', '\u{150}'), ('\u{153}',
- '\u{152}'), ('\u{155}', '\u{154}'), ('\u{157}', '\u{156}'), ('\u{159}', '\u{158}'),
- ('\u{15b}', '\u{15a}'), ('\u{15d}', '\u{15c}'), ('\u{15f}', '\u{15e}'), ('\u{161}',
- '\u{160}'), ('\u{163}', '\u{162}'), ('\u{165}', '\u{164}'), ('\u{167}', '\u{166}'),
- ('\u{169}', '\u{168}'), ('\u{16b}', '\u{16a}'), ('\u{16d}', '\u{16c}'), ('\u{16f}',
- '\u{16e}'), ('\u{171}', '\u{170}'), ('\u{173}', '\u{172}'), ('\u{175}', '\u{174}'),
- ('\u{177}', '\u{176}'), ('\u{17a}', '\u{179}'), ('\u{17c}', '\u{17b}'), ('\u{17e}',
- '\u{17d}'), ('\u{17f}', '\u{53}'), ('\u{180}', '\u{243}'), ('\u{183}', '\u{182}'),
- ('\u{185}', '\u{184}'), ('\u{188}', '\u{187}'), ('\u{18c}', '\u{18b}'), ('\u{192}',
- '\u{191}'), ('\u{195}', '\u{1f6}'), ('\u{199}', '\u{198}'), ('\u{19a}', '\u{23d}'),
- ('\u{19e}', '\u{220}'), ('\u{1a1}', '\u{1a0}'), ('\u{1a3}', '\u{1a2}'), ('\u{1a5}',
- '\u{1a4}'), ('\u{1a8}', '\u{1a7}'), ('\u{1ad}', '\u{1ac}'), ('\u{1b0}', '\u{1af}'),
- ('\u{1b4}', '\u{1b3}'), ('\u{1b6}', '\u{1b5}'), ('\u{1b9}', '\u{1b8}'), ('\u{1bd}',
- '\u{1bc}'), ('\u{1bf}', '\u{1f7}'), ('\u{1c6}', '\u{1c4}'), ('\u{1c9}', '\u{1c7}'),
- ('\u{1cc}', '\u{1ca}'), ('\u{1ce}', '\u{1cd}'), ('\u{1d0}', '\u{1cf}'), ('\u{1d2}',
- '\u{1d1}'), ('\u{1d4}', '\u{1d3}'), ('\u{1d6}', '\u{1d5}'), ('\u{1d8}', '\u{1d7}'),
- ('\u{1da}', '\u{1d9}'), ('\u{1dc}', '\u{1db}'), ('\u{1dd}', '\u{18e}'), ('\u{1df}',
- '\u{1de}'), ('\u{1e1}', '\u{1e0}'), ('\u{1e3}', '\u{1e2}'), ('\u{1e5}', '\u{1e4}'),
- ('\u{1e7}', '\u{1e6}'), ('\u{1e9}', '\u{1e8}'), ('\u{1eb}', '\u{1ea}'), ('\u{1ed}',
- '\u{1ec}'), ('\u{1ef}', '\u{1ee}'), ('\u{1f3}', '\u{1f1}'), ('\u{1f5}', '\u{1f4}'),
- ('\u{1f9}', '\u{1f8}'), ('\u{1fb}', '\u{1fa}'), ('\u{1fd}', '\u{1fc}'), ('\u{1ff}',
- '\u{1fe}'), ('\u{201}', '\u{200}'), ('\u{203}', '\u{202}'), ('\u{205}', '\u{204}'),
- ('\u{207}', '\u{206}'), ('\u{209}', '\u{208}'), ('\u{20b}', '\u{20a}'), ('\u{20d}',
- '\u{20c}'), ('\u{20f}', '\u{20e}'), ('\u{211}', '\u{210}'), ('\u{213}', '\u{212}'),
- ('\u{215}', '\u{214}'), ('\u{217}', '\u{216}'), ('\u{219}', '\u{218}'), ('\u{21b}',
- '\u{21a}'), ('\u{21d}', '\u{21c}'), ('\u{21f}', '\u{21e}'), ('\u{223}', '\u{222}'),
- ('\u{225}', '\u{224}'), ('\u{227}', '\u{226}'), ('\u{229}', '\u{228}'), ('\u{22b}',
- '\u{22a}'), ('\u{22d}', '\u{22c}'), ('\u{22f}', '\u{22e}'), ('\u{231}', '\u{230}'),
- ('\u{233}', '\u{232}'), ('\u{23c}', '\u{23b}'), ('\u{23f}', '\u{2c7e}'), ('\u{240}',
- '\u{2c7f}'), ('\u{242}', '\u{241}'), ('\u{247}', '\u{246}'), ('\u{249}', '\u{248}'),
- ('\u{24b}', '\u{24a}'), ('\u{24d}', '\u{24c}'), ('\u{24f}', '\u{24e}'), ('\u{250}',
- '\u{2c6f}'), ('\u{251}', '\u{2c6d}'), ('\u{252}', '\u{2c70}'), ('\u{253}', '\u{181}'),
- ('\u{254}', '\u{186}'), ('\u{256}', '\u{189}'), ('\u{257}', '\u{18a}'), ('\u{259}',
- '\u{18f}'), ('\u{25b}', '\u{190}'), ('\u{25c}', '\u{a7ab}'), ('\u{260}', '\u{193}'),
- ('\u{261}', '\u{a7ac}'), ('\u{263}', '\u{194}'), ('\u{265}', '\u{a78d}'), ('\u{266}',
- '\u{a7aa}'), ('\u{268}', '\u{197}'), ('\u{269}', '\u{196}'), ('\u{26b}', '\u{2c62}'),
- ('\u{26c}', '\u{a7ad}'), ('\u{26f}', '\u{19c}'), ('\u{271}', '\u{2c6e}'), ('\u{272}',
- '\u{19d}'), ('\u{275}', '\u{19f}'), ('\u{27d}', '\u{2c64}'), ('\u{280}', '\u{1a6}'),
- ('\u{283}', '\u{1a9}'), ('\u{287}', '\u{a7b1}'), ('\u{288}', '\u{1ae}'), ('\u{289}',
- '\u{244}'), ('\u{28a}', '\u{1b1}'), ('\u{28b}', '\u{1b2}'), ('\u{28c}', '\u{245}'),
- ('\u{292}', '\u{1b7}'), ('\u{29e}', '\u{a7b0}'), ('\u{371}', '\u{370}'), ('\u{373}',
- '\u{372}'), ('\u{377}', '\u{376}'), ('\u{37b}', '\u{3fd}'), ('\u{37c}', '\u{3fe}'),
- ('\u{37d}', '\u{3ff}'), ('\u{3ac}', '\u{386}'), ('\u{3ad}', '\u{388}'), ('\u{3ae}',
- '\u{389}'), ('\u{3af}', '\u{38a}'), ('\u{3b1}', '\u{391}'), ('\u{3b2}', '\u{392}'),
- ('\u{3b3}', '\u{393}'), ('\u{3b4}', '\u{394}'), ('\u{3b5}', '\u{395}'), ('\u{3b6}',
- '\u{396}'), ('\u{3b7}', '\u{397}'), ('\u{3b8}', '\u{398}'), ('\u{3b9}', '\u{399}'),
- ('\u{3ba}', '\u{39a}'), ('\u{3bb}', '\u{39b}'), ('\u{3bc}', '\u{39c}'), ('\u{3bd}',
- '\u{39d}'), ('\u{3be}', '\u{39e}'), ('\u{3bf}', '\u{39f}'), ('\u{3c0}', '\u{3a0}'),
- ('\u{3c1}', '\u{3a1}'), ('\u{3c2}', '\u{3a3}'), ('\u{3c3}', '\u{3a3}'), ('\u{3c4}',
- '\u{3a4}'), ('\u{3c5}', '\u{3a5}'), ('\u{3c6}', '\u{3a6}'), ('\u{3c7}', '\u{3a7}'),
- ('\u{3c8}', '\u{3a8}'), ('\u{3c9}', '\u{3a9}'), ('\u{3ca}', '\u{3aa}'), ('\u{3cb}',
- '\u{3ab}'), ('\u{3cc}', '\u{38c}'), ('\u{3cd}', '\u{38e}'), ('\u{3ce}', '\u{38f}'),
- ('\u{3d0}', '\u{392}'), ('\u{3d1}', '\u{398}'), ('\u{3d5}', '\u{3a6}'), ('\u{3d6}',
- '\u{3a0}'), ('\u{3d7}', '\u{3cf}'), ('\u{3d9}', '\u{3d8}'), ('\u{3db}', '\u{3da}'),
- ('\u{3dd}', '\u{3dc}'), ('\u{3df}', '\u{3de}'), ('\u{3e1}', '\u{3e0}'), ('\u{3e3}',
- '\u{3e2}'), ('\u{3e5}', '\u{3e4}'), ('\u{3e7}', '\u{3e6}'), ('\u{3e9}', '\u{3e8}'),
- ('\u{3eb}', '\u{3ea}'), ('\u{3ed}', '\u{3ec}'), ('\u{3ef}', '\u{3ee}'), ('\u{3f0}',
- '\u{39a}'), ('\u{3f1}', '\u{3a1}'), ('\u{3f2}', '\u{3f9}'), ('\u{3f3}', '\u{37f}'),
- ('\u{3f5}', '\u{395}'), ('\u{3f8}', '\u{3f7}'), ('\u{3fb}', '\u{3fa}'), ('\u{430}',
- '\u{410}'), ('\u{431}', '\u{411}'), ('\u{432}', '\u{412}'), ('\u{433}', '\u{413}'),
- ('\u{434}', '\u{414}'), ('\u{435}', '\u{415}'), ('\u{436}', '\u{416}'), ('\u{437}',
- '\u{417}'), ('\u{438}', '\u{418}'), ('\u{439}', '\u{419}'), ('\u{43a}', '\u{41a}'),
- ('\u{43b}', '\u{41b}'), ('\u{43c}', '\u{41c}'), ('\u{43d}', '\u{41d}'), ('\u{43e}',
- '\u{41e}'), ('\u{43f}', '\u{41f}'), ('\u{440}', '\u{420}'), ('\u{441}', '\u{421}'),
- ('\u{442}', '\u{422}'), ('\u{443}', '\u{423}'), ('\u{444}', '\u{424}'), ('\u{445}',
- '\u{425}'), ('\u{446}', '\u{426}'), ('\u{447}', '\u{427}'), ('\u{448}', '\u{428}'),
- ('\u{449}', '\u{429}'), ('\u{44a}', '\u{42a}'), ('\u{44b}', '\u{42b}'), ('\u{44c}',
- '\u{42c}'), ('\u{44d}', '\u{42d}'), ('\u{44e}', '\u{42e}'), ('\u{44f}', '\u{42f}'),
- ('\u{450}', '\u{400}'), ('\u{451}', '\u{401}'), ('\u{452}', '\u{402}'), ('\u{453}',
- '\u{403}'), ('\u{454}', '\u{404}'), ('\u{455}', '\u{405}'), ('\u{456}', '\u{406}'),
- ('\u{457}', '\u{407}'), ('\u{458}', '\u{408}'), ('\u{459}', '\u{409}'), ('\u{45a}',
- '\u{40a}'), ('\u{45b}', '\u{40b}'), ('\u{45c}', '\u{40c}'), ('\u{45d}', '\u{40d}'),
- ('\u{45e}', '\u{40e}'), ('\u{45f}', '\u{40f}'), ('\u{461}', '\u{460}'), ('\u{463}',
- '\u{462}'), ('\u{465}', '\u{464}'), ('\u{467}', '\u{466}'), ('\u{469}', '\u{468}'),
- ('\u{46b}', '\u{46a}'), ('\u{46d}', '\u{46c}'), ('\u{46f}', '\u{46e}'), ('\u{471}',
- '\u{470}'), ('\u{473}', '\u{472}'), ('\u{475}', '\u{474}'), ('\u{477}', '\u{476}'),
- ('\u{479}', '\u{478}'), ('\u{47b}', '\u{47a}'), ('\u{47d}', '\u{47c}'), ('\u{47f}',
- '\u{47e}'), ('\u{481}', '\u{480}'), ('\u{48b}', '\u{48a}'), ('\u{48d}', '\u{48c}'),
- ('\u{48f}', '\u{48e}'), ('\u{491}', '\u{490}'), ('\u{493}', '\u{492}'), ('\u{495}',
- '\u{494}'), ('\u{497}', '\u{496}'), ('\u{499}', '\u{498}'), ('\u{49b}', '\u{49a}'),
- ('\u{49d}', '\u{49c}'), ('\u{49f}', '\u{49e}'), ('\u{4a1}', '\u{4a0}'), ('\u{4a3}',
- '\u{4a2}'), ('\u{4a5}', '\u{4a4}'), ('\u{4a7}', '\u{4a6}'), ('\u{4a9}', '\u{4a8}'),
- ('\u{4ab}', '\u{4aa}'), ('\u{4ad}', '\u{4ac}'), ('\u{4af}', '\u{4ae}'), ('\u{4b1}',
- '\u{4b0}'), ('\u{4b3}', '\u{4b2}'), ('\u{4b5}', '\u{4b4}'), ('\u{4b7}', '\u{4b6}'),
- ('\u{4b9}', '\u{4b8}'), ('\u{4bb}', '\u{4ba}'), ('\u{4bd}', '\u{4bc}'), ('\u{4bf}',
- '\u{4be}'), ('\u{4c2}', '\u{4c1}'), ('\u{4c4}', '\u{4c3}'), ('\u{4c6}', '\u{4c5}'),
- ('\u{4c8}', '\u{4c7}'), ('\u{4ca}', '\u{4c9}'), ('\u{4cc}', '\u{4cb}'), ('\u{4ce}',
- '\u{4cd}'), ('\u{4cf}', '\u{4c0}'), ('\u{4d1}', '\u{4d0}'), ('\u{4d3}', '\u{4d2}'),
- ('\u{4d5}', '\u{4d4}'), ('\u{4d7}', '\u{4d6}'), ('\u{4d9}', '\u{4d8}'), ('\u{4db}',
- '\u{4da}'), ('\u{4dd}', '\u{4dc}'), ('\u{4df}', '\u{4de}'), ('\u{4e1}', '\u{4e0}'),
- ('\u{4e3}', '\u{4e2}'), ('\u{4e5}', '\u{4e4}'), ('\u{4e7}', '\u{4e6}'), ('\u{4e9}',
- '\u{4e8}'), ('\u{4eb}', '\u{4ea}'), ('\u{4ed}', '\u{4ec}'), ('\u{4ef}', '\u{4ee}'),
- ('\u{4f1}', '\u{4f0}'), ('\u{4f3}', '\u{4f2}'), ('\u{4f5}', '\u{4f4}'), ('\u{4f7}',
- '\u{4f6}'), ('\u{4f9}', '\u{4f8}'), ('\u{4fb}', '\u{4fa}'), ('\u{4fd}', '\u{4fc}'),
- ('\u{4ff}', '\u{4fe}'), ('\u{501}', '\u{500}'), ('\u{503}', '\u{502}'), ('\u{505}',
- '\u{504}'), ('\u{507}', '\u{506}'), ('\u{509}', '\u{508}'), ('\u{50b}', '\u{50a}'),
- ('\u{50d}', '\u{50c}'), ('\u{50f}', '\u{50e}'), ('\u{511}', '\u{510}'), ('\u{513}',
- '\u{512}'), ('\u{515}', '\u{514}'), ('\u{517}', '\u{516}'), ('\u{519}', '\u{518}'),
- ('\u{51b}', '\u{51a}'), ('\u{51d}', '\u{51c}'), ('\u{51f}', '\u{51e}'), ('\u{521}',
- '\u{520}'), ('\u{523}', '\u{522}'), ('\u{525}', '\u{524}'), ('\u{527}', '\u{526}'),
- ('\u{529}', '\u{528}'), ('\u{52b}', '\u{52a}'), ('\u{52d}', '\u{52c}'), ('\u{52f}',
- '\u{52e}'), ('\u{561}', '\u{531}'), ('\u{562}', '\u{532}'), ('\u{563}', '\u{533}'),
- ('\u{564}', '\u{534}'), ('\u{565}', '\u{535}'), ('\u{566}', '\u{536}'), ('\u{567}',
- '\u{537}'), ('\u{568}', '\u{538}'), ('\u{569}', '\u{539}'), ('\u{56a}', '\u{53a}'),
- ('\u{56b}', '\u{53b}'), ('\u{56c}', '\u{53c}'), ('\u{56d}', '\u{53d}'), ('\u{56e}',
- '\u{53e}'), ('\u{56f}', '\u{53f}'), ('\u{570}', '\u{540}'), ('\u{571}', '\u{541}'),
- ('\u{572}', '\u{542}'), ('\u{573}', '\u{543}'), ('\u{574}', '\u{544}'), ('\u{575}',
- '\u{545}'), ('\u{576}', '\u{546}'), ('\u{577}', '\u{547}'), ('\u{578}', '\u{548}'),
- ('\u{579}', '\u{549}'), ('\u{57a}', '\u{54a}'), ('\u{57b}', '\u{54b}'), ('\u{57c}',
- '\u{54c}'), ('\u{57d}', '\u{54d}'), ('\u{57e}', '\u{54e}'), ('\u{57f}', '\u{54f}'),
- ('\u{580}', '\u{550}'), ('\u{581}', '\u{551}'), ('\u{582}', '\u{552}'), ('\u{583}',
- '\u{553}'), ('\u{584}', '\u{554}'), ('\u{585}', '\u{555}'), ('\u{586}', '\u{556}'),
- ('\u{1d79}', '\u{a77d}'), ('\u{1d7d}', '\u{2c63}'), ('\u{1e01}', '\u{1e00}'), ('\u{1e03}',
- '\u{1e02}'), ('\u{1e05}', '\u{1e04}'), ('\u{1e07}', '\u{1e06}'), ('\u{1e09}', '\u{1e08}'),
- ('\u{1e0b}', '\u{1e0a}'), ('\u{1e0d}', '\u{1e0c}'), ('\u{1e0f}', '\u{1e0e}'), ('\u{1e11}',
- '\u{1e10}'), ('\u{1e13}', '\u{1e12}'), ('\u{1e15}', '\u{1e14}'), ('\u{1e17}', '\u{1e16}'),
- ('\u{1e19}', '\u{1e18}'), ('\u{1e1b}', '\u{1e1a}'), ('\u{1e1d}', '\u{1e1c}'), ('\u{1e1f}',
- '\u{1e1e}'), ('\u{1e21}', '\u{1e20}'), ('\u{1e23}', '\u{1e22}'), ('\u{1e25}', '\u{1e24}'),
- ('\u{1e27}', '\u{1e26}'), ('\u{1e29}', '\u{1e28}'), ('\u{1e2b}', '\u{1e2a}'), ('\u{1e2d}',
- '\u{1e2c}'), ('\u{1e2f}', '\u{1e2e}'), ('\u{1e31}', '\u{1e30}'), ('\u{1e33}', '\u{1e32}'),
- ('\u{1e35}', '\u{1e34}'), ('\u{1e37}', '\u{1e36}'), ('\u{1e39}', '\u{1e38}'), ('\u{1e3b}',
- '\u{1e3a}'), ('\u{1e3d}', '\u{1e3c}'), ('\u{1e3f}', '\u{1e3e}'), ('\u{1e41}', '\u{1e40}'),
- ('\u{1e43}', '\u{1e42}'), ('\u{1e45}', '\u{1e44}'), ('\u{1e47}', '\u{1e46}'), ('\u{1e49}',
- '\u{1e48}'), ('\u{1e4b}', '\u{1e4a}'), ('\u{1e4d}', '\u{1e4c}'), ('\u{1e4f}', '\u{1e4e}'),
- ('\u{1e51}', '\u{1e50}'), ('\u{1e53}', '\u{1e52}'), ('\u{1e55}', '\u{1e54}'), ('\u{1e57}',
- '\u{1e56}'), ('\u{1e59}', '\u{1e58}'), ('\u{1e5b}', '\u{1e5a}'), ('\u{1e5d}', '\u{1e5c}'),
- ('\u{1e5f}', '\u{1e5e}'), ('\u{1e61}', '\u{1e60}'), ('\u{1e63}', '\u{1e62}'), ('\u{1e65}',
- '\u{1e64}'), ('\u{1e67}', '\u{1e66}'), ('\u{1e69}', '\u{1e68}'), ('\u{1e6b}', '\u{1e6a}'),
- ('\u{1e6d}', '\u{1e6c}'), ('\u{1e6f}', '\u{1e6e}'), ('\u{1e71}', '\u{1e70}'), ('\u{1e73}',
- '\u{1e72}'), ('\u{1e75}', '\u{1e74}'), ('\u{1e77}', '\u{1e76}'), ('\u{1e79}', '\u{1e78}'),
- ('\u{1e7b}', '\u{1e7a}'), ('\u{1e7d}', '\u{1e7c}'), ('\u{1e7f}', '\u{1e7e}'), ('\u{1e81}',
- '\u{1e80}'), ('\u{1e83}', '\u{1e82}'), ('\u{1e85}', '\u{1e84}'), ('\u{1e87}', '\u{1e86}'),
- ('\u{1e89}', '\u{1e88}'), ('\u{1e8b}', '\u{1e8a}'), ('\u{1e8d}', '\u{1e8c}'), ('\u{1e8f}',
- '\u{1e8e}'), ('\u{1e91}', '\u{1e90}'), ('\u{1e93}', '\u{1e92}'), ('\u{1e95}', '\u{1e94}'),
- ('\u{1e9b}', '\u{1e60}'), ('\u{1ea1}', '\u{1ea0}'), ('\u{1ea3}', '\u{1ea2}'), ('\u{1ea5}',
- '\u{1ea4}'), ('\u{1ea7}', '\u{1ea6}'), ('\u{1ea9}', '\u{1ea8}'), ('\u{1eab}', '\u{1eaa}'),
- ('\u{1ead}', '\u{1eac}'), ('\u{1eaf}', '\u{1eae}'), ('\u{1eb1}', '\u{1eb0}'), ('\u{1eb3}',
- '\u{1eb2}'), ('\u{1eb5}', '\u{1eb4}'), ('\u{1eb7}', '\u{1eb6}'), ('\u{1eb9}', '\u{1eb8}'),
- ('\u{1ebb}', '\u{1eba}'), ('\u{1ebd}', '\u{1ebc}'), ('\u{1ebf}', '\u{1ebe}'), ('\u{1ec1}',
- '\u{1ec0}'), ('\u{1ec3}', '\u{1ec2}'), ('\u{1ec5}', '\u{1ec4}'), ('\u{1ec7}', '\u{1ec6}'),
- ('\u{1ec9}', '\u{1ec8}'), ('\u{1ecb}', '\u{1eca}'), ('\u{1ecd}', '\u{1ecc}'), ('\u{1ecf}',
- '\u{1ece}'), ('\u{1ed1}', '\u{1ed0}'), ('\u{1ed3}', '\u{1ed2}'), ('\u{1ed5}', '\u{1ed4}'),
- ('\u{1ed7}', '\u{1ed6}'), ('\u{1ed9}', '\u{1ed8}'), ('\u{1edb}', '\u{1eda}'), ('\u{1edd}',
- '\u{1edc}'), ('\u{1edf}', '\u{1ede}'), ('\u{1ee1}', '\u{1ee0}'), ('\u{1ee3}', '\u{1ee2}'),
- ('\u{1ee5}', '\u{1ee4}'), ('\u{1ee7}', '\u{1ee6}'), ('\u{1ee9}', '\u{1ee8}'), ('\u{1eeb}',
- '\u{1eea}'), ('\u{1eed}', '\u{1eec}'), ('\u{1eef}', '\u{1eee}'), ('\u{1ef1}', '\u{1ef0}'),
- ('\u{1ef3}', '\u{1ef2}'), ('\u{1ef5}', '\u{1ef4}'), ('\u{1ef7}', '\u{1ef6}'), ('\u{1ef9}',
- '\u{1ef8}'), ('\u{1efb}', '\u{1efa}'), ('\u{1efd}', '\u{1efc}'), ('\u{1eff}', '\u{1efe}'),
- ('\u{1f00}', '\u{1f08}'), ('\u{1f01}', '\u{1f09}'), ('\u{1f02}', '\u{1f0a}'), ('\u{1f03}',
- '\u{1f0b}'), ('\u{1f04}', '\u{1f0c}'), ('\u{1f05}', '\u{1f0d}'), ('\u{1f06}', '\u{1f0e}'),
- ('\u{1f07}', '\u{1f0f}'), ('\u{1f10}', '\u{1f18}'), ('\u{1f11}', '\u{1f19}'), ('\u{1f12}',
- '\u{1f1a}'), ('\u{1f13}', '\u{1f1b}'), ('\u{1f14}', '\u{1f1c}'), ('\u{1f15}', '\u{1f1d}'),
- ('\u{1f20}', '\u{1f28}'), ('\u{1f21}', '\u{1f29}'), ('\u{1f22}', '\u{1f2a}'), ('\u{1f23}',
- '\u{1f2b}'), ('\u{1f24}', '\u{1f2c}'), ('\u{1f25}', '\u{1f2d}'), ('\u{1f26}', '\u{1f2e}'),
- ('\u{1f27}', '\u{1f2f}'), ('\u{1f30}', '\u{1f38}'), ('\u{1f31}', '\u{1f39}'), ('\u{1f32}',
- '\u{1f3a}'), ('\u{1f33}', '\u{1f3b}'), ('\u{1f34}', '\u{1f3c}'), ('\u{1f35}', '\u{1f3d}'),
- ('\u{1f36}', '\u{1f3e}'), ('\u{1f37}', '\u{1f3f}'), ('\u{1f40}', '\u{1f48}'), ('\u{1f41}',
- '\u{1f49}'), ('\u{1f42}', '\u{1f4a}'), ('\u{1f43}', '\u{1f4b}'), ('\u{1f44}', '\u{1f4c}'),
- ('\u{1f45}', '\u{1f4d}'), ('\u{1f51}', '\u{1f59}'), ('\u{1f53}', '\u{1f5b}'), ('\u{1f55}',
- '\u{1f5d}'), ('\u{1f57}', '\u{1f5f}'), ('\u{1f60}', '\u{1f68}'), ('\u{1f61}', '\u{1f69}'),
- ('\u{1f62}', '\u{1f6a}'), ('\u{1f63}', '\u{1f6b}'), ('\u{1f64}', '\u{1f6c}'), ('\u{1f65}',
- '\u{1f6d}'), ('\u{1f66}', '\u{1f6e}'), ('\u{1f67}', '\u{1f6f}'), ('\u{1f70}', '\u{1fba}'),
- ('\u{1f71}', '\u{1fbb}'), ('\u{1f72}', '\u{1fc8}'), ('\u{1f73}', '\u{1fc9}'), ('\u{1f74}',
- '\u{1fca}'), ('\u{1f75}', '\u{1fcb}'), ('\u{1f76}', '\u{1fda}'), ('\u{1f77}', '\u{1fdb}'),
- ('\u{1f78}', '\u{1ff8}'), ('\u{1f79}', '\u{1ff9}'), ('\u{1f7a}', '\u{1fea}'), ('\u{1f7b}',
- '\u{1feb}'), ('\u{1f7c}', '\u{1ffa}'), ('\u{1f7d}', '\u{1ffb}'), ('\u{1f80}', '\u{1f88}'),
- ('\u{1f81}', '\u{1f89}'), ('\u{1f82}', '\u{1f8a}'), ('\u{1f83}', '\u{1f8b}'), ('\u{1f84}',
- '\u{1f8c}'), ('\u{1f85}', '\u{1f8d}'), ('\u{1f86}', '\u{1f8e}'), ('\u{1f87}', '\u{1f8f}'),
- ('\u{1f90}', '\u{1f98}'), ('\u{1f91}', '\u{1f99}'), ('\u{1f92}', '\u{1f9a}'), ('\u{1f93}',
- '\u{1f9b}'), ('\u{1f94}', '\u{1f9c}'), ('\u{1f95}', '\u{1f9d}'), ('\u{1f96}', '\u{1f9e}'),
- ('\u{1f97}', '\u{1f9f}'), ('\u{1fa0}', '\u{1fa8}'), ('\u{1fa1}', '\u{1fa9}'), ('\u{1fa2}',
- '\u{1faa}'), ('\u{1fa3}', '\u{1fab}'), ('\u{1fa4}', '\u{1fac}'), ('\u{1fa5}', '\u{1fad}'),
- ('\u{1fa6}', '\u{1fae}'), ('\u{1fa7}', '\u{1faf}'), ('\u{1fb0}', '\u{1fb8}'), ('\u{1fb1}',
- '\u{1fb9}'), ('\u{1fb3}', '\u{1fbc}'), ('\u{1fbe}', '\u{399}'), ('\u{1fc3}', '\u{1fcc}'),
- ('\u{1fd0}', '\u{1fd8}'), ('\u{1fd1}', '\u{1fd9}'), ('\u{1fe0}', '\u{1fe8}'), ('\u{1fe1}',
- '\u{1fe9}'), ('\u{1fe5}', '\u{1fec}'), ('\u{1ff3}', '\u{1ffc}'), ('\u{214e}', '\u{2132}'),
- ('\u{2184}', '\u{2183}'), ('\u{2c30}', '\u{2c00}'), ('\u{2c31}', '\u{2c01}'), ('\u{2c32}',
- '\u{2c02}'), ('\u{2c33}', '\u{2c03}'), ('\u{2c34}', '\u{2c04}'), ('\u{2c35}', '\u{2c05}'),
- ('\u{2c36}', '\u{2c06}'), ('\u{2c37}', '\u{2c07}'), ('\u{2c38}', '\u{2c08}'), ('\u{2c39}',
- '\u{2c09}'), ('\u{2c3a}', '\u{2c0a}'), ('\u{2c3b}', '\u{2c0b}'), ('\u{2c3c}', '\u{2c0c}'),
- ('\u{2c3d}', '\u{2c0d}'), ('\u{2c3e}', '\u{2c0e}'), ('\u{2c3f}', '\u{2c0f}'), ('\u{2c40}',
- '\u{2c10}'), ('\u{2c41}', '\u{2c11}'), ('\u{2c42}', '\u{2c12}'), ('\u{2c43}', '\u{2c13}'),
- ('\u{2c44}', '\u{2c14}'), ('\u{2c45}', '\u{2c15}'), ('\u{2c46}', '\u{2c16}'), ('\u{2c47}',
- '\u{2c17}'), ('\u{2c48}', '\u{2c18}'), ('\u{2c49}', '\u{2c19}'), ('\u{2c4a}', '\u{2c1a}'),
- ('\u{2c4b}', '\u{2c1b}'), ('\u{2c4c}', '\u{2c1c}'), ('\u{2c4d}', '\u{2c1d}'), ('\u{2c4e}',
- '\u{2c1e}'), ('\u{2c4f}', '\u{2c1f}'), ('\u{2c50}', '\u{2c20}'), ('\u{2c51}', '\u{2c21}'),
- ('\u{2c52}', '\u{2c22}'), ('\u{2c53}', '\u{2c23}'), ('\u{2c54}', '\u{2c24}'), ('\u{2c55}',
- '\u{2c25}'), ('\u{2c56}', '\u{2c26}'), ('\u{2c57}', '\u{2c27}'), ('\u{2c58}', '\u{2c28}'),
- ('\u{2c59}', '\u{2c29}'), ('\u{2c5a}', '\u{2c2a}'), ('\u{2c5b}', '\u{2c2b}'), ('\u{2c5c}',
- '\u{2c2c}'), ('\u{2c5d}', '\u{2c2d}'), ('\u{2c5e}', '\u{2c2e}'), ('\u{2c61}', '\u{2c60}'),
- ('\u{2c65}', '\u{23a}'), ('\u{2c66}', '\u{23e}'), ('\u{2c68}', '\u{2c67}'), ('\u{2c6a}',
- '\u{2c69}'), ('\u{2c6c}', '\u{2c6b}'), ('\u{2c73}', '\u{2c72}'), ('\u{2c76}', '\u{2c75}'),
- ('\u{2c81}', '\u{2c80}'), ('\u{2c83}', '\u{2c82}'), ('\u{2c85}', '\u{2c84}'), ('\u{2c87}',
- '\u{2c86}'), ('\u{2c89}', '\u{2c88}'), ('\u{2c8b}', '\u{2c8a}'), ('\u{2c8d}', '\u{2c8c}'),
- ('\u{2c8f}', '\u{2c8e}'), ('\u{2c91}', '\u{2c90}'), ('\u{2c93}', '\u{2c92}'), ('\u{2c95}',
- '\u{2c94}'), ('\u{2c97}', '\u{2c96}'), ('\u{2c99}', '\u{2c98}'), ('\u{2c9b}', '\u{2c9a}'),
- ('\u{2c9d}', '\u{2c9c}'), ('\u{2c9f}', '\u{2c9e}'), ('\u{2ca1}', '\u{2ca0}'), ('\u{2ca3}',
- '\u{2ca2}'), ('\u{2ca5}', '\u{2ca4}'), ('\u{2ca7}', '\u{2ca6}'), ('\u{2ca9}', '\u{2ca8}'),
- ('\u{2cab}', '\u{2caa}'), ('\u{2cad}', '\u{2cac}'), ('\u{2caf}', '\u{2cae}'), ('\u{2cb1}',
- '\u{2cb0}'), ('\u{2cb3}', '\u{2cb2}'), ('\u{2cb5}', '\u{2cb4}'), ('\u{2cb7}', '\u{2cb6}'),
- ('\u{2cb9}', '\u{2cb8}'), ('\u{2cbb}', '\u{2cba}'), ('\u{2cbd}', '\u{2cbc}'), ('\u{2cbf}',
- '\u{2cbe}'), ('\u{2cc1}', '\u{2cc0}'), ('\u{2cc3}', '\u{2cc2}'), ('\u{2cc5}', '\u{2cc4}'),
- ('\u{2cc7}', '\u{2cc6}'), ('\u{2cc9}', '\u{2cc8}'), ('\u{2ccb}', '\u{2cca}'), ('\u{2ccd}',
- '\u{2ccc}'), ('\u{2ccf}', '\u{2cce}'), ('\u{2cd1}', '\u{2cd0}'), ('\u{2cd3}', '\u{2cd2}'),
- ('\u{2cd5}', '\u{2cd4}'), ('\u{2cd7}', '\u{2cd6}'), ('\u{2cd9}', '\u{2cd8}'), ('\u{2cdb}',
- '\u{2cda}'), ('\u{2cdd}', '\u{2cdc}'), ('\u{2cdf}', '\u{2cde}'), ('\u{2ce1}', '\u{2ce0}'),
- ('\u{2ce3}', '\u{2ce2}'), ('\u{2cec}', '\u{2ceb}'), ('\u{2cee}', '\u{2ced}'), ('\u{2cf3}',
- '\u{2cf2}'), ('\u{2d00}', '\u{10a0}'), ('\u{2d01}', '\u{10a1}'), ('\u{2d02}', '\u{10a2}'),
- ('\u{2d03}', '\u{10a3}'), ('\u{2d04}', '\u{10a4}'), ('\u{2d05}', '\u{10a5}'), ('\u{2d06}',
- '\u{10a6}'), ('\u{2d07}', '\u{10a7}'), ('\u{2d08}', '\u{10a8}'), ('\u{2d09}', '\u{10a9}'),
- ('\u{2d0a}', '\u{10aa}'), ('\u{2d0b}', '\u{10ab}'), ('\u{2d0c}', '\u{10ac}'), ('\u{2d0d}',
- '\u{10ad}'), ('\u{2d0e}', '\u{10ae}'), ('\u{2d0f}', '\u{10af}'), ('\u{2d10}', '\u{10b0}'),
- ('\u{2d11}', '\u{10b1}'), ('\u{2d12}', '\u{10b2}'), ('\u{2d13}', '\u{10b3}'), ('\u{2d14}',
- '\u{10b4}'), ('\u{2d15}', '\u{10b5}'), ('\u{2d16}', '\u{10b6}'), ('\u{2d17}', '\u{10b7}'),
- ('\u{2d18}', '\u{10b8}'), ('\u{2d19}', '\u{10b9}'), ('\u{2d1a}', '\u{10ba}'), ('\u{2d1b}',
- '\u{10bb}'), ('\u{2d1c}', '\u{10bc}'), ('\u{2d1d}', '\u{10bd}'), ('\u{2d1e}', '\u{10be}'),
- ('\u{2d1f}', '\u{10bf}'), ('\u{2d20}', '\u{10c0}'), ('\u{2d21}', '\u{10c1}'), ('\u{2d22}',
- '\u{10c2}'), ('\u{2d23}', '\u{10c3}'), ('\u{2d24}', '\u{10c4}'), ('\u{2d25}', '\u{10c5}'),
- ('\u{2d27}', '\u{10c7}'), ('\u{2d2d}', '\u{10cd}'), ('\u{a641}', '\u{a640}'), ('\u{a643}',
- '\u{a642}'), ('\u{a645}', '\u{a644}'), ('\u{a647}', '\u{a646}'), ('\u{a649}', '\u{a648}'),
- ('\u{a64b}', '\u{a64a}'), ('\u{a64d}', '\u{a64c}'), ('\u{a64f}', '\u{a64e}'), ('\u{a651}',
- '\u{a650}'), ('\u{a653}', '\u{a652}'), ('\u{a655}', '\u{a654}'), ('\u{a657}', '\u{a656}'),
- ('\u{a659}', '\u{a658}'), ('\u{a65b}', '\u{a65a}'), ('\u{a65d}', '\u{a65c}'), ('\u{a65f}',
- '\u{a65e}'), ('\u{a661}', '\u{a660}'), ('\u{a663}', '\u{a662}'), ('\u{a665}', '\u{a664}'),
- ('\u{a667}', '\u{a666}'), ('\u{a669}', '\u{a668}'), ('\u{a66b}', '\u{a66a}'), ('\u{a66d}',
- '\u{a66c}'), ('\u{a681}', '\u{a680}'), ('\u{a683}', '\u{a682}'), ('\u{a685}', '\u{a684}'),
- ('\u{a687}', '\u{a686}'), ('\u{a689}', '\u{a688}'), ('\u{a68b}', '\u{a68a}'), ('\u{a68d}',
- '\u{a68c}'), ('\u{a68f}', '\u{a68e}'), ('\u{a691}', '\u{a690}'), ('\u{a693}', '\u{a692}'),
- ('\u{a695}', '\u{a694}'), ('\u{a697}', '\u{a696}'), ('\u{a699}', '\u{a698}'), ('\u{a69b}',
- '\u{a69a}'), ('\u{a723}', '\u{a722}'), ('\u{a725}', '\u{a724}'), ('\u{a727}', '\u{a726}'),
- ('\u{a729}', '\u{a728}'), ('\u{a72b}', '\u{a72a}'), ('\u{a72d}', '\u{a72c}'), ('\u{a72f}',
- '\u{a72e}'), ('\u{a733}', '\u{a732}'), ('\u{a735}', '\u{a734}'), ('\u{a737}', '\u{a736}'),
- ('\u{a739}', '\u{a738}'), ('\u{a73b}', '\u{a73a}'), ('\u{a73d}', '\u{a73c}'), ('\u{a73f}',
- '\u{a73e}'), ('\u{a741}', '\u{a740}'), ('\u{a743}', '\u{a742}'), ('\u{a745}', '\u{a744}'),
- ('\u{a747}', '\u{a746}'), ('\u{a749}', '\u{a748}'), ('\u{a74b}', '\u{a74a}'), ('\u{a74d}',
- '\u{a74c}'), ('\u{a74f}', '\u{a74e}'), ('\u{a751}', '\u{a750}'), ('\u{a753}', '\u{a752}'),
- ('\u{a755}', '\u{a754}'), ('\u{a757}', '\u{a756}'), ('\u{a759}', '\u{a758}'), ('\u{a75b}',
- '\u{a75a}'), ('\u{a75d}', '\u{a75c}'), ('\u{a75f}', '\u{a75e}'), ('\u{a761}', '\u{a760}'),
- ('\u{a763}', '\u{a762}'), ('\u{a765}', '\u{a764}'), ('\u{a767}', '\u{a766}'), ('\u{a769}',
- '\u{a768}'), ('\u{a76b}', '\u{a76a}'), ('\u{a76d}', '\u{a76c}'), ('\u{a76f}', '\u{a76e}'),
- ('\u{a77a}', '\u{a779}'), ('\u{a77c}', '\u{a77b}'), ('\u{a77f}', '\u{a77e}'), ('\u{a781}',
- '\u{a780}'), ('\u{a783}', '\u{a782}'), ('\u{a785}', '\u{a784}'), ('\u{a787}', '\u{a786}'),
- ('\u{a78c}', '\u{a78b}'), ('\u{a791}', '\u{a790}'), ('\u{a793}', '\u{a792}'), ('\u{a797}',
- '\u{a796}'), ('\u{a799}', '\u{a798}'), ('\u{a79b}', '\u{a79a}'), ('\u{a79d}', '\u{a79c}'),
- ('\u{a79f}', '\u{a79e}'), ('\u{a7a1}', '\u{a7a0}'), ('\u{a7a3}', '\u{a7a2}'), ('\u{a7a5}',
- '\u{a7a4}'), ('\u{a7a7}', '\u{a7a6}'), ('\u{a7a9}', '\u{a7a8}'), ('\u{ff41}', '\u{ff21}'),
- ('\u{ff42}', '\u{ff22}'), ('\u{ff43}', '\u{ff23}'), ('\u{ff44}', '\u{ff24}'), ('\u{ff45}',
- '\u{ff25}'), ('\u{ff46}', '\u{ff26}'), ('\u{ff47}', '\u{ff27}'), ('\u{ff48}', '\u{ff28}'),
- ('\u{ff49}', '\u{ff29}'), ('\u{ff4a}', '\u{ff2a}'), ('\u{ff4b}', '\u{ff2b}'), ('\u{ff4c}',
- '\u{ff2c}'), ('\u{ff4d}', '\u{ff2d}'), ('\u{ff4e}', '\u{ff2e}'), ('\u{ff4f}', '\u{ff2f}'),
- ('\u{ff50}', '\u{ff30}'), ('\u{ff51}', '\u{ff31}'), ('\u{ff52}', '\u{ff32}'), ('\u{ff53}',
- '\u{ff33}'), ('\u{ff54}', '\u{ff34}'), ('\u{ff55}', '\u{ff35}'), ('\u{ff56}', '\u{ff36}'),
- ('\u{ff57}', '\u{ff37}'), ('\u{ff58}', '\u{ff38}'), ('\u{ff59}', '\u{ff39}'), ('\u{ff5a}',
- '\u{ff3a}'), ('\u{10428}', '\u{10400}'), ('\u{10429}', '\u{10401}'), ('\u{1042a}',
- '\u{10402}'), ('\u{1042b}', '\u{10403}'), ('\u{1042c}', '\u{10404}'), ('\u{1042d}',
- '\u{10405}'), ('\u{1042e}', '\u{10406}'), ('\u{1042f}', '\u{10407}'), ('\u{10430}',
- '\u{10408}'), ('\u{10431}', '\u{10409}'), ('\u{10432}', '\u{1040a}'), ('\u{10433}',
- '\u{1040b}'), ('\u{10434}', '\u{1040c}'), ('\u{10435}', '\u{1040d}'), ('\u{10436}',
- '\u{1040e}'), ('\u{10437}', '\u{1040f}'), ('\u{10438}', '\u{10410}'), ('\u{10439}',
- '\u{10411}'), ('\u{1043a}', '\u{10412}'), ('\u{1043b}', '\u{10413}'), ('\u{1043c}',
- '\u{10414}'), ('\u{1043d}', '\u{10415}'), ('\u{1043e}', '\u{10416}'), ('\u{1043f}',
- '\u{10417}'), ('\u{10440}', '\u{10418}'), ('\u{10441}', '\u{10419}'), ('\u{10442}',
- '\u{1041a}'), ('\u{10443}', '\u{1041b}'), ('\u{10444}', '\u{1041c}'), ('\u{10445}',
- '\u{1041d}'), ('\u{10446}', '\u{1041e}'), ('\u{10447}', '\u{1041f}'), ('\u{10448}',
- '\u{10420}'), ('\u{10449}', '\u{10421}'), ('\u{1044a}', '\u{10422}'), ('\u{1044b}',
- '\u{10423}'), ('\u{1044c}', '\u{10424}'), ('\u{1044d}', '\u{10425}'), ('\u{1044e}',
- '\u{10426}'), ('\u{1044f}', '\u{10427}'), ('\u{118c0}', '\u{118a0}'), ('\u{118c1}',
- '\u{118a1}'), ('\u{118c2}', '\u{118a2}'), ('\u{118c3}', '\u{118a3}'), ('\u{118c4}',
- '\u{118a4}'), ('\u{118c5}', '\u{118a5}'), ('\u{118c6}', '\u{118a6}'), ('\u{118c7}',
- '\u{118a7}'), ('\u{118c8}', '\u{118a8}'), ('\u{118c9}', '\u{118a9}'), ('\u{118ca}',
- '\u{118aa}'), ('\u{118cb}', '\u{118ab}'), ('\u{118cc}', '\u{118ac}'), ('\u{118cd}',
- '\u{118ad}'), ('\u{118ce}', '\u{118ae}'), ('\u{118cf}', '\u{118af}'), ('\u{118d0}',
- '\u{118b0}'), ('\u{118d1}', '\u{118b1}'), ('\u{118d2}', '\u{118b2}'), ('\u{118d3}',
- '\u{118b3}'), ('\u{118d4}', '\u{118b4}'), ('\u{118d5}', '\u{118b5}'), ('\u{118d6}',
- '\u{118b6}'), ('\u{118d7}', '\u{118b7}'), ('\u{118d8}', '\u{118b8}'), ('\u{118d9}',
- '\u{118b9}'), ('\u{118da}', '\u{118ba}'), ('\u{118db}', '\u{118bb}'), ('\u{118dc}',
- '\u{118bc}'), ('\u{118dd}', '\u{118bd}'), ('\u{118de}', '\u{118be}'), ('\u{118df}',
- '\u{118bf}')
+ const to_titlecase_table: &'static [(char, [char; 3])] = &[
+ ('\u{61}', ['\u{41}', '\0', '\0']), ('\u{62}', ['\u{42}', '\0', '\0']), ('\u{63}',
+ ['\u{43}', '\0', '\0']), ('\u{64}', ['\u{44}', '\0', '\0']), ('\u{65}', ['\u{45}', '\0',
+ '\0']), ('\u{66}', ['\u{46}', '\0', '\0']), ('\u{67}', ['\u{47}', '\0', '\0']), ('\u{68}',
+ ['\u{48}', '\0', '\0']), ('\u{69}', ['\u{49}', '\0', '\0']), ('\u{6a}', ['\u{4a}', '\0',
+ '\0']), ('\u{6b}', ['\u{4b}', '\0', '\0']), ('\u{6c}', ['\u{4c}', '\0', '\0']), ('\u{6d}',
+ ['\u{4d}', '\0', '\0']), ('\u{6e}', ['\u{4e}', '\0', '\0']), ('\u{6f}', ['\u{4f}', '\0',
+ '\0']), ('\u{70}', ['\u{50}', '\0', '\0']), ('\u{71}', ['\u{51}', '\0', '\0']), ('\u{72}',
+ ['\u{52}', '\0', '\0']), ('\u{73}', ['\u{53}', '\0', '\0']), ('\u{74}', ['\u{54}', '\0',
+ '\0']), ('\u{75}', ['\u{55}', '\0', '\0']), ('\u{76}', ['\u{56}', '\0', '\0']), ('\u{77}',
+ ['\u{57}', '\0', '\0']), ('\u{78}', ['\u{58}', '\0', '\0']), ('\u{79}', ['\u{59}', '\0',
+ '\0']), ('\u{7a}', ['\u{5a}', '\0', '\0']), ('\u{b5}', ['\u{39c}', '\0', '\0']), ('\u{df}',
+ ['\u{53}', '\u{73}', '\0']), ('\u{e0}', ['\u{c0}', '\0', '\0']), ('\u{e1}', ['\u{c1}', '\0',
+ '\0']), ('\u{e2}', ['\u{c2}', '\0', '\0']), ('\u{e3}', ['\u{c3}', '\0', '\0']), ('\u{e4}',
+ ['\u{c4}', '\0', '\0']), ('\u{e5}', ['\u{c5}', '\0', '\0']), ('\u{e6}', ['\u{c6}', '\0',
+ '\0']), ('\u{e7}', ['\u{c7}', '\0', '\0']), ('\u{e8}', ['\u{c8}', '\0', '\0']), ('\u{e9}',
+ ['\u{c9}', '\0', '\0']), ('\u{ea}', ['\u{ca}', '\0', '\0']), ('\u{eb}', ['\u{cb}', '\0',
+ '\0']), ('\u{ec}', ['\u{cc}', '\0', '\0']), ('\u{ed}', ['\u{cd}', '\0', '\0']), ('\u{ee}',
+ ['\u{ce}', '\0', '\0']), ('\u{ef}', ['\u{cf}', '\0', '\0']), ('\u{f0}', ['\u{d0}', '\0',
+ '\0']), ('\u{f1}', ['\u{d1}', '\0', '\0']), ('\u{f2}', ['\u{d2}', '\0', '\0']), ('\u{f3}',
+ ['\u{d3}', '\0', '\0']), ('\u{f4}', ['\u{d4}', '\0', '\0']), ('\u{f5}', ['\u{d5}', '\0',
+ '\0']), ('\u{f6}', ['\u{d6}', '\0', '\0']), ('\u{f8}', ['\u{d8}', '\0', '\0']), ('\u{f9}',
+ ['\u{d9}', '\0', '\0']), ('\u{fa}', ['\u{da}', '\0', '\0']), ('\u{fb}', ['\u{db}', '\0',
+ '\0']), ('\u{fc}', ['\u{dc}', '\0', '\0']), ('\u{fd}', ['\u{dd}', '\0', '\0']), ('\u{fe}',
+ ['\u{de}', '\0', '\0']), ('\u{ff}', ['\u{178}', '\0', '\0']), ('\u{101}', ['\u{100}', '\0',
+ '\0']), ('\u{103}', ['\u{102}', '\0', '\0']), ('\u{105}', ['\u{104}', '\0', '\0']),
+ ('\u{107}', ['\u{106}', '\0', '\0']), ('\u{109}', ['\u{108}', '\0', '\0']), ('\u{10b}',
+ ['\u{10a}', '\0', '\0']), ('\u{10d}', ['\u{10c}', '\0', '\0']), ('\u{10f}', ['\u{10e}',
+ '\0', '\0']), ('\u{111}', ['\u{110}', '\0', '\0']), ('\u{113}', ['\u{112}', '\0', '\0']),
+ ('\u{115}', ['\u{114}', '\0', '\0']), ('\u{117}', ['\u{116}', '\0', '\0']), ('\u{119}',
+ ['\u{118}', '\0', '\0']), ('\u{11b}', ['\u{11a}', '\0', '\0']), ('\u{11d}', ['\u{11c}',
+ '\0', '\0']), ('\u{11f}', ['\u{11e}', '\0', '\0']), ('\u{121}', ['\u{120}', '\0', '\0']),
+ ('\u{123}', ['\u{122}', '\0', '\0']), ('\u{125}', ['\u{124}', '\0', '\0']), ('\u{127}',
+ ['\u{126}', '\0', '\0']), ('\u{129}', ['\u{128}', '\0', '\0']), ('\u{12b}', ['\u{12a}',
+ '\0', '\0']), ('\u{12d}', ['\u{12c}', '\0', '\0']), ('\u{12f}', ['\u{12e}', '\0', '\0']),
+ ('\u{131}', ['\u{49}', '\0', '\0']), ('\u{133}', ['\u{132}', '\0', '\0']), ('\u{135}',
+ ['\u{134}', '\0', '\0']), ('\u{137}', ['\u{136}', '\0', '\0']), ('\u{13a}', ['\u{139}',
+ '\0', '\0']), ('\u{13c}', ['\u{13b}', '\0', '\0']), ('\u{13e}', ['\u{13d}', '\0', '\0']),
+ ('\u{140}', ['\u{13f}', '\0', '\0']), ('\u{142}', ['\u{141}', '\0', '\0']), ('\u{144}',
+ ['\u{143}', '\0', '\0']), ('\u{146}', ['\u{145}', '\0', '\0']), ('\u{148}', ['\u{147}',
+ '\0', '\0']), ('\u{149}', ['\u{2bc}', '\u{4e}', '\0']), ('\u{14b}', ['\u{14a}', '\0',
+ '\0']), ('\u{14d}', ['\u{14c}', '\0', '\0']), ('\u{14f}', ['\u{14e}', '\0', '\0']),
+ ('\u{151}', ['\u{150}', '\0', '\0']), ('\u{153}', ['\u{152}', '\0', '\0']), ('\u{155}',
+ ['\u{154}', '\0', '\0']), ('\u{157}', ['\u{156}', '\0', '\0']), ('\u{159}', ['\u{158}',
+ '\0', '\0']), ('\u{15b}', ['\u{15a}', '\0', '\0']), ('\u{15d}', ['\u{15c}', '\0', '\0']),
+ ('\u{15f}', ['\u{15e}', '\0', '\0']), ('\u{161}', ['\u{160}', '\0', '\0']), ('\u{163}',
+ ['\u{162}', '\0', '\0']), ('\u{165}', ['\u{164}', '\0', '\0']), ('\u{167}', ['\u{166}',
+ '\0', '\0']), ('\u{169}', ['\u{168}', '\0', '\0']), ('\u{16b}', ['\u{16a}', '\0', '\0']),
+ ('\u{16d}', ['\u{16c}', '\0', '\0']), ('\u{16f}', ['\u{16e}', '\0', '\0']), ('\u{171}',
+ ['\u{170}', '\0', '\0']), ('\u{173}', ['\u{172}', '\0', '\0']), ('\u{175}', ['\u{174}',
+ '\0', '\0']), ('\u{177}', ['\u{176}', '\0', '\0']), ('\u{17a}', ['\u{179}', '\0', '\0']),
+ ('\u{17c}', ['\u{17b}', '\0', '\0']), ('\u{17e}', ['\u{17d}', '\0', '\0']), ('\u{17f}',
+ ['\u{53}', '\0', '\0']), ('\u{180}', ['\u{243}', '\0', '\0']), ('\u{183}', ['\u{182}', '\0',
+ '\0']), ('\u{185}', ['\u{184}', '\0', '\0']), ('\u{188}', ['\u{187}', '\0', '\0']),
+ ('\u{18c}', ['\u{18b}', '\0', '\0']), ('\u{192}', ['\u{191}', '\0', '\0']), ('\u{195}',
+ ['\u{1f6}', '\0', '\0']), ('\u{199}', ['\u{198}', '\0', '\0']), ('\u{19a}', ['\u{23d}',
+ '\0', '\0']), ('\u{19e}', ['\u{220}', '\0', '\0']), ('\u{1a1}', ['\u{1a0}', '\0', '\0']),
+ ('\u{1a3}', ['\u{1a2}', '\0', '\0']), ('\u{1a5}', ['\u{1a4}', '\0', '\0']), ('\u{1a8}',
+ ['\u{1a7}', '\0', '\0']), ('\u{1ad}', ['\u{1ac}', '\0', '\0']), ('\u{1b0}', ['\u{1af}',
+ '\0', '\0']), ('\u{1b4}', ['\u{1b3}', '\0', '\0']), ('\u{1b6}', ['\u{1b5}', '\0', '\0']),
+ ('\u{1b9}', ['\u{1b8}', '\0', '\0']), ('\u{1bd}', ['\u{1bc}', '\0', '\0']), ('\u{1bf}',
+ ['\u{1f7}', '\0', '\0']), ('\u{1c4}', ['\u{1c5}', '\0', '\0']), ('\u{1c5}', ['\u{1c5}',
+ '\0', '\0']), ('\u{1c6}', ['\u{1c5}', '\0', '\0']), ('\u{1c7}', ['\u{1c8}', '\0', '\0']),
+ ('\u{1c8}', ['\u{1c8}', '\0', '\0']), ('\u{1c9}', ['\u{1c8}', '\0', '\0']), ('\u{1ca}',
+ ['\u{1cb}', '\0', '\0']), ('\u{1cb}', ['\u{1cb}', '\0', '\0']), ('\u{1cc}', ['\u{1cb}',
+ '\0', '\0']), ('\u{1ce}', ['\u{1cd}', '\0', '\0']), ('\u{1d0}', ['\u{1cf}', '\0', '\0']),
+ ('\u{1d2}', ['\u{1d1}', '\0', '\0']), ('\u{1d4}', ['\u{1d3}', '\0', '\0']), ('\u{1d6}',
+ ['\u{1d5}', '\0', '\0']), ('\u{1d8}', ['\u{1d7}', '\0', '\0']), ('\u{1da}', ['\u{1d9}',
+ '\0', '\0']), ('\u{1dc}', ['\u{1db}', '\0', '\0']), ('\u{1dd}', ['\u{18e}', '\0', '\0']),
+ ('\u{1df}', ['\u{1de}', '\0', '\0']), ('\u{1e1}', ['\u{1e0}', '\0', '\0']), ('\u{1e3}',
+ ['\u{1e2}', '\0', '\0']), ('\u{1e5}', ['\u{1e4}', '\0', '\0']), ('\u{1e7}', ['\u{1e6}',
+ '\0', '\0']), ('\u{1e9}', ['\u{1e8}', '\0', '\0']), ('\u{1eb}', ['\u{1ea}', '\0', '\0']),
+ ('\u{1ed}', ['\u{1ec}', '\0', '\0']), ('\u{1ef}', ['\u{1ee}', '\0', '\0']), ('\u{1f0}',
+ ['\u{4a}', '\u{30c}', '\0']), ('\u{1f1}', ['\u{1f2}', '\0', '\0']), ('\u{1f2}', ['\u{1f2}',
+ '\0', '\0']), ('\u{1f3}', ['\u{1f2}', '\0', '\0']), ('\u{1f5}', ['\u{1f4}', '\0', '\0']),
+ ('\u{1f9}', ['\u{1f8}', '\0', '\0']), ('\u{1fb}', ['\u{1fa}', '\0', '\0']), ('\u{1fd}',
+ ['\u{1fc}', '\0', '\0']), ('\u{1ff}', ['\u{1fe}', '\0', '\0']), ('\u{201}', ['\u{200}',
+ '\0', '\0']), ('\u{203}', ['\u{202}', '\0', '\0']), ('\u{205}', ['\u{204}', '\0', '\0']),
+ ('\u{207}', ['\u{206}', '\0', '\0']), ('\u{209}', ['\u{208}', '\0', '\0']), ('\u{20b}',
+ ['\u{20a}', '\0', '\0']), ('\u{20d}', ['\u{20c}', '\0', '\0']), ('\u{20f}', ['\u{20e}',
+ '\0', '\0']), ('\u{211}', ['\u{210}', '\0', '\0']), ('\u{213}', ['\u{212}', '\0', '\0']),
+ ('\u{215}', ['\u{214}', '\0', '\0']), ('\u{217}', ['\u{216}', '\0', '\0']), ('\u{219}',
+ ['\u{218}', '\0', '\0']), ('\u{21b}', ['\u{21a}', '\0', '\0']), ('\u{21d}', ['\u{21c}',
+ '\0', '\0']), ('\u{21f}', ['\u{21e}', '\0', '\0']), ('\u{223}', ['\u{222}', '\0', '\0']),
+ ('\u{225}', ['\u{224}', '\0', '\0']), ('\u{227}', ['\u{226}', '\0', '\0']), ('\u{229}',
+ ['\u{228}', '\0', '\0']), ('\u{22b}', ['\u{22a}', '\0', '\0']), ('\u{22d}', ['\u{22c}',
+ '\0', '\0']), ('\u{22f}', ['\u{22e}', '\0', '\0']), ('\u{231}', ['\u{230}', '\0', '\0']),
+ ('\u{233}', ['\u{232}', '\0', '\0']), ('\u{23c}', ['\u{23b}', '\0', '\0']), ('\u{23f}',
+ ['\u{2c7e}', '\0', '\0']), ('\u{240}', ['\u{2c7f}', '\0', '\0']), ('\u{242}', ['\u{241}',
+ '\0', '\0']), ('\u{247}', ['\u{246}', '\0', '\0']), ('\u{249}', ['\u{248}', '\0', '\0']),
+ ('\u{24b}', ['\u{24a}', '\0', '\0']), ('\u{24d}', ['\u{24c}', '\0', '\0']), ('\u{24f}',
+ ['\u{24e}', '\0', '\0']), ('\u{250}', ['\u{2c6f}', '\0', '\0']), ('\u{251}', ['\u{2c6d}',
+ '\0', '\0']), ('\u{252}', ['\u{2c70}', '\0', '\0']), ('\u{253}', ['\u{181}', '\0', '\0']),
+ ('\u{254}', ['\u{186}', '\0', '\0']), ('\u{256}', ['\u{189}', '\0', '\0']), ('\u{257}',
+ ['\u{18a}', '\0', '\0']), ('\u{259}', ['\u{18f}', '\0', '\0']), ('\u{25b}', ['\u{190}',
+ '\0', '\0']), ('\u{25c}', ['\u{a7ab}', '\0', '\0']), ('\u{260}', ['\u{193}', '\0', '\0']),
+ ('\u{261}', ['\u{a7ac}', '\0', '\0']), ('\u{263}', ['\u{194}', '\0', '\0']), ('\u{265}',
+ ['\u{a78d}', '\0', '\0']), ('\u{266}', ['\u{a7aa}', '\0', '\0']), ('\u{268}', ['\u{197}',
+ '\0', '\0']), ('\u{269}', ['\u{196}', '\0', '\0']), ('\u{26b}', ['\u{2c62}', '\0', '\0']),
+ ('\u{26c}', ['\u{a7ad}', '\0', '\0']), ('\u{26f}', ['\u{19c}', '\0', '\0']), ('\u{271}',
+ ['\u{2c6e}', '\0', '\0']), ('\u{272}', ['\u{19d}', '\0', '\0']), ('\u{275}', ['\u{19f}',
+ '\0', '\0']), ('\u{27d}', ['\u{2c64}', '\0', '\0']), ('\u{280}', ['\u{1a6}', '\0', '\0']),
+ ('\u{283}', ['\u{1a9}', '\0', '\0']), ('\u{287}', ['\u{a7b1}', '\0', '\0']), ('\u{288}',
+ ['\u{1ae}', '\0', '\0']), ('\u{289}', ['\u{244}', '\0', '\0']), ('\u{28a}', ['\u{1b1}',
+ '\0', '\0']), ('\u{28b}', ['\u{1b2}', '\0', '\0']), ('\u{28c}', ['\u{245}', '\0', '\0']),
+ ('\u{292}', ['\u{1b7}', '\0', '\0']), ('\u{29e}', ['\u{a7b0}', '\0', '\0']), ('\u{345}',
+ ['\u{399}', '\0', '\0']), ('\u{371}', ['\u{370}', '\0', '\0']), ('\u{373}', ['\u{372}',
+ '\0', '\0']), ('\u{377}', ['\u{376}', '\0', '\0']), ('\u{37b}', ['\u{3fd}', '\0', '\0']),
+ ('\u{37c}', ['\u{3fe}', '\0', '\0']), ('\u{37d}', ['\u{3ff}', '\0', '\0']), ('\u{390}',
+ ['\u{399}', '\u{308}', '\u{301}']), ('\u{3ac}', ['\u{386}', '\0', '\0']), ('\u{3ad}',
+ ['\u{388}', '\0', '\0']), ('\u{3ae}', ['\u{389}', '\0', '\0']), ('\u{3af}', ['\u{38a}',
+ '\0', '\0']), ('\u{3b0}', ['\u{3a5}', '\u{308}', '\u{301}']), ('\u{3b1}', ['\u{391}', '\0',
+ '\0']), ('\u{3b2}', ['\u{392}', '\0', '\0']), ('\u{3b3}', ['\u{393}', '\0', '\0']),
+ ('\u{3b4}', ['\u{394}', '\0', '\0']), ('\u{3b5}', ['\u{395}', '\0', '\0']), ('\u{3b6}',
+ ['\u{396}', '\0', '\0']), ('\u{3b7}', ['\u{397}', '\0', '\0']), ('\u{3b8}', ['\u{398}',
+ '\0', '\0']), ('\u{3b9}', ['\u{399}', '\0', '\0']), ('\u{3ba}', ['\u{39a}', '\0', '\0']),
+ ('\u{3bb}', ['\u{39b}', '\0', '\0']), ('\u{3bc}', ['\u{39c}', '\0', '\0']), ('\u{3bd}',
+ ['\u{39d}', '\0', '\0']), ('\u{3be}', ['\u{39e}', '\0', '\0']), ('\u{3bf}', ['\u{39f}',
+ '\0', '\0']), ('\u{3c0}', ['\u{3a0}', '\0', '\0']), ('\u{3c1}', ['\u{3a1}', '\0', '\0']),
+ ('\u{3c2}', ['\u{3a3}', '\0', '\0']), ('\u{3c3}', ['\u{3a3}', '\0', '\0']), ('\u{3c4}',
+ ['\u{3a4}', '\0', '\0']), ('\u{3c5}', ['\u{3a5}', '\0', '\0']), ('\u{3c6}', ['\u{3a6}',
+ '\0', '\0']), ('\u{3c7}', ['\u{3a7}', '\0', '\0']), ('\u{3c8}', ['\u{3a8}', '\0', '\0']),
+ ('\u{3c9}', ['\u{3a9}', '\0', '\0']), ('\u{3ca}', ['\u{3aa}', '\0', '\0']), ('\u{3cb}',
+ ['\u{3ab}', '\0', '\0']), ('\u{3cc}', ['\u{38c}', '\0', '\0']), ('\u{3cd}', ['\u{38e}',
+ '\0', '\0']), ('\u{3ce}', ['\u{38f}', '\0', '\0']), ('\u{3d0}', ['\u{392}', '\0', '\0']),
+ ('\u{3d1}', ['\u{398}', '\0', '\0']), ('\u{3d5}', ['\u{3a6}', '\0', '\0']), ('\u{3d6}',
+ ['\u{3a0}', '\0', '\0']), ('\u{3d7}', ['\u{3cf}', '\0', '\0']), ('\u{3d9}', ['\u{3d8}',
+ '\0', '\0']), ('\u{3db}', ['\u{3da}', '\0', '\0']), ('\u{3dd}', ['\u{3dc}', '\0', '\0']),
+ ('\u{3df}', ['\u{3de}', '\0', '\0']), ('\u{3e1}', ['\u{3e0}', '\0', '\0']), ('\u{3e3}',
+ ['\u{3e2}', '\0', '\0']), ('\u{3e5}', ['\u{3e4}', '\0', '\0']), ('\u{3e7}', ['\u{3e6}',
+ '\0', '\0']), ('\u{3e9}', ['\u{3e8}', '\0', '\0']), ('\u{3eb}', ['\u{3ea}', '\0', '\0']),
+ ('\u{3ed}', ['\u{3ec}', '\0', '\0']), ('\u{3ef}', ['\u{3ee}', '\0', '\0']), ('\u{3f0}',
+ ['\u{39a}', '\0', '\0']), ('\u{3f1}', ['\u{3a1}', '\0', '\0']), ('\u{3f2}', ['\u{3f9}',
+ '\0', '\0']), ('\u{3f3}', ['\u{37f}', '\0', '\0']), ('\u{3f5}', ['\u{395}', '\0', '\0']),
+ ('\u{3f8}', ['\u{3f7}', '\0', '\0']), ('\u{3fb}', ['\u{3fa}', '\0', '\0']), ('\u{430}',
+ ['\u{410}', '\0', '\0']), ('\u{431}', ['\u{411}', '\0', '\0']), ('\u{432}', ['\u{412}',
+ '\0', '\0']), ('\u{433}', ['\u{413}', '\0', '\0']), ('\u{434}', ['\u{414}', '\0', '\0']),
+ ('\u{435}', ['\u{415}', '\0', '\0']), ('\u{436}', ['\u{416}', '\0', '\0']), ('\u{437}',
+ ['\u{417}', '\0', '\0']), ('\u{438}', ['\u{418}', '\0', '\0']), ('\u{439}', ['\u{419}',
+ '\0', '\0']), ('\u{43a}', ['\u{41a}', '\0', '\0']), ('\u{43b}', ['\u{41b}', '\0', '\0']),
+ ('\u{43c}', ['\u{41c}', '\0', '\0']), ('\u{43d}', ['\u{41d}', '\0', '\0']), ('\u{43e}',
+ ['\u{41e}', '\0', '\0']), ('\u{43f}', ['\u{41f}', '\0', '\0']), ('\u{440}', ['\u{420}',
+ '\0', '\0']), ('\u{441}', ['\u{421}', '\0', '\0']), ('\u{442}', ['\u{422}', '\0', '\0']),
+ ('\u{443}', ['\u{423}', '\0', '\0']), ('\u{444}', ['\u{424}', '\0', '\0']), ('\u{445}',
+ ['\u{425}', '\0', '\0']), ('\u{446}', ['\u{426}', '\0', '\0']), ('\u{447}', ['\u{427}',
+ '\0', '\0']), ('\u{448}', ['\u{428}', '\0', '\0']), ('\u{449}', ['\u{429}', '\0', '\0']),
+ ('\u{44a}', ['\u{42a}', '\0', '\0']), ('\u{44b}', ['\u{42b}', '\0', '\0']), ('\u{44c}',
+ ['\u{42c}', '\0', '\0']), ('\u{44d}', ['\u{42d}', '\0', '\0']), ('\u{44e}', ['\u{42e}',
+ '\0', '\0']), ('\u{44f}', ['\u{42f}', '\0', '\0']), ('\u{450}', ['\u{400}', '\0', '\0']),
+ ('\u{451}', ['\u{401}', '\0', '\0']), ('\u{452}', ['\u{402}', '\0', '\0']), ('\u{453}',
+ ['\u{403}', '\0', '\0']), ('\u{454}', ['\u{404}', '\0', '\0']), ('\u{455}', ['\u{405}',
+ '\0', '\0']), ('\u{456}', ['\u{406}', '\0', '\0']), ('\u{457}', ['\u{407}', '\0', '\0']),
+ ('\u{458}', ['\u{408}', '\0', '\0']), ('\u{459}', ['\u{409}', '\0', '\0']), ('\u{45a}',
+ ['\u{40a}', '\0', '\0']), ('\u{45b}', ['\u{40b}', '\0', '\0']), ('\u{45c}', ['\u{40c}',
+ '\0', '\0']), ('\u{45d}', ['\u{40d}', '\0', '\0']), ('\u{45e}', ['\u{40e}', '\0', '\0']),
+ ('\u{45f}', ['\u{40f}', '\0', '\0']), ('\u{461}', ['\u{460}', '\0', '\0']), ('\u{463}',
+ ['\u{462}', '\0', '\0']), ('\u{465}', ['\u{464}', '\0', '\0']), ('\u{467}', ['\u{466}',
+ '\0', '\0']), ('\u{469}', ['\u{468}', '\0', '\0']), ('\u{46b}', ['\u{46a}', '\0', '\0']),
+ ('\u{46d}', ['\u{46c}', '\0', '\0']), ('\u{46f}', ['\u{46e}', '\0', '\0']), ('\u{471}',
+ ['\u{470}', '\0', '\0']), ('\u{473}', ['\u{472}', '\0', '\0']), ('\u{475}', ['\u{474}',
+ '\0', '\0']), ('\u{477}', ['\u{476}', '\0', '\0']), ('\u{479}', ['\u{478}', '\0', '\0']),
+ ('\u{47b}', ['\u{47a}', '\0', '\0']), ('\u{47d}', ['\u{47c}', '\0', '\0']), ('\u{47f}',
+ ['\u{47e}', '\0', '\0']), ('\u{481}', ['\u{480}', '\0', '\0']), ('\u{48b}', ['\u{48a}',
+ '\0', '\0']), ('\u{48d}', ['\u{48c}', '\0', '\0']), ('\u{48f}', ['\u{48e}', '\0', '\0']),
+ ('\u{491}', ['\u{490}', '\0', '\0']), ('\u{493}', ['\u{492}', '\0', '\0']), ('\u{495}',
+ ['\u{494}', '\0', '\0']), ('\u{497}', ['\u{496}', '\0', '\0']), ('\u{499}', ['\u{498}',
+ '\0', '\0']), ('\u{49b}', ['\u{49a}', '\0', '\0']), ('\u{49d}', ['\u{49c}', '\0', '\0']),
+ ('\u{49f}', ['\u{49e}', '\0', '\0']), ('\u{4a1}', ['\u{4a0}', '\0', '\0']), ('\u{4a3}',
+ ['\u{4a2}', '\0', '\0']), ('\u{4a5}', ['\u{4a4}', '\0', '\0']), ('\u{4a7}', ['\u{4a6}',
+ '\0', '\0']), ('\u{4a9}', ['\u{4a8}', '\0', '\0']), ('\u{4ab}', ['\u{4aa}', '\0', '\0']),
+ ('\u{4ad}', ['\u{4ac}', '\0', '\0']), ('\u{4af}', ['\u{4ae}', '\0', '\0']), ('\u{4b1}',
+ ['\u{4b0}', '\0', '\0']), ('\u{4b3}', ['\u{4b2}', '\0', '\0']), ('\u{4b5}', ['\u{4b4}',
+ '\0', '\0']), ('\u{4b7}', ['\u{4b6}', '\0', '\0']), ('\u{4b9}', ['\u{4b8}', '\0', '\0']),
+ ('\u{4bb}', ['\u{4ba}', '\0', '\0']), ('\u{4bd}', ['\u{4bc}', '\0', '\0']), ('\u{4bf}',
+ ['\u{4be}', '\0', '\0']), ('\u{4c2}', ['\u{4c1}', '\0', '\0']), ('\u{4c4}', ['\u{4c3}',
+ '\0', '\0']), ('\u{4c6}', ['\u{4c5}', '\0', '\0']), ('\u{4c8}', ['\u{4c7}', '\0', '\0']),
+ ('\u{4ca}', ['\u{4c9}', '\0', '\0']), ('\u{4cc}', ['\u{4cb}', '\0', '\0']), ('\u{4ce}',
+ ['\u{4cd}', '\0', '\0']), ('\u{4cf}', ['\u{4c0}', '\0', '\0']), ('\u{4d1}', ['\u{4d0}',
+ '\0', '\0']), ('\u{4d3}', ['\u{4d2}', '\0', '\0']), ('\u{4d5}', ['\u{4d4}', '\0', '\0']),
+ ('\u{4d7}', ['\u{4d6}', '\0', '\0']), ('\u{4d9}', ['\u{4d8}', '\0', '\0']), ('\u{4db}',
+ ['\u{4da}', '\0', '\0']), ('\u{4dd}', ['\u{4dc}', '\0', '\0']), ('\u{4df}', ['\u{4de}',
+ '\0', '\0']), ('\u{4e1}', ['\u{4e0}', '\0', '\0']), ('\u{4e3}', ['\u{4e2}', '\0', '\0']),
+ ('\u{4e5}', ['\u{4e4}', '\0', '\0']), ('\u{4e7}', ['\u{4e6}', '\0', '\0']), ('\u{4e9}',
+ ['\u{4e8}', '\0', '\0']), ('\u{4eb}', ['\u{4ea}', '\0', '\0']), ('\u{4ed}', ['\u{4ec}',
+ '\0', '\0']), ('\u{4ef}', ['\u{4ee}', '\0', '\0']), ('\u{4f1}', ['\u{4f0}', '\0', '\0']),
+ ('\u{4f3}', ['\u{4f2}', '\0', '\0']), ('\u{4f5}', ['\u{4f4}', '\0', '\0']), ('\u{4f7}',
+ ['\u{4f6}', '\0', '\0']), ('\u{4f9}', ['\u{4f8}', '\0', '\0']), ('\u{4fb}', ['\u{4fa}',
+ '\0', '\0']), ('\u{4fd}', ['\u{4fc}', '\0', '\0']), ('\u{4ff}', ['\u{4fe}', '\0', '\0']),
+ ('\u{501}', ['\u{500}', '\0', '\0']), ('\u{503}', ['\u{502}', '\0', '\0']), ('\u{505}',
+ ['\u{504}', '\0', '\0']), ('\u{507}', ['\u{506}', '\0', '\0']), ('\u{509}', ['\u{508}',
+ '\0', '\0']), ('\u{50b}', ['\u{50a}', '\0', '\0']), ('\u{50d}', ['\u{50c}', '\0', '\0']),
+ ('\u{50f}', ['\u{50e}', '\0', '\0']), ('\u{511}', ['\u{510}', '\0', '\0']), ('\u{513}',
+ ['\u{512}', '\0', '\0']), ('\u{515}', ['\u{514}', '\0', '\0']), ('\u{517}', ['\u{516}',
+ '\0', '\0']), ('\u{519}', ['\u{518}', '\0', '\0']), ('\u{51b}', ['\u{51a}', '\0', '\0']),
+ ('\u{51d}', ['\u{51c}', '\0', '\0']), ('\u{51f}', ['\u{51e}', '\0', '\0']), ('\u{521}',
+ ['\u{520}', '\0', '\0']), ('\u{523}', ['\u{522}', '\0', '\0']), ('\u{525}', ['\u{524}',
+ '\0', '\0']), ('\u{527}', ['\u{526}', '\0', '\0']), ('\u{529}', ['\u{528}', '\0', '\0']),
+ ('\u{52b}', ['\u{52a}', '\0', '\0']), ('\u{52d}', ['\u{52c}', '\0', '\0']), ('\u{52f}',
+ ['\u{52e}', '\0', '\0']), ('\u{561}', ['\u{531}', '\0', '\0']), ('\u{562}', ['\u{532}',
+ '\0', '\0']), ('\u{563}', ['\u{533}', '\0', '\0']), ('\u{564}', ['\u{534}', '\0', '\0']),
+ ('\u{565}', ['\u{535}', '\0', '\0']), ('\u{566}', ['\u{536}', '\0', '\0']), ('\u{567}',
+ ['\u{537}', '\0', '\0']), ('\u{568}', ['\u{538}', '\0', '\0']), ('\u{569}', ['\u{539}',
+ '\0', '\0']), ('\u{56a}', ['\u{53a}', '\0', '\0']), ('\u{56b}', ['\u{53b}', '\0', '\0']),
+ ('\u{56c}', ['\u{53c}', '\0', '\0']), ('\u{56d}', ['\u{53d}', '\0', '\0']), ('\u{56e}',
+ ['\u{53e}', '\0', '\0']), ('\u{56f}', ['\u{53f}', '\0', '\0']), ('\u{570}', ['\u{540}',
+ '\0', '\0']), ('\u{571}', ['\u{541}', '\0', '\0']), ('\u{572}', ['\u{542}', '\0', '\0']),
+ ('\u{573}', ['\u{543}', '\0', '\0']), ('\u{574}', ['\u{544}', '\0', '\0']), ('\u{575}',
+ ['\u{545}', '\0', '\0']), ('\u{576}', ['\u{546}', '\0', '\0']), ('\u{577}', ['\u{547}',
+ '\0', '\0']), ('\u{578}', ['\u{548}', '\0', '\0']), ('\u{579}', ['\u{549}', '\0', '\0']),
+ ('\u{57a}', ['\u{54a}', '\0', '\0']), ('\u{57b}', ['\u{54b}', '\0', '\0']), ('\u{57c}',
+ ['\u{54c}', '\0', '\0']), ('\u{57d}', ['\u{54d}', '\0', '\0']), ('\u{57e}', ['\u{54e}',
+ '\0', '\0']), ('\u{57f}', ['\u{54f}', '\0', '\0']), ('\u{580}', ['\u{550}', '\0', '\0']),
+ ('\u{581}', ['\u{551}', '\0', '\0']), ('\u{582}', ['\u{552}', '\0', '\0']), ('\u{583}',
+ ['\u{553}', '\0', '\0']), ('\u{584}', ['\u{554}', '\0', '\0']), ('\u{585}', ['\u{555}',
+ '\0', '\0']), ('\u{586}', ['\u{556}', '\0', '\0']), ('\u{587}', ['\u{535}', '\u{582}',
+ '\0']), ('\u{1d79}', ['\u{a77d}', '\0', '\0']), ('\u{1d7d}', ['\u{2c63}', '\0', '\0']),
+ ('\u{1e01}', ['\u{1e00}', '\0', '\0']), ('\u{1e03}', ['\u{1e02}', '\0', '\0']), ('\u{1e05}',
+ ['\u{1e04}', '\0', '\0']), ('\u{1e07}', ['\u{1e06}', '\0', '\0']), ('\u{1e09}', ['\u{1e08}',
+ '\0', '\0']), ('\u{1e0b}', ['\u{1e0a}', '\0', '\0']), ('\u{1e0d}', ['\u{1e0c}', '\0',
+ '\0']), ('\u{1e0f}', ['\u{1e0e}', '\0', '\0']), ('\u{1e11}', ['\u{1e10}', '\0', '\0']),
+ ('\u{1e13}', ['\u{1e12}', '\0', '\0']), ('\u{1e15}', ['\u{1e14}', '\0', '\0']), ('\u{1e17}',
+ ['\u{1e16}', '\0', '\0']), ('\u{1e19}', ['\u{1e18}', '\0', '\0']), ('\u{1e1b}', ['\u{1e1a}',
+ '\0', '\0']), ('\u{1e1d}', ['\u{1e1c}', '\0', '\0']), ('\u{1e1f}', ['\u{1e1e}', '\0',
+ '\0']), ('\u{1e21}', ['\u{1e20}', '\0', '\0']), ('\u{1e23}', ['\u{1e22}', '\0', '\0']),
+ ('\u{1e25}', ['\u{1e24}', '\0', '\0']), ('\u{1e27}', ['\u{1e26}', '\0', '\0']), ('\u{1e29}',
+ ['\u{1e28}', '\0', '\0']), ('\u{1e2b}', ['\u{1e2a}', '\0', '\0']), ('\u{1e2d}', ['\u{1e2c}',
+ '\0', '\0']), ('\u{1e2f}', ['\u{1e2e}', '\0', '\0']), ('\u{1e31}', ['\u{1e30}', '\0',
+ '\0']), ('\u{1e33}', ['\u{1e32}', '\0', '\0']), ('\u{1e35}', ['\u{1e34}', '\0', '\0']),
+ ('\u{1e37}', ['\u{1e36}', '\0', '\0']), ('\u{1e39}', ['\u{1e38}', '\0', '\0']), ('\u{1e3b}',
+ ['\u{1e3a}', '\0', '\0']), ('\u{1e3d}', ['\u{1e3c}', '\0', '\0']), ('\u{1e3f}', ['\u{1e3e}',
+ '\0', '\0']), ('\u{1e41}', ['\u{1e40}', '\0', '\0']), ('\u{1e43}', ['\u{1e42}', '\0',
+ '\0']), ('\u{1e45}', ['\u{1e44}', '\0', '\0']), ('\u{1e47}', ['\u{1e46}', '\0', '\0']),
+ ('\u{1e49}', ['\u{1e48}', '\0', '\0']), ('\u{1e4b}', ['\u{1e4a}', '\0', '\0']), ('\u{1e4d}',
+ ['\u{1e4c}', '\0', '\0']), ('\u{1e4f}', ['\u{1e4e}', '\0', '\0']), ('\u{1e51}', ['\u{1e50}',
+ '\0', '\0']), ('\u{1e53}', ['\u{1e52}', '\0', '\0']), ('\u{1e55}', ['\u{1e54}', '\0',
+ '\0']), ('\u{1e57}', ['\u{1e56}', '\0', '\0']), ('\u{1e59}', ['\u{1e58}', '\0', '\0']),
+ ('\u{1e5b}', ['\u{1e5a}', '\0', '\0']), ('\u{1e5d}', ['\u{1e5c}', '\0', '\0']), ('\u{1e5f}',
+ ['\u{1e5e}', '\0', '\0']), ('\u{1e61}', ['\u{1e60}', '\0', '\0']), ('\u{1e63}', ['\u{1e62}',
+ '\0', '\0']), ('\u{1e65}', ['\u{1e64}', '\0', '\0']), ('\u{1e67}', ['\u{1e66}', '\0',
+ '\0']), ('\u{1e69}', ['\u{1e68}', '\0', '\0']), ('\u{1e6b}', ['\u{1e6a}', '\0', '\0']),
+ ('\u{1e6d}', ['\u{1e6c}', '\0', '\0']), ('\u{1e6f}', ['\u{1e6e}', '\0', '\0']), ('\u{1e71}',
+ ['\u{1e70}', '\0', '\0']), ('\u{1e73}', ['\u{1e72}', '\0', '\0']), ('\u{1e75}', ['\u{1e74}',
+ '\0', '\0']), ('\u{1e77}', ['\u{1e76}', '\0', '\0']), ('\u{1e79}', ['\u{1e78}', '\0',
+ '\0']), ('\u{1e7b}', ['\u{1e7a}', '\0', '\0']), ('\u{1e7d}', ['\u{1e7c}', '\0', '\0']),
+ ('\u{1e7f}', ['\u{1e7e}', '\0', '\0']), ('\u{1e81}', ['\u{1e80}', '\0', '\0']), ('\u{1e83}',
+ ['\u{1e82}', '\0', '\0']), ('\u{1e85}', ['\u{1e84}', '\0', '\0']), ('\u{1e87}', ['\u{1e86}',
+ '\0', '\0']), ('\u{1e89}', ['\u{1e88}', '\0', '\0']), ('\u{1e8b}', ['\u{1e8a}', '\0',
+ '\0']), ('\u{1e8d}', ['\u{1e8c}', '\0', '\0']), ('\u{1e8f}', ['\u{1e8e}', '\0', '\0']),
+ ('\u{1e91}', ['\u{1e90}', '\0', '\0']), ('\u{1e93}', ['\u{1e92}', '\0', '\0']), ('\u{1e95}',
+ ['\u{1e94}', '\0', '\0']), ('\u{1e96}', ['\u{48}', '\u{331}', '\0']), ('\u{1e97}',
+ ['\u{54}', '\u{308}', '\0']), ('\u{1e98}', ['\u{57}', '\u{30a}', '\0']), ('\u{1e99}',
+ ['\u{59}', '\u{30a}', '\0']), ('\u{1e9a}', ['\u{41}', '\u{2be}', '\0']), ('\u{1e9b}',
+ ['\u{1e60}', '\0', '\0']), ('\u{1ea1}', ['\u{1ea0}', '\0', '\0']), ('\u{1ea3}', ['\u{1ea2}',
+ '\0', '\0']), ('\u{1ea5}', ['\u{1ea4}', '\0', '\0']), ('\u{1ea7}', ['\u{1ea6}', '\0',
+ '\0']), ('\u{1ea9}', ['\u{1ea8}', '\0', '\0']), ('\u{1eab}', ['\u{1eaa}', '\0', '\0']),
+ ('\u{1ead}', ['\u{1eac}', '\0', '\0']), ('\u{1eaf}', ['\u{1eae}', '\0', '\0']), ('\u{1eb1}',
+ ['\u{1eb0}', '\0', '\0']), ('\u{1eb3}', ['\u{1eb2}', '\0', '\0']), ('\u{1eb5}', ['\u{1eb4}',
+ '\0', '\0']), ('\u{1eb7}', ['\u{1eb6}', '\0', '\0']), ('\u{1eb9}', ['\u{1eb8}', '\0',
+ '\0']), ('\u{1ebb}', ['\u{1eba}', '\0', '\0']), ('\u{1ebd}', ['\u{1ebc}', '\0', '\0']),
+ ('\u{1ebf}', ['\u{1ebe}', '\0', '\0']), ('\u{1ec1}', ['\u{1ec0}', '\0', '\0']), ('\u{1ec3}',
+ ['\u{1ec2}', '\0', '\0']), ('\u{1ec5}', ['\u{1ec4}', '\0', '\0']), ('\u{1ec7}', ['\u{1ec6}',
+ '\0', '\0']), ('\u{1ec9}', ['\u{1ec8}', '\0', '\0']), ('\u{1ecb}', ['\u{1eca}', '\0',
+ '\0']), ('\u{1ecd}', ['\u{1ecc}', '\0', '\0']), ('\u{1ecf}', ['\u{1ece}', '\0', '\0']),
+ ('\u{1ed1}', ['\u{1ed0}', '\0', '\0']), ('\u{1ed3}', ['\u{1ed2}', '\0', '\0']), ('\u{1ed5}',
+ ['\u{1ed4}', '\0', '\0']), ('\u{1ed7}', ['\u{1ed6}', '\0', '\0']), ('\u{1ed9}', ['\u{1ed8}',
+ '\0', '\0']), ('\u{1edb}', ['\u{1eda}', '\0', '\0']), ('\u{1edd}', ['\u{1edc}', '\0',
+ '\0']), ('\u{1edf}', ['\u{1ede}', '\0', '\0']), ('\u{1ee1}', ['\u{1ee0}', '\0', '\0']),
+ ('\u{1ee3}', ['\u{1ee2}', '\0', '\0']), ('\u{1ee5}', ['\u{1ee4}', '\0', '\0']), ('\u{1ee7}',
+ ['\u{1ee6}', '\0', '\0']), ('\u{1ee9}', ['\u{1ee8}', '\0', '\0']), ('\u{1eeb}', ['\u{1eea}',
+ '\0', '\0']), ('\u{1eed}', ['\u{1eec}', '\0', '\0']), ('\u{1eef}', ['\u{1eee}', '\0',
+ '\0']), ('\u{1ef1}', ['\u{1ef0}', '\0', '\0']), ('\u{1ef3}', ['\u{1ef2}', '\0', '\0']),
+ ('\u{1ef5}', ['\u{1ef4}', '\0', '\0']), ('\u{1ef7}', ['\u{1ef6}', '\0', '\0']), ('\u{1ef9}',
+ ['\u{1ef8}', '\0', '\0']), ('\u{1efb}', ['\u{1efa}', '\0', '\0']), ('\u{1efd}', ['\u{1efc}',
+ '\0', '\0']), ('\u{1eff}', ['\u{1efe}', '\0', '\0']), ('\u{1f00}', ['\u{1f08}', '\0',
+ '\0']), ('\u{1f01}', ['\u{1f09}', '\0', '\0']), ('\u{1f02}', ['\u{1f0a}', '\0', '\0']),
+ ('\u{1f03}', ['\u{1f0b}', '\0', '\0']), ('\u{1f04}', ['\u{1f0c}', '\0', '\0']), ('\u{1f05}',
+ ['\u{1f0d}', '\0', '\0']), ('\u{1f06}', ['\u{1f0e}', '\0', '\0']), ('\u{1f07}', ['\u{1f0f}',
+ '\0', '\0']), ('\u{1f10}', ['\u{1f18}', '\0', '\0']), ('\u{1f11}', ['\u{1f19}', '\0',
+ '\0']), ('\u{1f12}', ['\u{1f1a}', '\0', '\0']), ('\u{1f13}', ['\u{1f1b}', '\0', '\0']),
+ ('\u{1f14}', ['\u{1f1c}', '\0', '\0']), ('\u{1f15}', ['\u{1f1d}', '\0', '\0']), ('\u{1f20}',
+ ['\u{1f28}', '\0', '\0']), ('\u{1f21}', ['\u{1f29}', '\0', '\0']), ('\u{1f22}', ['\u{1f2a}',
+ '\0', '\0']), ('\u{1f23}', ['\u{1f2b}', '\0', '\0']), ('\u{1f24}', ['\u{1f2c}', '\0',
+ '\0']), ('\u{1f25}', ['\u{1f2d}', '\0', '\0']), ('\u{1f26}', ['\u{1f2e}', '\0', '\0']),
+ ('\u{1f27}', ['\u{1f2f}', '\0', '\0']), ('\u{1f30}', ['\u{1f38}', '\0', '\0']), ('\u{1f31}',
+ ['\u{1f39}', '\0', '\0']), ('\u{1f32}', ['\u{1f3a}', '\0', '\0']), ('\u{1f33}', ['\u{1f3b}',
+ '\0', '\0']), ('\u{1f34}', ['\u{1f3c}', '\0', '\0']), ('\u{1f35}', ['\u{1f3d}', '\0',
+ '\0']), ('\u{1f36}', ['\u{1f3e}', '\0', '\0']), ('\u{1f37}', ['\u{1f3f}', '\0', '\0']),
+ ('\u{1f40}', ['\u{1f48}', '\0', '\0']), ('\u{1f41}', ['\u{1f49}', '\0', '\0']), ('\u{1f42}',
+ ['\u{1f4a}', '\0', '\0']), ('\u{1f43}', ['\u{1f4b}', '\0', '\0']), ('\u{1f44}', ['\u{1f4c}',
+ '\0', '\0']), ('\u{1f45}', ['\u{1f4d}', '\0', '\0']), ('\u{1f50}', ['\u{3a5}', '\u{313}',
+ '\0']), ('\u{1f51}', ['\u{1f59}', '\0', '\0']), ('\u{1f52}', ['\u{3a5}', '\u{313}',
+ '\u{300}']), ('\u{1f53}', ['\u{1f5b}', '\0', '\0']), ('\u{1f54}', ['\u{3a5}', '\u{313}',
+ '\u{301}']), ('\u{1f55}', ['\u{1f5d}', '\0', '\0']), ('\u{1f56}', ['\u{3a5}', '\u{313}',
+ '\u{342}']), ('\u{1f57}', ['\u{1f5f}', '\0', '\0']), ('\u{1f60}', ['\u{1f68}', '\0', '\0']),
+ ('\u{1f61}', ['\u{1f69}', '\0', '\0']), ('\u{1f62}', ['\u{1f6a}', '\0', '\0']), ('\u{1f63}',
+ ['\u{1f6b}', '\0', '\0']), ('\u{1f64}', ['\u{1f6c}', '\0', '\0']), ('\u{1f65}', ['\u{1f6d}',
+ '\0', '\0']), ('\u{1f66}', ['\u{1f6e}', '\0', '\0']), ('\u{1f67}', ['\u{1f6f}', '\0',
+ '\0']), ('\u{1f70}', ['\u{1fba}', '\0', '\0']), ('\u{1f71}', ['\u{1fbb}', '\0', '\0']),
+ ('\u{1f72}', ['\u{1fc8}', '\0', '\0']), ('\u{1f73}', ['\u{1fc9}', '\0', '\0']), ('\u{1f74}',
+ ['\u{1fca}', '\0', '\0']), ('\u{1f75}', ['\u{1fcb}', '\0', '\0']), ('\u{1f76}', ['\u{1fda}',
+ '\0', '\0']), ('\u{1f77}', ['\u{1fdb}', '\0', '\0']), ('\u{1f78}', ['\u{1ff8}', '\0',
+ '\0']), ('\u{1f79}', ['\u{1ff9}', '\0', '\0']), ('\u{1f7a}', ['\u{1fea}', '\0', '\0']),
+ ('\u{1f7b}', ['\u{1feb}', '\0', '\0']), ('\u{1f7c}', ['\u{1ffa}', '\0', '\0']), ('\u{1f7d}',
+ ['\u{1ffb}', '\0', '\0']), ('\u{1f80}', ['\u{1f88}', '\0', '\0']), ('\u{1f81}', ['\u{1f89}',
+ '\0', '\0']), ('\u{1f82}', ['\u{1f8a}', '\0', '\0']), ('\u{1f83}', ['\u{1f8b}', '\0',
+ '\0']), ('\u{1f84}', ['\u{1f8c}', '\0', '\0']), ('\u{1f85}', ['\u{1f8d}', '\0', '\0']),
+ ('\u{1f86}', ['\u{1f8e}', '\0', '\0']), ('\u{1f87}', ['\u{1f8f}', '\0', '\0']), ('\u{1f90}',
+ ['\u{1f98}', '\0', '\0']), ('\u{1f91}', ['\u{1f99}', '\0', '\0']), ('\u{1f92}', ['\u{1f9a}',
+ '\0', '\0']), ('\u{1f93}', ['\u{1f9b}', '\0', '\0']), ('\u{1f94}', ['\u{1f9c}', '\0',
+ '\0']), ('\u{1f95}', ['\u{1f9d}', '\0', '\0']), ('\u{1f96}', ['\u{1f9e}', '\0', '\0']),
+ ('\u{1f97}', ['\u{1f9f}', '\0', '\0']), ('\u{1fa0}', ['\u{1fa8}', '\0', '\0']), ('\u{1fa1}',
+ ['\u{1fa9}', '\0', '\0']), ('\u{1fa2}', ['\u{1faa}', '\0', '\0']), ('\u{1fa3}', ['\u{1fab}',
+ '\0', '\0']), ('\u{1fa4}', ['\u{1fac}', '\0', '\0']), ('\u{1fa5}', ['\u{1fad}', '\0',
+ '\0']), ('\u{1fa6}', ['\u{1fae}', '\0', '\0']), ('\u{1fa7}', ['\u{1faf}', '\0', '\0']),
+ ('\u{1fb0}', ['\u{1fb8}', '\0', '\0']), ('\u{1fb1}', ['\u{1fb9}', '\0', '\0']), ('\u{1fb2}',
+ ['\u{1fba}', '\u{345}', '\0']), ('\u{1fb3}', ['\u{1fbc}', '\0', '\0']), ('\u{1fb4}',
+ ['\u{386}', '\u{345}', '\0']), ('\u{1fb6}', ['\u{391}', '\u{342}', '\0']), ('\u{1fb7}',
+ ['\u{391}', '\u{342}', '\u{345}']), ('\u{1fbe}', ['\u{399}', '\0', '\0']), ('\u{1fc2}',
+ ['\u{1fca}', '\u{345}', '\0']), ('\u{1fc3}', ['\u{1fcc}', '\0', '\0']), ('\u{1fc4}',
+ ['\u{389}', '\u{345}', '\0']), ('\u{1fc6}', ['\u{397}', '\u{342}', '\0']), ('\u{1fc7}',
+ ['\u{397}', '\u{342}', '\u{345}']), ('\u{1fd0}', ['\u{1fd8}', '\0', '\0']), ('\u{1fd1}',
+ ['\u{1fd9}', '\0', '\0']), ('\u{1fd2}', ['\u{399}', '\u{308}', '\u{300}']), ('\u{1fd3}',
+ ['\u{399}', '\u{308}', '\u{301}']), ('\u{1fd6}', ['\u{399}', '\u{342}', '\0']), ('\u{1fd7}',
+ ['\u{399}', '\u{308}', '\u{342}']), ('\u{1fe0}', ['\u{1fe8}', '\0', '\0']), ('\u{1fe1}',
+ ['\u{1fe9}', '\0', '\0']), ('\u{1fe2}', ['\u{3a5}', '\u{308}', '\u{300}']), ('\u{1fe3}',
+ ['\u{3a5}', '\u{308}', '\u{301}']), ('\u{1fe4}', ['\u{3a1}', '\u{313}', '\0']), ('\u{1fe5}',
+ ['\u{1fec}', '\0', '\0']), ('\u{1fe6}', ['\u{3a5}', '\u{342}', '\0']), ('\u{1fe7}',
+ ['\u{3a5}', '\u{308}', '\u{342}']), ('\u{1ff2}', ['\u{1ffa}', '\u{345}', '\0']),
+ ('\u{1ff3}', ['\u{1ffc}', '\0', '\0']), ('\u{1ff4}', ['\u{38f}', '\u{345}', '\0']),
+ ('\u{1ff6}', ['\u{3a9}', '\u{342}', '\0']), ('\u{1ff7}', ['\u{3a9}', '\u{342}', '\u{345}']),
+ ('\u{214e}', ['\u{2132}', '\0', '\0']), ('\u{2170}', ['\u{2160}', '\0', '\0']), ('\u{2171}',
+ ['\u{2161}', '\0', '\0']), ('\u{2172}', ['\u{2162}', '\0', '\0']), ('\u{2173}', ['\u{2163}',
+ '\0', '\0']), ('\u{2174}', ['\u{2164}', '\0', '\0']), ('\u{2175}', ['\u{2165}', '\0',
+ '\0']), ('\u{2176}', ['\u{2166}', '\0', '\0']), ('\u{2177}', ['\u{2167}', '\0', '\0']),
+ ('\u{2178}', ['\u{2168}', '\0', '\0']), ('\u{2179}', ['\u{2169}', '\0', '\0']), ('\u{217a}',
+ ['\u{216a}', '\0', '\0']), ('\u{217b}', ['\u{216b}', '\0', '\0']), ('\u{217c}', ['\u{216c}',
+ '\0', '\0']), ('\u{217d}', ['\u{216d}', '\0', '\0']), ('\u{217e}', ['\u{216e}', '\0',
+ '\0']), ('\u{217f}', ['\u{216f}', '\0', '\0']), ('\u{2184}', ['\u{2183}', '\0', '\0']),
+ ('\u{24d0}', ['\u{24b6}', '\0', '\0']), ('\u{24d1}', ['\u{24b7}', '\0', '\0']), ('\u{24d2}',
+ ['\u{24b8}', '\0', '\0']), ('\u{24d3}', ['\u{24b9}', '\0', '\0']), ('\u{24d4}', ['\u{24ba}',
+ '\0', '\0']), ('\u{24d5}', ['\u{24bb}', '\0', '\0']), ('\u{24d6}', ['\u{24bc}', '\0',
+ '\0']), ('\u{24d7}', ['\u{24bd}', '\0', '\0']), ('\u{24d8}', ['\u{24be}', '\0', '\0']),
+ ('\u{24d9}', ['\u{24bf}', '\0', '\0']), ('\u{24da}', ['\u{24c0}', '\0', '\0']), ('\u{24db}',
+ ['\u{24c1}', '\0', '\0']), ('\u{24dc}', ['\u{24c2}', '\0', '\0']), ('\u{24dd}', ['\u{24c3}',
+ '\0', '\0']), ('\u{24de}', ['\u{24c4}', '\0', '\0']), ('\u{24df}', ['\u{24c5}', '\0',
+ '\0']), ('\u{24e0}', ['\u{24c6}', '\0', '\0']), ('\u{24e1}', ['\u{24c7}', '\0', '\0']),
+ ('\u{24e2}', ['\u{24c8}', '\0', '\0']), ('\u{24e3}', ['\u{24c9}', '\0', '\0']), ('\u{24e4}',
+ ['\u{24ca}', '\0', '\0']), ('\u{24e5}', ['\u{24cb}', '\0', '\0']), ('\u{24e6}', ['\u{24cc}',
+ '\0', '\0']), ('\u{24e7}', ['\u{24cd}', '\0', '\0']), ('\u{24e8}', ['\u{24ce}', '\0',
+ '\0']), ('\u{24e9}', ['\u{24cf}', '\0', '\0']), ('\u{2c30}', ['\u{2c00}', '\0', '\0']),
+ ('\u{2c31}', ['\u{2c01}', '\0', '\0']), ('\u{2c32}', ['\u{2c02}', '\0', '\0']), ('\u{2c33}',
+ ['\u{2c03}', '\0', '\0']), ('\u{2c34}', ['\u{2c04}', '\0', '\0']), ('\u{2c35}', ['\u{2c05}',
+ '\0', '\0']), ('\u{2c36}', ['\u{2c06}', '\0', '\0']), ('\u{2c37}', ['\u{2c07}', '\0',
+ '\0']), ('\u{2c38}', ['\u{2c08}', '\0', '\0']), ('\u{2c39}', ['\u{2c09}', '\0', '\0']),
+ ('\u{2c3a}', ['\u{2c0a}', '\0', '\0']), ('\u{2c3b}', ['\u{2c0b}', '\0', '\0']), ('\u{2c3c}',
+ ['\u{2c0c}', '\0', '\0']), ('\u{2c3d}', ['\u{2c0d}', '\0', '\0']), ('\u{2c3e}', ['\u{2c0e}',
+ '\0', '\0']), ('\u{2c3f}', ['\u{2c0f}', '\0', '\0']), ('\u{2c40}', ['\u{2c10}', '\0',
+ '\0']), ('\u{2c41}', ['\u{2c11}', '\0', '\0']), ('\u{2c42}', ['\u{2c12}', '\0', '\0']),
+ ('\u{2c43}', ['\u{2c13}', '\0', '\0']), ('\u{2c44}', ['\u{2c14}', '\0', '\0']), ('\u{2c45}',
+ ['\u{2c15}', '\0', '\0']), ('\u{2c46}', ['\u{2c16}', '\0', '\0']), ('\u{2c47}', ['\u{2c17}',
+ '\0', '\0']), ('\u{2c48}', ['\u{2c18}', '\0', '\0']), ('\u{2c49}', ['\u{2c19}', '\0',
+ '\0']), ('\u{2c4a}', ['\u{2c1a}', '\0', '\0']), ('\u{2c4b}', ['\u{2c1b}', '\0', '\0']),
+ ('\u{2c4c}', ['\u{2c1c}', '\0', '\0']), ('\u{2c4d}', ['\u{2c1d}', '\0', '\0']), ('\u{2c4e}',
+ ['\u{2c1e}', '\0', '\0']), ('\u{2c4f}', ['\u{2c1f}', '\0', '\0']), ('\u{2c50}', ['\u{2c20}',
+ '\0', '\0']), ('\u{2c51}', ['\u{2c21}', '\0', '\0']), ('\u{2c52}', ['\u{2c22}', '\0',
+ '\0']), ('\u{2c53}', ['\u{2c23}', '\0', '\0']), ('\u{2c54}', ['\u{2c24}', '\0', '\0']),
+ ('\u{2c55}', ['\u{2c25}', '\0', '\0']), ('\u{2c56}', ['\u{2c26}', '\0', '\0']), ('\u{2c57}',
+ ['\u{2c27}', '\0', '\0']), ('\u{2c58}', ['\u{2c28}', '\0', '\0']), ('\u{2c59}', ['\u{2c29}',
+ '\0', '\0']), ('\u{2c5a}', ['\u{2c2a}', '\0', '\0']), ('\u{2c5b}', ['\u{2c2b}', '\0',
+ '\0']), ('\u{2c5c}', ['\u{2c2c}', '\0', '\0']), ('\u{2c5d}', ['\u{2c2d}', '\0', '\0']),
+ ('\u{2c5e}', ['\u{2c2e}', '\0', '\0']), ('\u{2c61}', ['\u{2c60}', '\0', '\0']), ('\u{2c65}',
+ ['\u{23a}', '\0', '\0']), ('\u{2c66}', ['\u{23e}', '\0', '\0']), ('\u{2c68}', ['\u{2c67}',
+ '\0', '\0']), ('\u{2c6a}', ['\u{2c69}', '\0', '\0']), ('\u{2c6c}', ['\u{2c6b}', '\0',
+ '\0']), ('\u{2c73}', ['\u{2c72}', '\0', '\0']), ('\u{2c76}', ['\u{2c75}', '\0', '\0']),
+ ('\u{2c81}', ['\u{2c80}', '\0', '\0']), ('\u{2c83}', ['\u{2c82}', '\0', '\0']), ('\u{2c85}',
+ ['\u{2c84}', '\0', '\0']), ('\u{2c87}', ['\u{2c86}', '\0', '\0']), ('\u{2c89}', ['\u{2c88}',
+ '\0', '\0']), ('\u{2c8b}', ['\u{2c8a}', '\0', '\0']), ('\u{2c8d}', ['\u{2c8c}', '\0',
+ '\0']), ('\u{2c8f}', ['\u{2c8e}', '\0', '\0']), ('\u{2c91}', ['\u{2c90}', '\0', '\0']),
+ ('\u{2c93}', ['\u{2c92}', '\0', '\0']), ('\u{2c95}', ['\u{2c94}', '\0', '\0']), ('\u{2c97}',
+ ['\u{2c96}', '\0', '\0']), ('\u{2c99}', ['\u{2c98}', '\0', '\0']), ('\u{2c9b}', ['\u{2c9a}',
+ '\0', '\0']), ('\u{2c9d}', ['\u{2c9c}', '\0', '\0']), ('\u{2c9f}', ['\u{2c9e}', '\0',
+ '\0']), ('\u{2ca1}', ['\u{2ca0}', '\0', '\0']), ('\u{2ca3}', ['\u{2ca2}', '\0', '\0']),
+ ('\u{2ca5}', ['\u{2ca4}', '\0', '\0']), ('\u{2ca7}', ['\u{2ca6}', '\0', '\0']), ('\u{2ca9}',
+ ['\u{2ca8}', '\0', '\0']), ('\u{2cab}', ['\u{2caa}', '\0', '\0']), ('\u{2cad}', ['\u{2cac}',
+ '\0', '\0']), ('\u{2caf}', ['\u{2cae}', '\0', '\0']), ('\u{2cb1}', ['\u{2cb0}', '\0',
+ '\0']), ('\u{2cb3}', ['\u{2cb2}', '\0', '\0']), ('\u{2cb5}', ['\u{2cb4}', '\0', '\0']),
+ ('\u{2cb7}', ['\u{2cb6}', '\0', '\0']), ('\u{2cb9}', ['\u{2cb8}', '\0', '\0']), ('\u{2cbb}',
+ ['\u{2cba}', '\0', '\0']), ('\u{2cbd}', ['\u{2cbc}', '\0', '\0']), ('\u{2cbf}', ['\u{2cbe}',
+ '\0', '\0']), ('\u{2cc1}', ['\u{2cc0}', '\0', '\0']), ('\u{2cc3}', ['\u{2cc2}', '\0',
+ '\0']), ('\u{2cc5}', ['\u{2cc4}', '\0', '\0']), ('\u{2cc7}', ['\u{2cc6}', '\0', '\0']),
+ ('\u{2cc9}', ['\u{2cc8}', '\0', '\0']), ('\u{2ccb}', ['\u{2cca}', '\0', '\0']), ('\u{2ccd}',
+ ['\u{2ccc}', '\0', '\0']), ('\u{2ccf}', ['\u{2cce}', '\0', '\0']), ('\u{2cd1}', ['\u{2cd0}',
+ '\0', '\0']), ('\u{2cd3}', ['\u{2cd2}', '\0', '\0']), ('\u{2cd5}', ['\u{2cd4}', '\0',
+ '\0']), ('\u{2cd7}', ['\u{2cd6}', '\0', '\0']), ('\u{2cd9}', ['\u{2cd8}', '\0', '\0']),
+ ('\u{2cdb}', ['\u{2cda}', '\0', '\0']), ('\u{2cdd}', ['\u{2cdc}', '\0', '\0']), ('\u{2cdf}',
+ ['\u{2cde}', '\0', '\0']), ('\u{2ce1}', ['\u{2ce0}', '\0', '\0']), ('\u{2ce3}', ['\u{2ce2}',
+ '\0', '\0']), ('\u{2cec}', ['\u{2ceb}', '\0', '\0']), ('\u{2cee}', ['\u{2ced}', '\0',
+ '\0']), ('\u{2cf3}', ['\u{2cf2}', '\0', '\0']), ('\u{2d00}', ['\u{10a0}', '\0', '\0']),
+ ('\u{2d01}', ['\u{10a1}', '\0', '\0']), ('\u{2d02}', ['\u{10a2}', '\0', '\0']), ('\u{2d03}',
+ ['\u{10a3}', '\0', '\0']), ('\u{2d04}', ['\u{10a4}', '\0', '\0']), ('\u{2d05}', ['\u{10a5}',
+ '\0', '\0']), ('\u{2d06}', ['\u{10a6}', '\0', '\0']), ('\u{2d07}', ['\u{10a7}', '\0',
+ '\0']), ('\u{2d08}', ['\u{10a8}', '\0', '\0']), ('\u{2d09}', ['\u{10a9}', '\0', '\0']),
+ ('\u{2d0a}', ['\u{10aa}', '\0', '\0']), ('\u{2d0b}', ['\u{10ab}', '\0', '\0']), ('\u{2d0c}',
+ ['\u{10ac}', '\0', '\0']), ('\u{2d0d}', ['\u{10ad}', '\0', '\0']), ('\u{2d0e}', ['\u{10ae}',
+ '\0', '\0']), ('\u{2d0f}', ['\u{10af}', '\0', '\0']), ('\u{2d10}', ['\u{10b0}', '\0',
+ '\0']), ('\u{2d11}', ['\u{10b1}', '\0', '\0']), ('\u{2d12}', ['\u{10b2}', '\0', '\0']),
+ ('\u{2d13}', ['\u{10b3}', '\0', '\0']), ('\u{2d14}', ['\u{10b4}', '\0', '\0']), ('\u{2d15}',
+ ['\u{10b5}', '\0', '\0']), ('\u{2d16}', ['\u{10b6}', '\0', '\0']), ('\u{2d17}', ['\u{10b7}',
+ '\0', '\0']), ('\u{2d18}', ['\u{10b8}', '\0', '\0']), ('\u{2d19}', ['\u{10b9}', '\0',
+ '\0']), ('\u{2d1a}', ['\u{10ba}', '\0', '\0']), ('\u{2d1b}', ['\u{10bb}', '\0', '\0']),
+ ('\u{2d1c}', ['\u{10bc}', '\0', '\0']), ('\u{2d1d}', ['\u{10bd}', '\0', '\0']), ('\u{2d1e}',
+ ['\u{10be}', '\0', '\0']), ('\u{2d1f}', ['\u{10bf}', '\0', '\0']), ('\u{2d20}', ['\u{10c0}',
+ '\0', '\0']), ('\u{2d21}', ['\u{10c1}', '\0', '\0']), ('\u{2d22}', ['\u{10c2}', '\0',
+ '\0']), ('\u{2d23}', ['\u{10c3}', '\0', '\0']), ('\u{2d24}', ['\u{10c4}', '\0', '\0']),
+ ('\u{2d25}', ['\u{10c5}', '\0', '\0']), ('\u{2d27}', ['\u{10c7}', '\0', '\0']), ('\u{2d2d}',
+ ['\u{10cd}', '\0', '\0']), ('\u{a641}', ['\u{a640}', '\0', '\0']), ('\u{a643}', ['\u{a642}',
+ '\0', '\0']), ('\u{a645}', ['\u{a644}', '\0', '\0']), ('\u{a647}', ['\u{a646}', '\0',
+ '\0']), ('\u{a649}', ['\u{a648}', '\0', '\0']), ('\u{a64b}', ['\u{a64a}', '\0', '\0']),
+ ('\u{a64d}', ['\u{a64c}', '\0', '\0']), ('\u{a64f}', ['\u{a64e}', '\0', '\0']), ('\u{a651}',
+ ['\u{a650}', '\0', '\0']), ('\u{a653}', ['\u{a652}', '\0', '\0']), ('\u{a655}', ['\u{a654}',
+ '\0', '\0']), ('\u{a657}', ['\u{a656}', '\0', '\0']), ('\u{a659}', ['\u{a658}', '\0',
+ '\0']), ('\u{a65b}', ['\u{a65a}', '\0', '\0']), ('\u{a65d}', ['\u{a65c}', '\0', '\0']),
+ ('\u{a65f}', ['\u{a65e}', '\0', '\0']), ('\u{a661}', ['\u{a660}', '\0', '\0']), ('\u{a663}',
+ ['\u{a662}', '\0', '\0']), ('\u{a665}', ['\u{a664}', '\0', '\0']), ('\u{a667}', ['\u{a666}',
+ '\0', '\0']), ('\u{a669}', ['\u{a668}', '\0', '\0']), ('\u{a66b}', ['\u{a66a}', '\0',
+ '\0']), ('\u{a66d}', ['\u{a66c}', '\0', '\0']), ('\u{a681}', ['\u{a680}', '\0', '\0']),
+ ('\u{a683}', ['\u{a682}', '\0', '\0']), ('\u{a685}', ['\u{a684}', '\0', '\0']), ('\u{a687}',
+ ['\u{a686}', '\0', '\0']), ('\u{a689}', ['\u{a688}', '\0', '\0']), ('\u{a68b}', ['\u{a68a}',
+ '\0', '\0']), ('\u{a68d}', ['\u{a68c}', '\0', '\0']), ('\u{a68f}', ['\u{a68e}', '\0',
+ '\0']), ('\u{a691}', ['\u{a690}', '\0', '\0']), ('\u{a693}', ['\u{a692}', '\0', '\0']),
+ ('\u{a695}', ['\u{a694}', '\0', '\0']), ('\u{a697}', ['\u{a696}', '\0', '\0']), ('\u{a699}',
+ ['\u{a698}', '\0', '\0']), ('\u{a69b}', ['\u{a69a}', '\0', '\0']), ('\u{a723}', ['\u{a722}',
+ '\0', '\0']), ('\u{a725}', ['\u{a724}', '\0', '\0']), ('\u{a727}', ['\u{a726}', '\0',
+ '\0']), ('\u{a729}', ['\u{a728}', '\0', '\0']), ('\u{a72b}', ['\u{a72a}', '\0', '\0']),
+ ('\u{a72d}', ['\u{a72c}', '\0', '\0']), ('\u{a72f}', ['\u{a72e}', '\0', '\0']), ('\u{a733}',
+ ['\u{a732}', '\0', '\0']), ('\u{a735}', ['\u{a734}', '\0', '\0']), ('\u{a737}', ['\u{a736}',
+ '\0', '\0']), ('\u{a739}', ['\u{a738}', '\0', '\0']), ('\u{a73b}', ['\u{a73a}', '\0',
+ '\0']), ('\u{a73d}', ['\u{a73c}', '\0', '\0']), ('\u{a73f}', ['\u{a73e}', '\0', '\0']),
+ ('\u{a741}', ['\u{a740}', '\0', '\0']), ('\u{a743}', ['\u{a742}', '\0', '\0']), ('\u{a745}',
+ ['\u{a744}', '\0', '\0']), ('\u{a747}', ['\u{a746}', '\0', '\0']), ('\u{a749}', ['\u{a748}',
+ '\0', '\0']), ('\u{a74b}', ['\u{a74a}', '\0', '\0']), ('\u{a74d}', ['\u{a74c}', '\0',
+ '\0']), ('\u{a74f}', ['\u{a74e}', '\0', '\0']), ('\u{a751}', ['\u{a750}', '\0', '\0']),
+ ('\u{a753}', ['\u{a752}', '\0', '\0']), ('\u{a755}', ['\u{a754}', '\0', '\0']), ('\u{a757}',
+ ['\u{a756}', '\0', '\0']), ('\u{a759}', ['\u{a758}', '\0', '\0']), ('\u{a75b}', ['\u{a75a}',
+ '\0', '\0']), ('\u{a75d}', ['\u{a75c}', '\0', '\0']), ('\u{a75f}', ['\u{a75e}', '\0',
+ '\0']), ('\u{a761}', ['\u{a760}', '\0', '\0']), ('\u{a763}', ['\u{a762}', '\0', '\0']),
+ ('\u{a765}', ['\u{a764}', '\0', '\0']), ('\u{a767}', ['\u{a766}', '\0', '\0']), ('\u{a769}',
+ ['\u{a768}', '\0', '\0']), ('\u{a76b}', ['\u{a76a}', '\0', '\0']), ('\u{a76d}', ['\u{a76c}',
+ '\0', '\0']), ('\u{a76f}', ['\u{a76e}', '\0', '\0']), ('\u{a77a}', ['\u{a779}', '\0',
+ '\0']), ('\u{a77c}', ['\u{a77b}', '\0', '\0']), ('\u{a77f}', ['\u{a77e}', '\0', '\0']),
+ ('\u{a781}', ['\u{a780}', '\0', '\0']), ('\u{a783}', ['\u{a782}', '\0', '\0']), ('\u{a785}',
+ ['\u{a784}', '\0', '\0']), ('\u{a787}', ['\u{a786}', '\0', '\0']), ('\u{a78c}', ['\u{a78b}',
+ '\0', '\0']), ('\u{a791}', ['\u{a790}', '\0', '\0']), ('\u{a793}', ['\u{a792}', '\0',
+ '\0']), ('\u{a797}', ['\u{a796}', '\0', '\0']), ('\u{a799}', ['\u{a798}', '\0', '\0']),
+ ('\u{a79b}', ['\u{a79a}', '\0', '\0']), ('\u{a79d}', ['\u{a79c}', '\0', '\0']), ('\u{a79f}',
+ ['\u{a79e}', '\0', '\0']), ('\u{a7a1}', ['\u{a7a0}', '\0', '\0']), ('\u{a7a3}', ['\u{a7a2}',
+ '\0', '\0']), ('\u{a7a5}', ['\u{a7a4}', '\0', '\0']), ('\u{a7a7}', ['\u{a7a6}', '\0',
+ '\0']), ('\u{a7a9}', ['\u{a7a8}', '\0', '\0']), ('\u{fb00}', ['\u{46}', '\u{66}', '\0']),
+ ('\u{fb01}', ['\u{46}', '\u{69}', '\0']), ('\u{fb02}', ['\u{46}', '\u{6c}', '\0']),
+ ('\u{fb03}', ['\u{46}', '\u{66}', '\u{69}']), ('\u{fb04}', ['\u{46}', '\u{66}', '\u{6c}']),
+ ('\u{fb05}', ['\u{53}', '\u{74}', '\0']), ('\u{fb06}', ['\u{53}', '\u{74}', '\0']),
+ ('\u{fb13}', ['\u{544}', '\u{576}', '\0']), ('\u{fb14}', ['\u{544}', '\u{565}', '\0']),
+ ('\u{fb15}', ['\u{544}', '\u{56b}', '\0']), ('\u{fb16}', ['\u{54e}', '\u{576}', '\0']),
+ ('\u{fb17}', ['\u{544}', '\u{56d}', '\0']), ('\u{ff41}', ['\u{ff21}', '\0', '\0']),
+ ('\u{ff42}', ['\u{ff22}', '\0', '\0']), ('\u{ff43}', ['\u{ff23}', '\0', '\0']), ('\u{ff44}',
+ ['\u{ff24}', '\0', '\0']), ('\u{ff45}', ['\u{ff25}', '\0', '\0']), ('\u{ff46}', ['\u{ff26}',
+ '\0', '\0']), ('\u{ff47}', ['\u{ff27}', '\0', '\0']), ('\u{ff48}', ['\u{ff28}', '\0',
+ '\0']), ('\u{ff49}', ['\u{ff29}', '\0', '\0']), ('\u{ff4a}', ['\u{ff2a}', '\0', '\0']),
+ ('\u{ff4b}', ['\u{ff2b}', '\0', '\0']), ('\u{ff4c}', ['\u{ff2c}', '\0', '\0']), ('\u{ff4d}',
+ ['\u{ff2d}', '\0', '\0']), ('\u{ff4e}', ['\u{ff2e}', '\0', '\0']), ('\u{ff4f}', ['\u{ff2f}',
+ '\0', '\0']), ('\u{ff50}', ['\u{ff30}', '\0', '\0']), ('\u{ff51}', ['\u{ff31}', '\0',
+ '\0']), ('\u{ff52}', ['\u{ff32}', '\0', '\0']), ('\u{ff53}', ['\u{ff33}', '\0', '\0']),
+ ('\u{ff54}', ['\u{ff34}', '\0', '\0']), ('\u{ff55}', ['\u{ff35}', '\0', '\0']), ('\u{ff56}',
+ ['\u{ff36}', '\0', '\0']), ('\u{ff57}', ['\u{ff37}', '\0', '\0']), ('\u{ff58}', ['\u{ff38}',
+ '\0', '\0']), ('\u{ff59}', ['\u{ff39}', '\0', '\0']), ('\u{ff5a}', ['\u{ff3a}', '\0',
+ '\0']), ('\u{10428}', ['\u{10400}', '\0', '\0']), ('\u{10429}', ['\u{10401}', '\0', '\0']),
+ ('\u{1042a}', ['\u{10402}', '\0', '\0']), ('\u{1042b}', ['\u{10403}', '\0', '\0']),
+ ('\u{1042c}', ['\u{10404}', '\0', '\0']), ('\u{1042d}', ['\u{10405}', '\0', '\0']),
+ ('\u{1042e}', ['\u{10406}', '\0', '\0']), ('\u{1042f}', ['\u{10407}', '\0', '\0']),
+ ('\u{10430}', ['\u{10408}', '\0', '\0']), ('\u{10431}', ['\u{10409}', '\0', '\0']),
+ ('\u{10432}', ['\u{1040a}', '\0', '\0']), ('\u{10433}', ['\u{1040b}', '\0', '\0']),
+ ('\u{10434}', ['\u{1040c}', '\0', '\0']), ('\u{10435}', ['\u{1040d}', '\0', '\0']),
+ ('\u{10436}', ['\u{1040e}', '\0', '\0']), ('\u{10437}', ['\u{1040f}', '\0', '\0']),
+ ('\u{10438}', ['\u{10410}', '\0', '\0']), ('\u{10439}', ['\u{10411}', '\0', '\0']),
+ ('\u{1043a}', ['\u{10412}', '\0', '\0']), ('\u{1043b}', ['\u{10413}', '\0', '\0']),
+ ('\u{1043c}', ['\u{10414}', '\0', '\0']), ('\u{1043d}', ['\u{10415}', '\0', '\0']),
+ ('\u{1043e}', ['\u{10416}', '\0', '\0']), ('\u{1043f}', ['\u{10417}', '\0', '\0']),
+ ('\u{10440}', ['\u{10418}', '\0', '\0']), ('\u{10441}', ['\u{10419}', '\0', '\0']),
+ ('\u{10442}', ['\u{1041a}', '\0', '\0']), ('\u{10443}', ['\u{1041b}', '\0', '\0']),
+ ('\u{10444}', ['\u{1041c}', '\0', '\0']), ('\u{10445}', ['\u{1041d}', '\0', '\0']),
+ ('\u{10446}', ['\u{1041e}', '\0', '\0']), ('\u{10447}', ['\u{1041f}', '\0', '\0']),
+ ('\u{10448}', ['\u{10420}', '\0', '\0']), ('\u{10449}', ['\u{10421}', '\0', '\0']),
+ ('\u{1044a}', ['\u{10422}', '\0', '\0']), ('\u{1044b}', ['\u{10423}', '\0', '\0']),
+ ('\u{1044c}', ['\u{10424}', '\0', '\0']), ('\u{1044d}', ['\u{10425}', '\0', '\0']),
+ ('\u{1044e}', ['\u{10426}', '\0', '\0']), ('\u{1044f}', ['\u{10427}', '\0', '\0']),
+ ('\u{118c0}', ['\u{118a0}', '\0', '\0']), ('\u{118c1}', ['\u{118a1}', '\0', '\0']),
+ ('\u{118c2}', ['\u{118a2}', '\0', '\0']), ('\u{118c3}', ['\u{118a3}', '\0', '\0']),
+ ('\u{118c4}', ['\u{118a4}', '\0', '\0']), ('\u{118c5}', ['\u{118a5}', '\0', '\0']),
+ ('\u{118c6}', ['\u{118a6}', '\0', '\0']), ('\u{118c7}', ['\u{118a7}', '\0', '\0']),
+ ('\u{118c8}', ['\u{118a8}', '\0', '\0']), ('\u{118c9}', ['\u{118a9}', '\0', '\0']),
+ ('\u{118ca}', ['\u{118aa}', '\0', '\0']), ('\u{118cb}', ['\u{118ab}', '\0', '\0']),
+ ('\u{118cc}', ['\u{118ac}', '\0', '\0']), ('\u{118cd}', ['\u{118ad}', '\0', '\0']),
+ ('\u{118ce}', ['\u{118ae}', '\0', '\0']), ('\u{118cf}', ['\u{118af}', '\0', '\0']),
+ ('\u{118d0}', ['\u{118b0}', '\0', '\0']), ('\u{118d1}', ['\u{118b1}', '\0', '\0']),
+ ('\u{118d2}', ['\u{118b2}', '\0', '\0']), ('\u{118d3}', ['\u{118b3}', '\0', '\0']),
+ ('\u{118d4}', ['\u{118b4}', '\0', '\0']), ('\u{118d5}', ['\u{118b5}', '\0', '\0']),
+ ('\u{118d6}', ['\u{118b6}', '\0', '\0']), ('\u{118d7}', ['\u{118b7}', '\0', '\0']),
+ ('\u{118d8}', ['\u{118b8}', '\0', '\0']), ('\u{118d9}', ['\u{118b9}', '\0', '\0']),
+ ('\u{118da}', ['\u{118ba}', '\0', '\0']), ('\u{118db}', ['\u{118bb}', '\0', '\0']),
+ ('\u{118dc}', ['\u{118bc}', '\0', '\0']), ('\u{118dd}', ['\u{118bd}', '\0', '\0']),
+ ('\u{118de}', ['\u{118be}', '\0', '\0']), ('\u{118df}', ['\u{118bf}', '\0', '\0'])
];
}
}
const grapheme_cat_table: &'static [(char, char, GraphemeCat)] = &[
- ('\u{0}', '\u{1f}', GC_Control), ('\u{7f}', '\u{9f}', GC_Control), ('\u{ad}', '\u{ad}',
+ ('\0', '\u{1f}', GC_Control), ('\u{7f}', '\u{9f}', GC_Control), ('\u{ad}', '\u{ad}',
GC_Control), ('\u{300}', '\u{36f}', GC_Extend), ('\u{483}', '\u{489}', GC_Extend),
('\u{591}', '\u{5bd}', GC_Extend), ('\u{5bf}', '\u{5bf}', GC_Extend), ('\u{5c1}', '\u{5c2}',
GC_Extend), ('\u{5c4}', '\u{5c5}', GC_Extend), ('\u{5c7}', '\u{5c7}', GC_Extend),
}
def::DefStruct(did) => {
record_extern_fqn(cx, did, clean::TypeStruct);
- ret.extend(build_impls(cx, tcx, did).into_iter());
+ ret.extend(build_impls(cx, tcx, did));
clean::StructItem(build_struct(cx, tcx, did))
}
def::DefTy(did, false) => {
record_extern_fqn(cx, did, clean::TypeTypedef);
- ret.extend(build_impls(cx, tcx, did).into_iter());
+ ret.extend(build_impls(cx, tcx, did));
build_type(cx, tcx, did)
}
def::DefTy(did, true) => {
record_extern_fqn(cx, did, clean::TypeEnum);
- ret.extend(build_impls(cx, tcx, did).into_iter());
+ ret.extend(build_impls(cx, tcx, did));
build_type(cx, tcx, did)
}
// Assume that the enum type is reexported next to the variant, and
fn build_external_function(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId) -> clean::Function {
let t = ty::lookup_item_type(tcx, did);
let (decl, style, abi) = match t.ty.sty {
- ty::ty_bare_fn(_, ref f) => ((did, &f.sig).clean(cx), f.unsafety, f.abi),
+ ty::TyBareFn(_, ref f) => ((did, &f.sig).clean(cx), f.unsafety, f.abi),
_ => panic!("bad function"),
};
let predicates = ty::lookup_predicates(tcx, did);
decl: decl,
generics: (&t.generics, &predicates, subst::FnSpace).clean(cx),
unsafety: style,
+ constness: ast::Constness::NotConst,
abi: abi,
}
}
let t = ty::lookup_item_type(tcx, did);
let predicates = ty::lookup_predicates(tcx, did);
match t.ty.sty {
- ty::ty_enum(edid, _) if !csearch::is_typedef(&tcx.sess.cstore, did) => {
+ ty::TyEnum(edid, _) if !csearch::is_typedef(&tcx.sess.cstore, did) => {
return clean::EnumItem(clean::Enum {
generics: (&t.generics, &predicates, subst::TypeSpace).clean(cx),
variants_stripped: false,
clean::TypedefItem(clean::Typedef {
type_: t.ty.clean(cx),
generics: (&t.generics, &predicates, subst::TypeSpace).clean(cx),
- })
+ }, false)
}
pub fn build_impls(cx: &DocContext, tcx: &ty::ctxt,
}) => {
clean::MethodItem(clean::Method {
unsafety: unsafety,
+ constness: ast::Constness::NotConst,
decl: decl,
self_: self_,
generics: generics,
}
ty::TypeTraitItem(ref assoc_ty) => {
let did = assoc_ty.def_id;
- let type_scheme = ty::lookup_item_type(tcx, did);
- let predicates = ty::lookup_predicates(tcx, did);
+ let type_scheme = ty::TypeScheme {
+ ty: assoc_ty.ty.unwrap(),
+ generics: ty::Generics::empty()
+ };
// Not sure the choice of ParamSpace actually matters here,
// because an associated type won't have generics on the LHS
- let typedef = (type_scheme, predicates,
+ let typedef = (type_scheme, ty::GenericPredicates::empty(),
subst::ParamSpace::TypeSpace).clean(cx);
Some(clean::Item {
name: Some(assoc_ty.name.clean(cx)),
- inner: clean::TypedefItem(typedef),
+ inner: clean::TypedefItem(typedef, true),
source: clean::Span::empty(),
attrs: vec![],
visibility: None,
decoder::DlDef(def) if vis == ast::Public => {
if !visited.insert(def) { return }
match try_inline_def(cx, tcx, def) {
- Some(i) => items.extend(i.into_iter()),
+ Some(i) => items.extend(i),
None => {}
}
}
/// A stable identifier to the particular version of JSON output.
/// Increment this when the `Crate` and related structures change.
-pub static SCHEMA_VERSION: &'static str = "0.8.3";
+pub const SCHEMA_VERSION: &'static str = "0.8.3";
mod inline;
mod simplify;
inner: PrimitiveItem(prim),
});
}
- m.items.extend(tmp.into_iter());
+ m.items.extend(tmp);
}
let src = match cx.input {
EnumItem(Enum),
FunctionItem(Function),
ModuleItem(Module),
- TypedefItem(Typedef),
+ TypedefItem(Typedef, bool /* is associated type */),
StaticItem(Static),
ConstantItem(Constant),
TraitItem(Trait),
let mut items: Vec<Item> = vec![];
items.extend(self.extern_crates.iter().map(|x| x.clean(cx)));
- items.extend(self.imports.iter().flat_map(|x| x.clean(cx).into_iter()));
+ items.extend(self.imports.iter().flat_map(|x| x.clean(cx)));
items.extend(self.structs.iter().map(|x| x.clean(cx)));
items.extend(self.enums.iter().map(|x| x.clean(cx)));
items.extend(self.fns.iter().map(|x| x.clean(cx)));
- items.extend(self.foreigns.iter().flat_map(|x| x.clean(cx).into_iter()));
+ items.extend(self.foreigns.iter().flat_map(|x| x.clean(cx)));
items.extend(self.mods.iter().map(|x| x.clean(cx)));
items.extend(self.typedefs.iter().map(|x| x.clean(cx)));
items.extend(self.statics.iter().map(|x| x.clean(cx)));
items.extend(self.constants.iter().map(|x| x.clean(cx)));
items.extend(self.traits.iter().map(|x| x.clean(cx)));
- items.extend(self.impls.iter().flat_map(|x| x.clean(cx).into_iter()));
+ items.extend(self.impls.iter().flat_map(|x| x.clean(cx)));
items.extend(self.macros.iter().map(|x| x.clean(cx)));
items.extend(self.def_traits.iter().map(|x| x.clean(cx)));
impl TyParamBound {
fn maybe_sized(cx: &DocContext) -> TyParamBound {
use syntax::ast::TraitBoundModifier as TBM;
- let mut sized_bound = ty::BuiltinBound::BoundSized.clean(cx);
+ let mut sized_bound = ty::BoundSized.clean(cx);
if let TyParamBound::TraitBound(_, ref mut tbm) = sized_bound {
*tbm = TBM::Maybe
};
fn external_path_params(cx: &DocContext, trait_did: Option<ast::DefId>,
bindings: Vec<TypeBinding>, substs: &subst::Substs) -> PathParameters {
- use rustc::middle::ty::sty;
let lifetimes = substs.regions().get_slice(subst::TypeSpace)
.iter()
.filter_map(|v| v.clean(cx))
(Some(did), Some(ref tcx)) if tcx.lang_items.fn_trait_kind(did).is_some() => {
assert_eq!(types.len(), 1);
let inputs = match types[0].sty {
- sty::ty_tup(ref tys) => tys.iter().map(|t| t.clean(cx)).collect(),
+ ty::TyTuple(ref tys) => tys.iter().map(|t| t.clean(cx)).collect(),
_ => {
return PathParameters::AngleBracketed {
lifetimes: lifetimes,
let output = None;
// FIXME(#20299) return type comes from a projection now
// match types[1].sty {
- // sty::ty_tup(ref v) if v.is_empty() => None, // -> ()
+ // ty::TyTuple(ref v) if v.is_empty() => None, // -> ()
// _ => Some(types[1].clean(cx))
// };
PathParameters::Parenthesized {
path: path,
typarams: None,
did: did,
+ is_generic: false,
},
lifetimes: vec![]
}, ast::TraitBoundModifier::None)
// collect any late bound regions
let mut late_bounds = vec![];
for &ty_s in self.substs.types.get_slice(ParamSpace::TypeSpace) {
- use rustc::middle::ty::{Region, sty};
- if let sty::ty_tup(ref ts) = ty_s.sty {
+ if let ty::TyTuple(ref ts) = ty_s.sty {
for &ty_s in ts {
- if let sty::ty_rptr(ref reg, _) = ty_s.sty {
- if let &Region::ReLateBound(_, _) = *reg {
+ if let ty::TyRef(ref reg, _) = ty_s.sty {
+ if let &ty::Region::ReLateBound(_, _) = *reg {
debug!(" hit an ReLateBound {:?}", reg);
if let Some(lt) = reg.clean(cx) {
late_bounds.push(lt)
}
TraitBound(PolyTrait {
- trait_: ResolvedPath { path: path, typarams: None, did: self.def_id, },
+ trait_: ResolvedPath {
+ path: path,
+ typarams: None,
+ did: self.def_id,
+ is_generic: false,
+ },
lifetimes: late_bounds
}, ast::TraitBoundModifier::None)
}
}
-impl<'tcx> Clean<Vec<TyParamBound>> for ty::ParamBounds<'tcx> {
- fn clean(&self, cx: &DocContext) -> Vec<TyParamBound> {
- let mut v = Vec::new();
- for t in &self.trait_bounds {
- v.push(t.clean(cx));
- }
- for r in self.region_bounds.iter().filter_map(|r| r.clean(cx)) {
- v.push(RegionBound(r));
- }
- v
- }
-}
-
impl<'tcx> Clean<Option<Vec<TyParamBound>>> for subst::Substs<'tcx> {
fn clean(&self, cx: &DocContext) -> Option<Vec<TyParamBound>> {
let mut v = Vec::new();
pub generics: Generics,
pub self_: SelfTy,
pub unsafety: ast::Unsafety,
+ pub constness: ast::Constness,
pub decl: FnDecl,
pub abi: abi::Abi
}
Method {
generics: self.generics.clean(cx),
self_: self.explicit_self.node.clean(cx),
- unsafety: self.unsafety.clone(),
+ unsafety: self.unsafety,
+ constness: self.constness,
decl: decl,
abi: self.abi
}
pub decl: FnDecl,
pub generics: Generics,
pub unsafety: ast::Unsafety,
- pub abi: abi::Abi
+ pub constness: ast::Constness,
+ pub abi: abi::Abi,
}
impl Clean<Item> for doctree::Function {
decl: self.decl.clean(cx),
generics: self.generics.clean(cx),
unsafety: self.unsafety,
+ constness: self.constness,
abi: self.abi,
}),
}
type_params: Vec::new(),
where_predicates: Vec::new()
},
- }),
+ }, true),
ast::MacImplItem(_) => {
MacroItem(Macro {
source: self.span.to_src(cx),
ty::ByValueExplicitSelfCategory => SelfValue,
ty::ByReferenceExplicitSelfCategory(..) => {
match self.fty.sig.0.inputs[0].sty {
- ty::ty_rptr(r, mt) => {
+ ty::TyRef(r, mt) => {
SelfBorrowed(r.clean(cx), mt.mutbl.clean(cx))
}
_ => unreachable!(),
generics: generics,
self_: self_,
decl: decl,
- abi: self.fty.abi
+ abi: self.fty.abi,
+
+ // trait methods canot (currently, at least) be const
+ constness: ast::Constness::NotConst,
})
} else {
TyMethodItem(TyMethod {
generics: generics,
self_: self_,
decl: decl,
- abi: self.fty.abi
+ abi: self.fty.abi,
})
};
/// it does not preserve mutability or boxes.
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
pub enum Type {
- /// structs/enums/traits (anything that'd be an ast::TyPath)
+ /// structs/enums/traits (most that'd be an ast::TyPath)
ResolvedPath {
path: Path,
typarams: Option<Vec<TyParamBound>>,
did: ast::DefId,
+ /// true if is a `T::Name` path for associated types
+ is_generic: bool,
},
/// For parameterized types, so the consumer of the JSON don't go
/// looking for types which don't exist anywhere.
TyObjectSum(ref lhs, ref bounds) => {
let lhs_ty = lhs.clean(cx);
match lhs_ty {
- ResolvedPath { path, typarams: None, did } => {
- ResolvedPath { path: path, typarams: Some(bounds.clean(cx)), did: did}
+ ResolvedPath { path, typarams: None, did, is_generic } => {
+ ResolvedPath {
+ path: path,
+ typarams: Some(bounds.clean(cx)),
+ did: did,
+ is_generic: is_generic,
+ }
}
_ => {
lhs_ty // shouldn't happen
impl<'tcx> Clean<Type> for ty::Ty<'tcx> {
fn clean(&self, cx: &DocContext) -> Type {
match self.sty {
- ty::ty_bool => Primitive(Bool),
- ty::ty_char => Primitive(Char),
- ty::ty_int(ast::TyIs) => Primitive(Isize),
- ty::ty_int(ast::TyI8) => Primitive(I8),
- ty::ty_int(ast::TyI16) => Primitive(I16),
- ty::ty_int(ast::TyI32) => Primitive(I32),
- ty::ty_int(ast::TyI64) => Primitive(I64),
- ty::ty_uint(ast::TyUs) => Primitive(Usize),
- ty::ty_uint(ast::TyU8) => Primitive(U8),
- ty::ty_uint(ast::TyU16) => Primitive(U16),
- ty::ty_uint(ast::TyU32) => Primitive(U32),
- ty::ty_uint(ast::TyU64) => Primitive(U64),
- ty::ty_float(ast::TyF32) => Primitive(F32),
- ty::ty_float(ast::TyF64) => Primitive(F64),
- ty::ty_str => Primitive(Str),
- ty::ty_uniq(t) => {
+ ty::TyBool => Primitive(Bool),
+ ty::TyChar => Primitive(Char),
+ ty::TyInt(ast::TyIs) => Primitive(Isize),
+ ty::TyInt(ast::TyI8) => Primitive(I8),
+ ty::TyInt(ast::TyI16) => Primitive(I16),
+ ty::TyInt(ast::TyI32) => Primitive(I32),
+ ty::TyInt(ast::TyI64) => Primitive(I64),
+ ty::TyUint(ast::TyUs) => Primitive(Usize),
+ ty::TyUint(ast::TyU8) => Primitive(U8),
+ ty::TyUint(ast::TyU16) => Primitive(U16),
+ ty::TyUint(ast::TyU32) => Primitive(U32),
+ ty::TyUint(ast::TyU64) => Primitive(U64),
+ ty::TyFloat(ast::TyF32) => Primitive(F32),
+ ty::TyFloat(ast::TyF64) => Primitive(F64),
+ ty::TyStr => Primitive(Str),
+ ty::TyBox(t) => {
let box_did = cx.tcx_opt().and_then(|tcx| {
tcx.lang_items.owned_box()
});
lang_struct(cx, box_did, t, "Box", Unique)
}
- ty::ty_vec(ty, None) => Vector(box ty.clean(cx)),
- ty::ty_vec(ty, Some(i)) => FixedVector(box ty.clean(cx),
- format!("{}", i)),
- ty::ty_ptr(mt) => RawPointer(mt.mutbl.clean(cx), box mt.ty.clean(cx)),
- ty::ty_rptr(r, mt) => BorrowedRef {
+ ty::TySlice(ty) => Vector(box ty.clean(cx)),
+ ty::TyArray(ty, i) => FixedVector(box ty.clean(cx),
+ format!("{}", i)),
+ ty::TyRawPtr(mt) => RawPointer(mt.mutbl.clean(cx), box mt.ty.clean(cx)),
+ ty::TyRef(r, mt) => BorrowedRef {
lifetime: r.clean(cx),
mutability: mt.mutbl.clean(cx),
type_: box mt.ty.clean(cx),
},
- ty::ty_bare_fn(_, ref fty) => BareFunction(box BareFunctionDecl {
+ ty::TyBareFn(_, ref fty) => BareFunction(box BareFunctionDecl {
unsafety: fty.unsafety,
generics: Generics {
lifetimes: Vec::new(),
decl: (ast_util::local_def(0), &fty.sig).clean(cx),
abi: fty.abi.to_string(),
}),
- ty::ty_struct(did, substs) |
- ty::ty_enum(did, substs) => {
+ ty::TyStruct(did, substs) |
+ ty::TyEnum(did, substs) => {
let fqn = csearch::get_item_path(cx.tcx(), did);
let fqn: Vec<_> = fqn.into_iter().map(|i| i.to_string()).collect();
let kind = match self.sty {
- ty::ty_struct(..) => TypeStruct,
+ ty::TyStruct(..) => TypeStruct,
_ => TypeEnum,
};
let path = external_path(cx, &fqn.last().unwrap().to_string(),
path: path,
typarams: None,
did: did,
+ is_generic: false,
}
}
- ty::ty_trait(box ty::TyTrait { ref principal, ref bounds }) => {
+ ty::TyTrait(box ty::TraitTy { ref principal, ref bounds }) => {
let did = principal.def_id();
let fqn = csearch::get_item_path(cx.tcx(), did);
let fqn: Vec<_> = fqn.into_iter().map(|i| i.to_string()).collect();
path: path,
typarams: Some(typarams),
did: did,
+ is_generic: false,
}
}
- ty::ty_tup(ref t) => Tuple(t.clean(cx)),
+ ty::TyTuple(ref t) => Tuple(t.clean(cx)),
- ty::ty_projection(ref data) => data.clean(cx),
+ ty::TyProjection(ref data) => data.clean(cx),
- ty::ty_param(ref p) => Generic(token::get_name(p.name).to_string()),
+ ty::TyParam(ref p) => Generic(token::get_name(p.name).to_string()),
- ty::ty_closure(..) => Tuple(vec![]), // FIXME(pcwalton)
+ ty::TyClosure(..) => Tuple(vec![]), // FIXME(pcwalton)
- ty::ty_infer(..) => panic!("ty_infer"),
- ty::ty_err => panic!("ty_err"),
+ ty::TyInfer(..) => panic!("TyInfer"),
+ ty::TyError => panic!("TyError"),
}
}
}
StructVariant(VariantStruct {
struct_type: doctree::Plain,
fields_stripped: false,
- fields: s.iter().zip(self.args.iter()).map(|(name, ty)| {
+ fields: s.iter().zip(&self.args).map(|(name, ty)| {
Item {
source: Span::empty(),
name: Some(name.clean(cx)),
inner: TypedefItem(Typedef {
type_: self.ty.clean(cx),
generics: self.gen.clean(cx),
- }),
+ }, false),
}
}
}
for item in items {
let target = match item.inner {
- TypedefItem(ref t) => &t.type_,
+ TypedefItem(ref t, true) => &t.type_,
_ => continue,
};
let primitive = match *target {
for path in list {
match inline::try_inline(cx, path.node.id(), None) {
Some(items) => {
- ret.extend(items.into_iter());
+ ret.extend(items);
}
None => {
remaining.push(path.clean(cx));
generics: generics.clean(cx),
unsafety: ast::Unsafety::Unsafe,
abi: abi::Rust,
+ constness: ast::Constness::NotConst,
})
}
ast::ForeignItemStatic(ref ty, mutbl) => {
ast::LitStr(ref st, _) => st.to_string(),
ast::LitBinary(ref data) => format!("{:?}", data),
ast::LitByte(b) => {
- let mut res = String::from_str("b'");
+ let mut res = String::from("b'");
for c in (b as char).escape_default() {
res.push(c);
}
None => panic!("unresolved id not in defmap")
};
- match def {
- def::DefSelfTy(..) if path.segments.len() == 1 => {
- return Generic(token::get_name(special_idents::type_self.name).to_string());
- }
+ let is_generic = match def {
def::DefPrimTy(p) => match p {
ast::TyStr => return Primitive(Str),
ast::TyBool => return Primitive(Bool),
ast::TyFloat(ast::TyF32) => return Primitive(F32),
ast::TyFloat(ast::TyF64) => return Primitive(F64),
},
- def::DefTyParam(_, _, _, n) => {
- return Generic(token::get_name(n).to_string())
+ def::DefSelfTy(..) if path.segments.len() == 1 => {
+ return Generic(token::get_name(special_idents::type_self.name).to_string());
}
- _ => {}
+ def::DefSelfTy(..) | def::DefTyParam(..) => true,
+ _ => false,
};
let did = register_def(&*cx, def);
- ResolvedPath { path: path, typarams: None, did: did }
+ ResolvedPath { path: path, typarams: None, did: did, is_generic: is_generic }
}
fn register_def(cx: &DocContext, def: def::Def) -> ast::DefId {
}
}
+impl<'a> Clean<Stability> for &'a attr::Stability {
+ fn clean(&self, _: &DocContext) -> Stability {
+ Stability {
+ level: self.level,
+ feature: self.feature.to_string(),
+ since: self.since.as_ref().map_or("".to_string(),
+ |interned| interned.to_string()),
+ deprecated_since: self.deprecated_since.as_ref().map_or("".to_string(),
+ |istr| istr.to_string()),
+ reason: self.reason.as_ref().map_or("".to_string(),
+ |interned| interned.to_string()),
+ }
+ }
+}
+
impl<'tcx> Clean<Item> for ty::AssociatedConst<'tcx> {
fn clean(&self, cx: &DocContext) -> Item {
Item {
}
}
-impl Clean<Item> for ty::AssociatedType {
+impl<'tcx> Clean<Item> for ty::AssociatedType<'tcx> {
fn clean(&self, cx: &DocContext) -> Item {
- // When loading a cross-crate associated type, the bounds for this type
- // are actually located on the trait/impl itself, so we need to load
- // all of the generics from there and then look for bounds that are
- // applied to this associated type in question.
- let predicates = ty::lookup_predicates(cx.tcx(), self.container.id());
- let generics = match self.container {
- ty::TraitContainer(did) => {
- let def = ty::lookup_trait_def(cx.tcx(), did);
- (&def.generics, &predicates, subst::TypeSpace).clean(cx)
- }
- ty::ImplContainer(did) => {
- let ty = ty::lookup_item_type(cx.tcx(), did);
- (&ty.generics, &predicates, subst::TypeSpace).clean(cx)
- }
- };
let my_name = self.name.clean(cx);
- let mut bounds = generics.where_predicates.iter().filter_map(|pred| {
- let (name, self_type, trait_, bounds) = match *pred {
- WherePredicate::BoundPredicate {
- ty: QPath { ref name, ref self_type, ref trait_ },
- ref bounds
- } => (name, self_type, trait_, bounds),
- _ => return None,
- };
- if *name != my_name { return None }
- match **trait_ {
- ResolvedPath { did, .. } if did == self.container.id() => {}
- _ => return None,
- }
- match **self_type {
- Generic(ref s) if *s == "Self" => {}
- _ => return None,
- }
- Some(bounds)
- }).flat_map(|i| i.iter().cloned()).collect::<Vec<_>>();
+
+ let mut bounds = if let ty::TraitContainer(did) = self.container {
+ // When loading a cross-crate associated type, the bounds for this type
+ // are actually located on the trait/impl itself, so we need to load
+ // all of the generics from there and then look for bounds that are
+ // applied to this associated type in question.
+ let def = ty::lookup_trait_def(cx.tcx(), did);
+ let predicates = ty::lookup_predicates(cx.tcx(), did);
+ let generics = (&def.generics, &predicates, subst::TypeSpace).clean(cx);
+ generics.where_predicates.iter().filter_map(|pred| {
+ let (name, self_type, trait_, bounds) = match *pred {
+ WherePredicate::BoundPredicate {
+ ty: QPath { ref name, ref self_type, ref trait_ },
+ ref bounds
+ } => (name, self_type, trait_, bounds),
+ _ => return None,
+ };
+ if *name != my_name { return None }
+ match **trait_ {
+ ResolvedPath { did, .. } if did == self.container.id() => {}
+ _ => return None,
+ }
+ match **self_type {
+ Generic(ref s) if *s == "Self" => {}
+ _ => return None,
+ }
+ Some(bounds)
+ }).flat_map(|i| i.iter().cloned()).collect::<Vec<_>>()
+ } else {
+ vec![]
+ };
// Our Sized/?Sized bound didn't get handled when creating the generics
// because we didn't actually get our whole set of bounds until just now
source: DUMMY_SP.clean(cx),
name: Some(self.name.clean(cx)),
attrs: inline::load_attrs(cx, cx.tcx(), self.def_id),
- inner: AssociatedTypeItem(bounds, None),
+ inner: AssociatedTypeItem(bounds, self.ty.clean(cx)),
visibility: self.vis.clean(cx),
def_id: self.def_id,
stability: stability::lookup(cx.tcx(), self.def_id).clean(cx),
}
}],
},
+ is_generic: false,
}
}
}
pub fn ty_params(mut params: Vec<clean::TyParam>) -> Vec<clean::TyParam> {
- for param in params.iter_mut() {
+ for param in &mut params {
param.bounds = ty_bounds(mem::replace(&mut param.bounds, Vec::new()));
}
return params;
} if *s == "Self" => Some(bounds),
_ => None,
}
- }).flat_map(|bounds| bounds.iter()).any(|bound| {
+ }).flat_map(|bounds| bounds).any(|bound| {
let poly_trait = match *bound {
clean::TraitBound(ref t, _) => t,
_ => return false,
use rustc_lint;
use rustc_driver::driver;
use rustc::session::{self, config};
-use rustc::session::config::UnstableFeatures;
use rustc::middle::{privacy, ty};
+use rustc::ast_map;
use rustc::lint;
use rustc_trans::back::link;
use rustc_resolve as resolve;
-use syntax::{ast, ast_map, codemap, diagnostic};
+use syntax::{ast, codemap, diagnostic};
+use syntax::feature_gate::UnstableFeatures;
use std::cell::{RefCell, Cell};
use std::collections::{HashMap, HashSet};
pub use rustc::session::search_paths::SearchPaths;
/// Are we generating documentation (`Typed`) or tests (`NotTyped`)?
-pub enum MaybeTyped<'tcx> {
- Typed(ty::ctxt<'tcx>),
+pub enum MaybeTyped<'a, 'tcx: 'a> {
+ Typed(&'a ty::ctxt<'tcx>),
NotTyped(session::Session)
}
pub type ExternalPaths = RefCell<Option<HashMap<ast::DefId,
(Vec<String>, clean::TypeKind)>>>;
-pub struct DocContext<'tcx> {
+pub struct DocContext<'a, 'tcx: 'a> {
pub krate: &'tcx ast::Crate,
- pub maybe_typed: MaybeTyped<'tcx>,
+ pub maybe_typed: MaybeTyped<'a, 'tcx>,
pub input: Input,
pub external_paths: ExternalPaths,
pub external_traits: RefCell<Option<HashMap<ast::DefId, clean::Trait>>>,
pub deref_trait_did: Cell<Option<ast::DefId>>,
}
-impl<'tcx> DocContext<'tcx> {
+impl<'b, 'tcx> DocContext<'b, 'tcx> {
pub fn sess<'a>(&'a self) -> &'a session::Session {
match self.maybe_typed {
- Typed(ref tcx) => &tcx.sess,
+ Typed(tcx) => &tcx.sess,
NotTyped(ref sess) => sess
}
}
pub fn tcx_opt<'a>(&'a self) -> Option<&'a ty::ctxt<'tcx>> {
match self.maybe_typed {
- Typed(ref tcx) => Some(tcx),
+ Typed(tcx) => Some(tcx),
NotTyped(_) => None
}
}
target_triple: triple.unwrap_or(config::host_triple().to_string()),
cfg: config::parse_cfgspecs(cfgs),
// Ensure that rustdoc works even if rustc is feature-staged
- unstable_features: UnstableFeatures::Default,
+ unstable_features: UnstableFeatures::Allow,
..config::basic_options().clone()
};
let codemap = codemap::CodeMap::new();
- let diagnostic_handler = diagnostic::default_handler(diagnostic::Auto, None, true);
+ let diagnostic_handler = diagnostic::Handler::new(diagnostic::Auto, None, true);
let span_diagnostic_handler =
- diagnostic::mk_span_handler(diagnostic_handler, codemap);
+ diagnostic::SpanHandler::new(diagnostic_handler, codemap);
let sess = session::build_session_(sessopts, cpath,
span_diagnostic_handler);
let arenas = ty::CtxtArenas::new();
let ast_map = driver::assign_node_ids_and_map(&sess, &mut forest);
- let ty::CrateAnalysis {
- exported_items, public_items, ty_cx, ..
- } = driver::phase_3_run_analysis_passes(sess,
- ast_map,
- &arenas,
- name,
- resolve::MakeGlobMap::No);
-
- let ctxt = DocContext {
- krate: ty_cx.map.krate(),
- maybe_typed: Typed(ty_cx),
- input: input,
- external_traits: RefCell::new(Some(HashMap::new())),
- external_typarams: RefCell::new(Some(HashMap::new())),
- external_paths: RefCell::new(Some(HashMap::new())),
- inlined: RefCell::new(Some(HashSet::new())),
- populated_crate_impls: RefCell::new(HashSet::new()),
- deref_trait_did: Cell::new(None),
- };
- debug!("crate: {:?}", ctxt.krate);
-
- let mut analysis = CrateAnalysis {
- exported_items: exported_items,
- public_items: public_items,
- external_paths: RefCell::new(None),
- external_typarams: RefCell::new(None),
- inlined: RefCell::new(None),
- deref_trait_did: None,
- };
-
- let krate = {
- let mut v = RustdocVisitor::new(&ctxt, Some(&analysis));
- v.visit(ctxt.krate);
- v.clean(&ctxt)
- };
-
- let external_paths = ctxt.external_paths.borrow_mut().take();
- *analysis.external_paths.borrow_mut() = external_paths;
- let map = ctxt.external_typarams.borrow_mut().take();
- *analysis.external_typarams.borrow_mut() = map;
- let map = ctxt.inlined.borrow_mut().take();
- *analysis.inlined.borrow_mut() = map;
- analysis.deref_trait_did = ctxt.deref_trait_did.get();
- (krate, analysis)
+ driver::phase_3_run_analysis_passes(sess,
+ ast_map,
+ &arenas,
+ name,
+ resolve::MakeGlobMap::No,
+ |tcx, analysis| {
+ let ty::CrateAnalysis { exported_items, public_items, .. } = analysis;
+
+ let ctxt = DocContext {
+ krate: tcx.map.krate(),
+ maybe_typed: Typed(tcx),
+ input: input,
+ external_traits: RefCell::new(Some(HashMap::new())),
+ external_typarams: RefCell::new(Some(HashMap::new())),
+ external_paths: RefCell::new(Some(HashMap::new())),
+ inlined: RefCell::new(Some(HashSet::new())),
+ populated_crate_impls: RefCell::new(HashSet::new()),
+ deref_trait_did: Cell::new(None),
+ };
+ debug!("crate: {:?}", ctxt.krate);
+
+ let mut analysis = CrateAnalysis {
+ exported_items: exported_items,
+ public_items: public_items,
+ external_paths: RefCell::new(None),
+ external_typarams: RefCell::new(None),
+ inlined: RefCell::new(None),
+ deref_trait_did: None,
+ };
+
+ let krate = {
+ let mut v = RustdocVisitor::new(&ctxt, Some(&analysis));
+ v.visit(ctxt.krate);
+ v.clean(&ctxt)
+ };
+
+ let external_paths = ctxt.external_paths.borrow_mut().take();
+ *analysis.external_paths.borrow_mut() = external_paths;
+ let map = ctxt.external_typarams.borrow_mut().take();
+ *analysis.external_typarams.borrow_mut() = map;
+ let map = ctxt.inlined.borrow_mut().take();
+ *analysis.inlined.borrow_mut() = map;
+ analysis.deref_trait_did = ctxt.deref_trait_did.get();
+ (krate, analysis)
+ }).1
}
pub vis: ast::Visibility,
pub stab: Option<attr::Stability>,
pub unsafety: ast::Unsafety,
+ pub constness: ast::Constness,
pub whence: Span,
pub generics: ast::Generics,
pub abi: abi::Abi,
/// space after it.
#[derive(Copy, Clone)]
pub struct UnsafetySpace(pub ast::Unsafety);
+/// Similarly to VisSpace, this structure is used to render a function constness
+/// with a space after it.
+#[derive(Copy, Clone)]
+pub struct ConstnessSpace(pub ast::Constness);
/// Wrapper struct for properly emitting a method declaration.
pub struct Method<'a>(pub &'a clean::SelfTy, pub &'a clean::FnDecl);
/// Similar to VisSpace, but used for mutability
}
}
+impl ConstnessSpace {
+ pub fn get(&self) -> ast::Constness {
+ let ConstnessSpace(v) = *self; v
+ }
+}
+
impl<'a, T: fmt::Display> fmt::Display for CommaSep<'a, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for (i, item) in self.0.iter().enumerate() {
if print_all {
let amt = path.segments.len() - 1;
match rel_root {
- Some(root) => {
- let mut root = String::from_str(&root);
+ Some(mut root) => {
for seg in &path.segments[..amt] {
if "super" == seg.name || "self" == seg.name {
try!(write!(w, "{}::", seg.name));
clean::Generic(ref name) => {
f.write_str(name)
}
- clean::ResolvedPath{ did, ref typarams, ref path } => {
- // Paths like Self::Output should be rendered with all segments
- try!(resolved_path(f, did, path, path.segments[0].name == "Self"));
+ clean::ResolvedPath{ did, ref typarams, ref path, is_generic } => {
+ // Paths like T::Output and Self::Output should be rendered with all segments
+ try!(resolved_path(f, did, path, is_generic));
tybounds(f, typarams)
}
clean::Infer => write!(f, "_"),
}
}
+impl fmt::Display for ConstnessSpace {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self.get() {
+ ast::Constness::Const => write!(f, "const "),
+ ast::Constness::NotConst => Ok(())
+ }
+ }
+}
+
impl fmt::Display for clean::Import {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
/// Highlights some source code, returning the HTML output.
pub fn highlight(src: &str, class: Option<&str>, id: Option<&str>) -> String {
debug!("highlighting: ================\n{}\n==============", src);
- let sess = parse::new_parse_sess();
- let fm = parse::string_to_filemap(&sess,
- src.to_string(),
- "<stdin>".to_string());
+ let sess = parse::ParseSess::new();
+ let fm = sess.codemap().new_filemap("<stdin>".to_string(), src.to_string());
let mut out = Vec::new();
doit(&sess,
loop {
let next = lexer.next_token();
- let snip = |sp| sess.span_diagnostic.cm.span_to_snippet(sp).unwrap();
+ let snip = |sp| sess.codemap().span_to_snippet(sp).unwrap();
if next.tok == token::Eof { break }
// as mentioned above, use the original source code instead of
// stringifying this token
- let snip = sess.span_diagnostic.cm.span_to_snippet(next.sp).unwrap();
+ let snip = sess.codemap().span_to_snippet(next.sp).unwrap();
if klass == "" {
try!(write!(out, "{}", Escape(&snip)));
} else {
s.push_str(&format!("<span class='rusttest'>{}</span>", Escape(&test)));
});
s.push_str(&highlight::highlight(&text,
- None,
- Some("rust-example-rendered")));
+ Some("rust-example-rendered"),
+ None));
let output = CString::new(s).unwrap();
hoedown_buffer_puts(ob, output.as_ptr());
})
use externalfiles::ExternalHtml;
-use serialize::json;
-use serialize::json::ToJson;
-use syntax::abi;
-use syntax::ast;
-use syntax::ast_util;
-use syntax::attr;
+use serialize::json::{self, ToJson};
+use syntax::{abi, ast, ast_util, attr};
use rustc::util::nodemap::NodeSet;
-use clean;
+use clean::{self, SelfTy};
use doctree;
use fold::DocFolder;
use html::escape::Escape;
+use html::format::{ConstnessSpace};
use html::format::{TyParamBounds, WhereClause, href, AbiSpace};
use html::format::{VisSpace, Method, UnsafetySpace, MutableSpace};
-use html::highlight;
use html::item_type::ItemType;
-use html::layout;
-use html::markdown::Markdown;
-use html::markdown;
+use html::markdown::{self, Markdown};
+use html::{highlight, layout};
/// A pair of name and its optional document.
pub type NameDoc = (String, Option<String>);
let did = ast_util::local_def(pid);
match paths.get(&did) {
Some(&(ref fqp, _)) => {
+ // Needed to determine `self` type.
+ let parent_basename = Some(fqp[fqp.len() - 1].clone());
search_index.push(IndexItem {
ty: shortty(item),
name: item.name.clone().unwrap(),
path: fqp[..fqp.len() - 1].connect("::"),
desc: shorter(item.doc_value()),
parent: Some(did),
- search_type: None,
+ search_type: get_index_search_type(&item, parent_basename),
});
},
None => {}
// Reduce `NodeId` in paths into smaller sequential numbers,
// and prune the paths that do not appear in the index.
- for item in &*search_index {
+ for item in search_index.iter() {
match item.parent {
Some(nodeid) => {
if !nodeid_to_pathid.contains_key(&nodeid) {
// Create the intermediate directories
let mut cur = self.dst.clone();
- let mut root_path = String::from_str("../../");
+ let mut root_path = String::from("../../");
clean_srcpath(&self.cx.src_root, &p, false, |component| {
cur.push(component);
mkdir(&cur).unwrap();
clean::StructItem(ref s) => self.generics(&s.generics),
clean::EnumItem(ref e) => self.generics(&e.generics),
clean::FunctionItem(ref f) => self.generics(&f.generics),
- clean::TypedefItem(ref t) => self.generics(&t.generics),
+ clean::TypedefItem(ref t, _) => self.generics(&t.generics),
clean::TraitItem(ref t) => self.generics(&t.generics),
clean::ImplItem(ref i) => self.generics(&i.generics),
clean::TyMethodItem(ref i) => self.generics(&i.generics),
((Some(*last), path), true)
}
}
+ clean::TypedefItem(_, true) => {
+ // skip associated types in impls
+ ((None, None), false)
+ }
_ => ((None, Some(&*self.stack)), false)
};
let hidden_field = match item.inner {
clean::TraitItem(ref t) => item_trait(fmt, self.cx, self.item, t),
clean::StructItem(ref s) => item_struct(fmt, self.item, s),
clean::EnumItem(ref e) => item_enum(fmt, self.item, e),
- clean::TypedefItem(ref t) => item_typedef(fmt, self.item, t),
+ clean::TypedefItem(ref t, _) => item_typedef(fmt, self.item, t),
clean::MacroItem(ref m) => item_macro(fmt, self.item, m),
clean::PrimitiveItem(ref p) => item_primitive(fmt, self.item, p),
clean::StaticItem(ref i) | clean::ForeignStaticItem(ref i) =>
fn item_function(w: &mut fmt::Formatter, it: &clean::Item,
f: &clean::Function) -> fmt::Result {
- try!(write!(w, "<pre class='rust fn'>{vis}{unsafety}{abi}fn \
+ try!(write!(w, "<pre class='rust fn'>{vis}{unsafety}{abi}{constness}fn \
{name}{generics}{decl}{where_clause}</pre>",
vis = VisSpace(it.visibility),
unsafety = UnsafetySpace(f.unsafety),
abi = AbiSpace(f.abi),
+ constness = ConstnessSpace(f.constness),
name = it.name.as_ref().unwrap(),
generics = f.generics,
where_clause = WhereClause(&f.generics),
fn render_assoc_item(w: &mut fmt::Formatter, meth: &clean::Item,
link: AssocItemLink) -> fmt::Result {
- fn method(w: &mut fmt::Formatter, it: &clean::Item,
- unsafety: ast::Unsafety, abi: abi::Abi,
- g: &clean::Generics, selfty: &clean::SelfTy,
- d: &clean::FnDecl, link: AssocItemLink) -> fmt::Result {
+ fn method(w: &mut fmt::Formatter,
+ it: &clean::Item,
+ unsafety: ast::Unsafety,
+ constness: ast::Constness,
+ abi: abi::Abi,
+ g: &clean::Generics,
+ selfty: &clean::SelfTy,
+ d: &clean::FnDecl,
+ link: AssocItemLink)
+ -> fmt::Result {
use syntax::abi::Abi;
let name = it.name.as_ref().unwrap();
href(did).map(|p| format!("{}{}", p.0, anchor)).unwrap_or(anchor)
}
};
- write!(w, "{}{}fn <a href='{href}' class='fnname'>{name}</a>\
+ write!(w, "{}{}{}fn <a href='{href}' class='fnname'>{name}</a>\
{generics}{decl}{where_clause}",
- match unsafety {
- ast::Unsafety::Unsafe => "unsafe ",
- _ => "",
- },
+ UnsafetySpace(unsafety),
+ ConstnessSpace(constness),
match abi {
Abi::Rust => String::new(),
a => format!("extern {} ", a.to_string())
}
match meth.inner {
clean::TyMethodItem(ref m) => {
- method(w, meth, m.unsafety, m.abi, &m.generics, &m.self_, &m.decl,
- link)
+ method(w, meth, m.unsafety, ast::Constness::NotConst,
+ m.abi, &m.generics, &m.self_, &m.decl, link)
}
clean::MethodItem(ref m) => {
- method(w, meth, m.unsafety, m.abi, &m.generics, &m.self_, &m.decl,
+ method(w, meth, m.unsafety, m.constness,
+ m.abi, &m.generics, &m.self_, &m.decl,
link)
}
clean::AssociatedConstItem(ref ty, ref default) => {
}
try!(write!(w, "<h2 id='implementations'>Trait \
Implementations</h2>"));
- let (derived, manual): (Vec<_>, _) = traits.iter().partition(|i| {
+ let (derived, manual): (Vec<_>, Vec<&Impl>) = traits.iter().partition(|i| {
i.impl_.derived
});
for i in &manual {
let deref_type = impl_.impl_.trait_.as_ref().unwrap();
let target = impl_.impl_.items.iter().filter_map(|item| {
match item.inner {
- clean::TypedefItem(ref t) => Some(&t.type_),
+ clean::TypedefItem(ref t, true) => Some(&t.type_),
_ => None,
}
- }).next().unwrap();
+ }).next().expect("Expected associated type binding");
let what = AssocItemRender::DerefFor { trait_: deref_type, type_: target };
match *target {
clean::ResolvedPath { did, .. } => render_assoc_items(w, did, what),
}
}
+// Render_header is false when we are rendering a `Deref` impl and true
+// otherwise. If render_header is false, we will avoid rendering static
+// methods, since they are not accessible for the type implementing `Deref`
fn render_impl(w: &mut fmt::Formatter, i: &Impl, link: AssocItemLink,
render_header: bool) -> fmt::Result {
if render_header {
}
fn doctraititem(w: &mut fmt::Formatter, item: &clean::Item,
- link: AssocItemLink) -> fmt::Result {
+ link: AssocItemLink, render_static: bool) -> fmt::Result {
match item.inner {
clean::MethodItem(..) | clean::TyMethodItem(..) => {
- try!(write!(w, "<h4 id='method.{}' class='{}'><code>",
- *item.name.as_ref().unwrap(),
- shortty(item)));
+ // Only render when the method is not static or we allow static methods
+ if !is_static_method(item) || render_static {
+ try!(write!(w, "<h4 id='method.{}' class='{}'><code>",
+ *item.name.as_ref().unwrap(),
+ shortty(item)));
try!(render_assoc_item(w, item, link));
- try!(write!(w, "</code></h4>\n"));
+ try!(write!(w, "</code></h4>\n"));
+ }
}
- clean::TypedefItem(ref tydef) => {
+ clean::TypedefItem(ref tydef, _) => {
let name = item.name.as_ref().unwrap();
try!(write!(w, "<h4 id='assoc_type.{}' class='{}'><code>",
*name,
}
_ => panic!("can't make docs for trait item with name {:?}", item.name)
}
- if let AssocItemLink::Anchor = link {
- document(w, item)
+
+ return if let AssocItemLink::Anchor = link {
+ if is_static_method(item) && !render_static {
+ Ok(())
+ } else {
+ document(w, item)
+ }
} else {
Ok(())
+ };
+
+ fn is_static_method(item: &clean::Item) -> bool {
+ match item.inner {
+ clean::MethodItem(ref method) => method.self_ == SelfTy::SelfStatic,
+ clean::TyMethodItem(ref method) => method.self_ == SelfTy::SelfStatic,
+ _ => false
+ }
}
}
try!(write!(w, "<div class='impl-items'>"));
- for trait_item in i.impl_.items.iter() {
- try!(doctraititem(w, trait_item, link));
+ for trait_item in &i.impl_.items {
+ try!(doctraititem(w, trait_item, link, render_header));
}
fn render_default_items(w: &mut fmt::Formatter,
did: ast::DefId,
t: &clean::Trait,
- i: &clean::Impl) -> fmt::Result {
+ i: &clean::Impl,
+ render_static: bool) -> fmt::Result {
for trait_item in &t.items {
let n = trait_item.name.clone();
match i.items.iter().find(|m| { m.name == n }) {
None => {}
}
- try!(doctraititem(w, trait_item, AssocItemLink::GotoSource(did)));
+ try!(doctraititem(w, trait_item, AssocItemLink::GotoSource(did), render_static));
}
Ok(())
}
// for them work.
if let Some(clean::ResolvedPath { did, .. }) = i.impl_.trait_ {
if let Some(t) = cache().traits.get(&did) {
- try!(render_default_items(w, did, t, &i.impl_));
+ try!(render_default_items(w, did, t, &i.impl_, render_header));
+
}
}
try!(write!(w, "</div>"));
fn item_typedef(w: &mut fmt::Formatter, it: &clean::Item,
t: &clean::Typedef) -> fmt::Result {
- try!(write!(w, "<pre class='rust typedef'>type {}{} = {};</pre>",
+ try!(write!(w, "<pre class='rust typedef'>type {}{}{where_clause} = {type_};</pre>",
it.name.as_ref().unwrap(),
t.generics,
- t.type_));
+ where_clause = WhereClause(&t.generics),
+ type_ = t.type_));
document(w, it)
}
font-size: 1em;
position: relative;
}
-/* Shift "where ..." part of method definition down a line */
-.content .method .where { display: block; }
+/* Shift "where ..." part of method or fn definition down a line */
+.content .method .where, .content .fn .where { display: block; }
/* Bit of whitespace to indent it */
-.content .method .where::before { content: ' '; }
+.content .method .where::before, .content .fn .where::before { content: ' '; }
.content .methods > div { margin-left: 40px; }
.content .impl-items .docblock, .content .impl-items .stability {
margin-left: 40px;
}
-.content .impl-items .method, .content .impl-items .type {
+.content .impl-items .method, .content .impl-items > .type {
margin-left: 20px;
}
.content .search-results td:first-child { padding-right: 0; }
.content .search-results td:first-child a { padding-right: 10px; }
+tr.result span.primitive::after { content: ' (primitive type)'; font-style: italic; }
+
#help {
background: #e9e9e9;
border-radius: 4px;
(function() {
"use strict";
- var resizeTimeout, interval;
// This mapping table should match the discriminants of
// `rustdoc::html::item_type::ItemType` type in Rust.
"constant",
"associatedconstant"];
+ // used for special search precedence
+ var TY_PRIMITIVE = itemTypes.indexOf("primitive");
+
$('.js-only').removeClass('js-only');
function getQueryStringParams() {
if ($('#' + from).length === 0) {
return;
}
- if (ev === null) $('#' + from)[0].scrollIntoView();
+ if (ev === null) { $('#' + from)[0].scrollIntoView(); };
$('.line-numbers span').removeClass('line-highlighted');
for (i = from; i <= to; ++i) {
$('#' + i).addClass('line-highlighted');
highlightSourceLines(null);
$(window).on('hashchange', highlightSourceLines);
- $(document).on('keyup', function(e) {
+ $(document).on('keyup', function handleKeyboardShortcut(e) {
if (document.activeElement.tagName === 'INPUT') {
return;
}
return function(s1, s2) {
if (s1 === s2) {
return 0;
- } else {
- var s1_len = s1.length, s2_len = s2.length;
- if (s1_len && s2_len) {
- var i1 = 0, i2 = 0, a, b, c, c2, row = row2;
- while (i1 < s1_len)
- row[i1] = ++i1;
- while (i2 < s2_len) {
- c2 = s2.charCodeAt(i2);
- a = i2;
- ++i2;
- b = i2;
- for (i1 = 0; i1 < s1_len; ++i1) {
- c = a + (s1.charCodeAt(i1) !== c2 ? 1 : 0);
- a = row[i1];
- b = b < a ? (b < c ? b + 1 : c) : (a < c ? a + 1 : c);
- row[i1] = b;
- }
+ }
+ var s1_len = s1.length, s2_len = s2.length;
+ if (s1_len && s2_len) {
+ var i1 = 0, i2 = 0, a, b, c, c2, row = row2;
+ while (i1 < s1_len) {
+ row[i1] = ++i1;
+ }
+ while (i2 < s2_len) {
+ c2 = s2.charCodeAt(i2);
+ a = i2;
+ ++i2;
+ b = i2;
+ for (i1 = 0; i1 < s1_len; ++i1) {
+ c = a + (s1.charCodeAt(i1) !== c2 ? 1 : 0);
+ a = row[i1];
+ b = b < a ? (b < c ? b + 1 : c) : (a < c ? a + 1 : c);
+ row[i1] = b;
}
- return b;
- } else {
- return s1_len + s2_len;
}
+ return b;
}
+ return s1_len + s2_len;
};
})();
results = [],
split = valLower.split("::");
- //remove empty keywords
+ // remove empty keywords
for (var j = 0; j < split.length; ++j) {
split[j].toLowerCase();
if (split[j] === "") {
return [];
}
- results.sort(function(aaa, bbb) {
+ results.sort(function sortResults(aaa, bbb) {
var a, b;
// Sort by non levenshtein results and then levenshtein results by the distance
// (less changes required to match means higher rankings)
a = (aaa.lev);
b = (bbb.lev);
- if (a !== b) return a - b;
+ if (a !== b) { return a - b; }
// sort by crate (non-current crate goes later)
a = (aaa.item.crate !== window.currentCrate);
b = (bbb.item.crate !== window.currentCrate);
- if (a !== b) return a - b;
+ if (a !== b) { return a - b; }
// sort by exact match (mismatch goes later)
a = (aaa.word !== valLower);
b = (bbb.word !== valLower);
- if (a !== b) return a - b;
+ if (a !== b) { return a - b; }
// sort by item name length (longer goes later)
a = aaa.word.length;
b = bbb.word.length;
- if (a !== b) return a - b;
+ if (a !== b) { return a - b; }
// sort by item name (lexicographically larger goes later)
a = aaa.word;
b = bbb.word;
- if (a !== b) return (a > b ? +1 : -1);
+ if (a !== b) { return (a > b ? +1 : -1); }
// sort by index of keyword in item name (no literal occurrence goes later)
a = (aaa.index < 0);
b = (bbb.index < 0);
- if (a !== b) return a - b;
+ if (a !== b) { return a - b; }
// (later literal occurrence, if any, goes later)
a = aaa.index;
b = bbb.index;
- if (a !== b) return a - b;
+ if (a !== b) { return a - b; }
+
+ // special precedence for primitive pages
+ if ((aaa.item.ty === TY_PRIMITIVE) && (bbb.item.ty !== TY_PRIMITIVE)) {
+ return -1;
+ }
// sort by description (no description goes later)
a = (aaa.item.desc === '');
b = (bbb.item.desc === '');
- if (a !== b) return a - b;
+ if (a !== b) { return a - b; }
// sort by type (later occurrence in `itemTypes` goes later)
a = aaa.item.ty;
b = bbb.item.ty;
- if (a !== b) return a - b;
+ if (a !== b) { return a - b; }
// sort by path (lexicographically larger goes later)
a = aaa.item.path;
b = bbb.item.path;
- if (a !== b) return (a > b ? +1 : -1);
+ if (a !== b) { return (a > b ? +1 : -1); }
// que sera, sera
return 0;
* @return {[boolean]} [Whether the result is valid or not]
*/
function validateResult(name, path, keys, parent) {
- for (var i=0; i < keys.length; ++i) {
+ for (var i = 0; i < keys.length; ++i) {
// each check is for validation so we negate the conditions and invalidate
if (!(
// check for an exact name match
raw: raw,
query: query,
type: type,
- id: query + type,
+ id: query + type
};
}
$results.on('click', function() {
var dst = $(this).find('a')[0];
- if (window.location.pathname == dst.pathname) {
+ if (window.location.pathname === dst.pathname) {
$('#search').addClass('hidden');
$('#main').removeClass('hidden');
document.location.href = dst.href;
return;
}
+ // Update document title to maintain a meaningful browser history
+ $(document).prop("title", "Results for " + query.query + " - Rust");
+
// Because searching is incremental by character, only the most
// recent search query is added to the browser history.
if (browserSupportsHistoryApi()) {
function itemTypeFromName(typename) {
for (var i = 0; i < itemTypes.length; ++i) {
- if (itemTypes[i] === typename) return i;
+ if (itemTypes[i] === typename) { return i; }
}
return -1;
}
searchIndex = [];
var searchWords = [];
for (var crate in rawSearchIndex) {
- if (!rawSearchIndex.hasOwnProperty(crate)) { continue }
+ if (!rawSearchIndex.hasOwnProperty(crate)) { continue; }
// an array of [(Number) item type,
// (String) name,
}
function plainSummaryLine(markdown) {
- var str = markdown.replace(/\n/g, ' ')
- str = str.replace(/'/g, "\'")
- str = str.replace(/^#+? (.+?)/, "$1")
- str = str.replace(/\[(.*?)\]\(.*?\)/g, "$1")
- str = str.replace(/\[(.*?)\]\[.*?\]/g, "$1")
- return str;
+ markdown.replace(/\n/g, ' ')
+ .replace(/'/g, "\'")
+ .replace(/^#+? (.+?)/, "$1")
+ .replace(/\[(.*?)\]\(.*?\)/g, "$1")
+ .replace(/\[(.*?)\]\[.*?\]/g, "$1");
}
index = buildIndex(rawSearchIndex);
startSearch();
// Draw a convenient sidebar of known crates if we have a listing
- if (rootPath == '../') {
+ if (rootPath === '../') {
var sidebar = $('.sidebar');
var div = $('<div>').attr('class', 'block crate');
div.append($('<h2>').text('Crates'));
var crates = [];
for (var crate in rawSearchIndex) {
- if (!rawSearchIndex.hasOwnProperty(crate)) { continue }
+ if (!rawSearchIndex.hasOwnProperty(crate)) { continue; }
crates.push(crate);
}
crates.sort();
for (var i = 0; i < crates.length; ++i) {
var klass = 'crate';
- if (crates[i] == window.currentCrate) {
+ if (crates[i] === window.currentCrate) {
klass += ' current';
}
if (rawSearchIndex[crates[i]].items[0]) {
function block(shortty, longty) {
var filtered = items[shortty];
- if (!filtered) return;
+ if (!filtered) { return; }
var div = $('<div>').attr('class', 'block ' + shortty);
div.append($('<h2>').text(longty));
var desc = item[1]; // can be null
var klass = shortty;
- if (name === current.name && shortty == current.ty) {
+ if (name === current.name && shortty === current.ty) {
klass += ' current';
}
var path;
var list = $('#implementors-list');
var libs = Object.getOwnPropertyNames(imp);
for (var i = 0; i < libs.length; ++i) {
- if (libs[i] == currentCrate) continue;
+ if (libs[i] === currentCrate) { continue; }
var structs = imp[libs[i]];
for (var j = 0; j < structs.length; ++j) {
var code = $('<code>').append(structs[j]);
if (sectionIsCollapsed) {
// button will expand the section
return "+";
- } else {
- // button will collapse the section
- // note that this text is also set in the HTML template in render.rs
- return "\u2212"; // "\u2212" is '−' minus sign
}
+ // button will collapse the section
+ // note that this text is also set in the HTML template in render.rs
+ return "\u2212"; // "\u2212" is '−' minus sign
}
$("#toggle-all-docs").on("click", function() {
}
if (relatedDoc.is(".docblock")) {
if (relatedDoc.is(":visible")) {
- relatedDoc.slideUp({duration:'fast', easing:'linear'});
+ relatedDoc.slideUp({duration: 'fast', easing: 'linear'});
toggle.parent(".toggle-wrapper").addClass("collapsed");
toggle.children(".inner").text(labelForToggleButton(true));
toggle.children(".toggle-label").fadeIn();
} else {
- relatedDoc.slideDown({duration:'fast', easing:'linear'});
+ relatedDoc.slideDown({duration: 'fast', easing: 'linear'});
toggle.parent(".toggle-wrapper").removeClass("collapsed");
toggle.children(".inner").text(labelForToggleButton(false));
toggle.children(".toggle-label").hide();
$('<span/>', {'class': 'toggle-label'})
.css('display', 'none')
.html(' Expand description'));
- var wrapper = $("<div class='toggle-wrapper'>").append(mainToggle);
+ var wrapper = $("<div class='toggle-wrapper'>").append(mainToggle);
$("#main > .docblock").before(wrapper);
});
}
return function(ev) {
- var cur_id = parseInt(ev.target.id);
+ var cur_id = parseInt(ev.target.id, 10);
if (ev.shiftKey && prev_id) {
if (prev_id > cur_id) {
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
/*jslint browser: true, es5: true */
/*globals $: true, rootPath: true */
-(function() {
- if (window.playgroundUrl) {
- $('pre.rust').hover(function() {
- var a = $('<a>').text('⇱').attr('class', 'test-arrow');
- var code = $(this).prev(".rusttest").text();
- a.attr('href', window.playgroundUrl + '?code=' +
- encodeURIComponent(code));
- a.attr('target', '_blank');
- $(this).append(a);
- }, function() {
- $(this).find('a.test-arrow').remove();
- });
+document.addEventListener('DOMContentLoaded', function() {
+ if (!window.playgroundUrl) {
+ return;
}
-}());
+
+ var elements = document.querySelectorAll('pre.rust');
+
+ Array.prototype.forEach.call(elements, function(el) {
+ el.onmouseover = function(e) {
+ if (el.contains(e.relatedTarget)) {
+ return;
+ }
+
+ var a = document.createElement('a');
+ a.textContent = '⇱';
+ a.setAttribute('class', 'test-arrow');
+
+ var code = el.previousElementSibling.textContent;
+ a.setAttribute('href', window.playgroundUrl + '?code=' +
+ encodeURIComponent(code));
+ a.setAttribute('target', '_blank');
+
+ el.appendChild(a);
+ };
+
+ el.onmouseout = function(e) {
+ if (el.contains(e.relatedTarget)) {
+ return;
+ }
+
+ el.removeChild(el.querySelectorAll('a.test-arrow')[0]);
+ };
+ });
+});
(0, &self.top_level)
}
Some(entry) => {
- sec_number = String::from_str(&entry.sec_number);
+ sec_number = entry.sec_number.clone();
sec_number.push_str(".");
(entry.level, &entry.children)
}
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
- html_favicon_url = "http://www.rust-lang.org/favicon.ico",
+ html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(box_patterns)]
#![feature(box_syntax)]
-#![feature(collections)]
-#![feature(exit_status)]
-#![feature(set_stdio)]
+#![feature(dynamic_lib)]
#![feature(libc)]
+#![feature(owned_ascii_ext)]
+#![feature(path_ext)]
+#![feature(path_relative_from)]
#![feature(rustc_private)]
+#![feature(set_stdio)]
+#![feature(slice_extras)]
+#![feature(slice_patterns)]
#![feature(staged_api)]
-#![feature(std_misc)]
+#![feature(subslice_offset)]
#![feature(test)]
#![feature(unicode)]
-#![feature(path_ext)]
-#![feature(path_relative_from)]
-#![feature(slice_patterns)]
+#![feature(vec_push_all)]
extern crate arena;
extern crate getopts;
use std::fs::File;
use std::io::{self, Read, Write};
use std::path::PathBuf;
+use std::process;
use std::rc::Rc;
use std::sync::mpsc::channel;
let s = env::args().collect::<Vec<_>>();
main_args(&s)
}).unwrap().join().unwrap();
- env::set_exit_status(res as i32);
+ process::exit(res as i32);
}
pub fn opts() -> Vec<getopts::OptGroup> {
#[cfg(all(not(target_os="windows"), not(target_os="macos")))]
fn libname(n: String) -> String {
- let mut i = String::from_str("lib");
+ let mut i = String::from("lib");
i.push_str(&n);
i.push_str(".so");
i
};
let codemap = CodeMap::new();
- let diagnostic_handler = diagnostic::default_handler(diagnostic::Auto, None, true);
+ let diagnostic_handler = diagnostic::Handler::new(diagnostic::Auto, None, true);
let span_diagnostic_handler =
- diagnostic::mk_span_handler(diagnostic_handler, codemap);
+ diagnostic::SpanHandler::new(diagnostic_handler, codemap);
let sess = session::build_session_(sessopts,
Some(input_path.clone()),
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
let mut cfg = config::build_configuration(&sess);
- cfg.extend(config::parse_cfgspecs(cfgs).into_iter());
+ cfg.extend(config::parse_cfgspecs(cfgs));
let krate = driver::phase_1_parse_input(&sess, cfg, &input);
let krate = driver::phase_2_configure_and_expand(&sess, krate,
"rustdoc-test", None)
attrs: Vec::new(),
};
- let attrs = krate.attrs.iter().filter(|a| a.check_name("doc"))
+ let attrs = krate.attrs.iter()
+ .filter(|a| a.check_name("doc"))
.filter_map(|a| a.meta_item_list())
- .flat_map(|l| l.iter())
+ .flat_map(|l| l)
.filter(|a| a.check_name("test"))
.filter_map(|a| a.meta_item_list())
- .flat_map(|l| l.iter());
+ .flat_map(|l| l);
for attr in attrs {
if attr.check_name("no_crate_inject") {
opts.no_crate_inject = true;
// it with a sink that is also passed to rustc itself. When this function
// returns the output of the sink is copied onto the output of our own thread.
//
- // The basic idea is to not use a default_handler() for rustc, and then also
+ // The basic idea is to not use a default Handler for rustc, and then also
// not print things by default to the actual stderr.
struct Sink(Arc<Mutex<Vec<u8>>>);
impl Write for Sink {
// Compile the code
let codemap = CodeMap::new();
- let diagnostic_handler = diagnostic::mk_handler(true, box emitter);
+ let diagnostic_handler = diagnostic::Handler::with_emitter(true, box emitter);
let span_diagnostic_handler =
- diagnostic::mk_span_handler(diagnostic_handler, codemap);
+ diagnostic::SpanHandler::new(diagnostic_handler, codemap);
let sess = session::build_session_(sessopts,
None,
let path = env::var_os(var).unwrap_or(OsString::new());
let mut path = env::split_paths(&path).collect::<Vec<_>>();
path.insert(0, libdir.clone());
- env::join_paths(path.iter()).unwrap()
+ env::join_paths(path).unwrap()
};
cmd.env(var, &newpath);
use syntax::abi;
use syntax::ast;
use syntax::ast_util;
-use syntax::ast_map;
use syntax::attr;
use syntax::attr::AttrMetaMethods;
use syntax::codemap::Span;
+use rustc::ast_map;
use rustc::middle::stability;
use core;
pub struct RustdocVisitor<'a, 'tcx: 'a> {
pub module: Module,
pub attrs: Vec<ast::Attribute>,
- pub cx: &'a core::DocContext<'tcx>,
+ pub cx: &'a core::DocContext<'a, 'tcx>,
pub analysis: Option<&'a core::CrateAnalysis>,
view_item_stack: HashSet<ast::NodeId>,
inlining_from_glob: bool,
}
impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
- pub fn new(cx: &'a core::DocContext<'tcx>,
+ pub fn new(cx: &'a core::DocContext<'a, 'tcx>,
analysis: Option<&'a core::CrateAnalysis>) -> RustdocVisitor<'a, 'tcx> {
// If the root is reexported, terminate all recursion.
let mut stack = HashSet::new();
}
fn stability(&self, id: ast::NodeId) -> Option<attr::Stability> {
- self.cx.tcx_opt().and_then(|tcx| stability::lookup(tcx, ast_util::local_def(id)))
+ self.cx.tcx_opt().and_then(
+ |tcx| stability::lookup(tcx, ast_util::local_def(id)).map(|x| x.clone()))
}
pub fn visit(&mut self, krate: &ast::Crate) {
pub fn visit_fn(&mut self, item: &ast::Item,
name: ast::Ident, fd: &ast::FnDecl,
- unsafety: &ast::Unsafety, abi: &abi::Abi,
+ unsafety: &ast::Unsafety,
+ constness: ast::Constness,
+ abi: &abi::Abi,
gen: &ast::Generics) -> Function {
debug!("Visiting fn");
Function {
whence: item.span,
generics: gen.clone(),
unsafety: *unsafety,
+ constness: constness,
abi: *abi,
}
}
om.enums.push(self.visit_enum_def(item, name, ed, gen)),
ast::ItemStruct(ref sd, ref gen) =>
om.structs.push(self.visit_struct_def(item, name, &**sd, gen)),
- ast::ItemFn(ref fd, ref pur, ref abi, ref gen, _) =>
- om.fns.push(self.visit_fn(item, name, &**fd, pur, abi, gen)),
+ ast::ItemFn(ref fd, ref unsafety, constness, ref abi, ref gen, _) =>
+ om.fns.push(self.visit_fn(item, name, &**fd, unsafety,
+ constness, abi, gen)),
ast::ItemTy(ref ty, ref gen) => {
let t = Typedef {
ty: ty.clone(),
//! val: num.to_json(),
//! }).unwrap();
//! println!("data: {}", data);
-//! // data: {"uid":1,"dsc":"test","val":"0.0001+12.539j"};
+//! // data: {"uid":1,"dsc":"test","val":"0.0001+12.539i"};
//! }
//! ```
//!
fn fmt_number_or_null(v: f64) -> string::String {
match v.classify() {
- Fp::Nan | Fp::Infinite => string::String::from_str("null"),
+ Fp::Nan | Fp::Infinite => string::String::from("null"),
_ if v.fract() != 0f64 => v.to_string(),
_ => v.to_string() + ".0",
}
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
- html_favicon_url = "http://www.rust-lang.org/favicon.ico",
+ html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(box_syntax)]
#![feature(collections)]
-#![feature(core)]
+#![feature(enumset)]
+#![feature(hashmap_hasher)]
+#![feature(num_bits_bytes)]
#![feature(rustc_private)]
#![feature(staged_api)]
-#![feature(std_misc)]
-#![feature(unicode)]
#![feature(str_char)]
+#![feature(unicode)]
+#![feature(vecmap)]
#![cfg_attr(test, feature(test))]
// test harness access
use mem;
/// Extension methods for ASCII-subset only operations on owned strings
-#[unstable(feature = "std_misc",
+#[unstable(feature = "owned_ascii_ext",
reason = "would prefer to do this in a more general way")]
pub trait OwnedAsciiExt {
/// Converts the string to ASCII upper case:
}
}
-#[unstable(feature = "std_misc",
- reason = "would prefer to do this in a more general way")]
impl OwnedAsciiExt for String {
#[inline]
fn into_ascii_uppercase(self) -> String {
#[inline]
fn eq_ignore_ascii_case(&self, other: &[u8]) -> bool {
self.len() == other.len() &&
- self.iter().zip(other.iter()).all(|(a, b)| {
+ self.iter().zip(other).all(|(a, b)| {
a.eq_ignore_ascii_case(b)
})
}
}
}
-#[unstable(feature = "std_misc",
- reason = "would prefer to do this in a more general way")]
impl OwnedAsciiExt for Vec<u8> {
#[inline]
fn into_ascii_uppercase(mut self) -> Vec<u8> {
use super::state::HashState;
const INITIAL_LOG2_CAP: usize = 5;
-#[unstable(feature = "std_misc")]
-pub const INITIAL_CAPACITY: usize = 1 << INITIAL_LOG2_CAP; // 2^5
+const INITIAL_CAPACITY: usize = 1 << INITIAL_LOG2_CAP; // 2^5
/// The default behavior of HashMap implements a load factor of 90.9%.
/// This behavior is characterized by the following condition:
{
/// Creates an empty hashmap which will use the given hasher to hash keys.
///
- /// The creates map has the default initial capacity.
+ /// The created map has the default initial capacity.
///
/// # Examples
///
/// ```
- /// # #![feature(std_misc)]
+ /// # #![feature(hashmap_hasher)]
/// use std::collections::HashMap;
/// use std::collections::hash_map::RandomState;
///
/// map.insert(1, 2);
/// ```
#[inline]
- #[unstable(feature = "std_misc", reason = "hasher stuff is unclear")]
+ #[unstable(feature = "hashmap_hasher", reason = "hasher stuff is unclear")]
pub fn with_hash_state(hash_state: S) -> HashMap<K, V, S> {
HashMap {
hash_state: hash_state,
/// # Examples
///
/// ```
- /// # #![feature(std_misc)]
+ /// # #![feature(hashmap_hasher)]
/// use std::collections::HashMap;
/// use std::collections::hash_map::RandomState;
///
/// map.insert(1, 2);
/// ```
#[inline]
- #[unstable(feature = "std_misc", reason = "hasher stuff is unclear")]
+ #[unstable(feature = "hashmap_hasher", reason = "hasher stuff is unclear")]
pub fn with_capacity_and_hash_state(capacity: usize, hash_state: S)
-> HashMap<K, V, S> {
let resize_policy = DefaultResizePolicy::new();
/// *val *= 2;
/// }
///
- /// for (key, val) in map.iter() {
+ /// for (key, val) in &map {
/// println!("key: {} val: {}", key, val);
/// }
/// ```
/// # Examples
///
/// ```
- /// # #![feature(std_misc)]
+ /// # #![feature(drain)]
/// use std::collections::HashMap;
///
/// let mut a = HashMap::new();
/// assert!(a.is_empty());
/// ```
#[inline]
- #[unstable(feature = "std_misc",
+ #[unstable(feature = "drain",
reason = "matches collection reform specification, waiting for dust to settle")]
pub fn drain(&mut self) -> Drain<K, V> {
fn last_two<A, B, C>((_, b, c): (A, B, C)) -> (B, C) { (b, c) }
where K: Eq + Hash + Debug, V: Debug, S: HashState
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- self.iter().fold(f.debug_map(), |b, (k, v)| b.entry(k, v)).finish()
+ f.debug_map().entries(self.iter()).finish()
}
}
}
/// HashMap drain iterator.
-#[unstable(feature = "std_misc",
+#[unstable(feature = "drain",
reason = "matches collection reform specification, waiting for dust to settle")]
pub struct Drain<'a, K: 'a, V: 'a> {
inner: iter::Map<table::Drain<'a, K, V>, fn((SafeHash, K, V)) -> (K, V)>
}
impl<'a, K, V> Entry<'a, K, V> {
- #[unstable(feature = "std_misc",
+ #[unstable(feature = "entry",
reason = "will soon be replaced by or_insert")]
#[deprecated(since = "1.0",
reason = "replaced with more ergonomic `or_insert` and `or_insert_with`")]
/// `Hasher`, but the hashers created by two different `RandomState`
/// instances are unlikely to produce the same result for the same values.
#[derive(Clone)]
-#[unstable(feature = "std_misc",
+#[unstable(feature = "hashmap_hasher",
reason = "hashing an hash maps may be altered")]
pub struct RandomState {
k0: u64,
k1: u64,
}
-#[unstable(feature = "std_misc",
+#[unstable(feature = "hashmap_hasher",
reason = "hashing an hash maps may be altered")]
impl RandomState {
/// Constructs a new `RandomState` that is initialized with random keys.
}
}
-#[unstable(feature = "std_misc",
+#[unstable(feature = "hashmap_hasher",
reason = "hashing an hash maps may be altered")]
impl HashState for RandomState {
type Hasher = SipHasher;
use ops::{BitOr, BitAnd, BitXor, Sub};
use option::Option::{Some, None, self};
-use super::map::{self, HashMap, Keys, INITIAL_CAPACITY, RandomState};
+use super::map::{self, HashMap, Keys, RandomState};
use super::state::HashState;
+const INITIAL_CAPACITY: usize = 32;
+
// Future Optimization (FIXME!)
// =============================
//
/// # Examples
///
/// ```
- /// # #![feature(std_misc)]
+ /// # #![feature(hashmap_hasher)]
/// use std::collections::HashSet;
/// use std::collections::hash_map::RandomState;
///
/// set.insert(2);
/// ```
#[inline]
- #[unstable(feature = "std_misc", reason = "hasher stuff is unclear")]
+ #[unstable(feature = "hashmap_hasher", reason = "hasher stuff is unclear")]
pub fn with_hash_state(hash_state: S) -> HashSet<T, S> {
HashSet::with_capacity_and_hash_state(INITIAL_CAPACITY, hash_state)
}
/// # Examples
///
/// ```
- /// # #![feature(std_misc)]
+ /// # #![feature(hashmap_hasher)]
/// use std::collections::HashSet;
/// use std::collections::hash_map::RandomState;
///
/// set.insert(1);
/// ```
#[inline]
- #[unstable(feature = "std_misc", reason = "hasher stuff is unclear")]
+ #[unstable(feature = "hashmap_hasher", reason = "hasher stuff is unclear")]
pub fn with_capacity_and_hash_state(capacity: usize, hash_state: S)
-> HashSet<T, S> {
HashSet {
/// Clears the set, returning all elements in an iterator.
#[inline]
- #[unstable(feature = "std_misc",
+ #[unstable(feature = "drain",
reason = "matches collection reform specification, waiting for dust to settle")]
pub fn drain(&mut self) -> Drain<T> {
fn first<A, B>((a, _): (A, B)) -> A { a }
S: HashState
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- self.iter().fold(f.debug_set(), |b, e| b.entry(e)).finish()
+ f.debug_set().entries(self.iter()).finish()
}
}
///
/// let mut i = 0;
/// let expected = [1, 2, 3, 4, 5];
- /// for x in set.iter() {
+ /// for x in &set {
/// assert!(expected.contains(x));
/// i += 1;
/// }
///
/// let mut i = 0;
/// let expected = [2, 3];
- /// for x in set.iter() {
+ /// for x in &set {
/// assert!(expected.contains(x));
/// i += 1;
/// }
///
/// let mut i = 0;
/// let expected = [1, 2, 4, 5];
- /// for x in set.iter() {
+ /// for x in &set {
/// assert!(expected.contains(x));
/// i += 1;
/// }
///
/// let mut i = 0;
/// let expected = [1, 2];
- /// for x in set.iter() {
+ /// for x in &set {
/// assert!(expected.contains(x));
/// i += 1;
/// }
/// let v: Vec<String> = set.into_iter().collect();
///
/// // Will print in an arbitrary order.
- /// for x in v.iter() {
+ /// for x in &v {
/// println!("{}", x);
/// }
/// ```
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![unstable(feature = "hashmap_hasher", reason = "hasher stuff is unclear")]
+
use clone::Clone;
use default::Default;
use hash;
/// algorithm can implement the `Default` trait and create hash maps with the
/// `DefaultState` structure. This state is 0-sized and will simply delegate
/// to `Default` when asked to create a hasher.
-#[unstable(feature = "std_misc", reason = "hasher stuff is unclear")]
pub trait HashState {
/// Type of the hasher that will be created.
type Hasher: hash::Hasher;
/// default trait.
///
/// This struct has is 0-sized and does not need construction.
-#[unstable(feature = "std_misc", reason = "hasher stuff is unclear")]
pub struct DefaultState<H>(marker::PhantomData<H>);
impl<H: Default + hash::Hasher> HashState for DefaultState<H> {
use hash::{Hash, Hasher};
use iter::{Iterator, ExactSizeIterator};
use marker::{Copy, Send, Sync, Sized, self};
-use mem::{min_align_of, size_of};
+use mem::{align_of, size_of};
use mem;
use num::wrapping::OverflowingOps;
use ops::{Deref, DerefMut, Drop};
// Returns a tuple of (key_offset, val_offset),
// from the start of a mallocated array.
+#[inline]
fn calculate_offsets(hashes_size: usize,
keys_size: usize, keys_align: usize,
vals_align: usize)
vals_align);
let (end_of_vals, oflo2) = vals_offset.overflowing_add(vals_size);
- let min_align = cmp::max(hash_align, cmp::max(keys_align, vals_align));
+ let align = cmp::max(hash_align, cmp::max(keys_align, vals_align));
- (min_align, hash_offset, end_of_vals, oflo || oflo2)
+ (align, hash_offset, end_of_vals, oflo || oflo2)
}
#[test]
// factored out into a different function.
let (malloc_alignment, hash_offset, size, oflo) =
calculate_allocation(
- hashes_size, min_align_of::<u64>(),
- keys_size, min_align_of::< K >(),
- vals_size, min_align_of::< V >());
+ hashes_size, align_of::<u64>(),
+ keys_size, align_of::< K >(),
+ vals_size, align_of::< V >());
assert!(!oflo, "capacity overflow");
let buffer = *self.hashes as *mut u8;
let (keys_offset, vals_offset, oflo) =
calculate_offsets(hashes_size,
- keys_size, min_align_of::<K>(),
- min_align_of::<V>());
+ keys_size, align_of::<K>(),
+ align_of::<V>());
debug_assert!(!oflo, "capacity overflow");
unsafe {
RawBucket {
let keys_size = self.capacity * size_of::<K>();
let vals_size = self.capacity * size_of::<V>();
let (align, _, size, oflo) =
- calculate_allocation(hashes_size, min_align_of::<u64>(),
- keys_size, min_align_of::<K>(),
- vals_size, min_align_of::<V>());
+ calculate_allocation(hashes_size, align_of::<u64>(),
+ keys_size, align_of::<K>(),
+ vals_size, align_of::<V>());
debug_assert!(!oflo, "should be impossible");
//! ### Use a `BTreeMap` when:
//! * You're interested in what the smallest or largest key-value pair is.
//! * You want to find the largest or smallest key that is smaller or larger
-//! than something
+//! than something.
//! * You want to be able to get all of the entries in order on-demand.
//! * You want a sorted map.
//!
//! relation to the number of elements in the collection. VecMap should only be
//! seriously considered for small keys.
//!
-//! Note also that BTreeMap's precise preformance depends on the value of B.
+//! Note also that BTreeMap's precise performance depends on the value of B.
//!
//! # Correct and Efficient Usage of Collections
//!
//! contents by-value. This is great when the collection itself is no longer
//! needed, and the values are needed elsewhere. Using `extend` with `into_iter`
//! is the main way that contents of one collection are moved into another.
+//! `extend` automatically calls `into_iter`, and takes any `T: IntoIterator`.
//! Calling `collect` on an iterator itself is also a great way to convert one
//! collection into another. Both of these methods should internally use the
//! capacity management tools discussed in the previous section to do this as
//! ```
//! let mut vec1 = vec![1, 2, 3, 4];
//! let vec2 = vec![10, 20, 30, 40];
-//! vec1.extend(vec2.into_iter());
+//! vec1.extend(vec2);
//! ```
//!
//! ```
//! If a `Vacant(entry)` is yielded, then the key *was not* found. In this case
//! the only valid operation is to `insert` a value into the entry. When this is
//! done, the vacant entry is consumed and converted into a mutable reference to
-//! the the value that was inserted. This allows for further manipulation of the
+//! the value that was inserted. This allows for further manipulation of the
//! value beyond the lifetime of the search itself. This is useful if complex
//! logic needs to be performed on the value regardless of whether the value was
//! just inserted.
//! assert_eq!(count.get(&'s'), Some(&8));
//!
//! println!("Number of occurrences of each character");
-//! for (char, count) in count.iter() {
+//! for (char, count) in &count {
//! println!("{}: {}", char, count);
//! }
//! ```
//! // Our clients.
//! let mut blood_alcohol = BTreeMap::new();
//!
-//! for id in orders.into_iter() {
+//! for id in orders {
//! // If this is the first time we've seen this customer, initialize them
//! // with no blood alcohol. Otherwise, just retrieve them.
//! let person = blood_alcohol.entry(id).or_insert(Person{id: id, blood_alcohol: 0.0});
/// Experimental support for providing custom hash algorithms to a HashMap and
/// HashSet.
-#[unstable(feature = "std_misc", reason = "module was recently added")]
+#[unstable(feature = "hashmap_hasher", reason = "module was recently added")]
pub mod hash_state {
pub use super::hash::state::*;
}
//!
//! A simple wrapper over the platform's dynamic library facilities
-#![unstable(feature = "std_misc")]
+#![unstable(feature = "dynamic_lib",
+ reason = "API has not been scrutinized and is highly likely to \
+ either disappear or change")]
#![allow(missing_docs)]
use prelude::v1::*;
pub fn check_for_errors_in<T, F>(f: F) -> Result<T, String> where
F: FnOnce() -> T,
{
- use sync::{StaticMutex, MUTEX_INIT};
- static LOCK: StaticMutex = MUTEX_INIT;
+ use sync::StaticMutex;
+ static LOCK: StaticMutex = StaticMutex::new();
unsafe {
// dlerror isn't thread safe, so we need to lock around this entire
// sequence
let result = match filename {
Some(filename) => {
let filename_str: Vec<_> =
- filename.encode_wide().chain(Some(0).into_iter()).collect();
+ filename.encode_wide().chain(Some(0)).collect();
let result = unsafe {
LoadLibraryW(filename_str.as_ptr() as *const libc::c_void)
};
use fmt;
use io;
use path::{Path, PathBuf};
-use sync::atomic::{AtomicIsize, ATOMIC_ISIZE_INIT, Ordering};
-use sync::{StaticMutex, MUTEX_INIT};
+use sync::atomic::{AtomicIsize, Ordering};
+use sync::StaticMutex;
use sys::os as os_imp;
/// Returns the current working directory as a `PathBuf`.
os_imp::chdir(p.as_ref())
}
-static ENV_LOCK: StaticMutex = MUTEX_INIT;
+static ENV_LOCK: StaticMutex = StaticMutex::new();
/// An iterator over a snapshot of the environment variables of this process.
///
/// if let Some(path) = env::var_os("PATH") {
/// let mut paths = env::split_paths(&path).collect::<Vec<_>>();
/// paths.push(PathBuf::from("/home/xyz/bin"));
-/// let new_path = env::join_paths(paths.iter()).unwrap();
+/// let new_path = env::join_paths(paths).unwrap();
/// env::set_var("PATH", &new_path);
/// }
/// ```
os_imp::current_exe()
}
-static EXIT_STATUS: AtomicIsize = ATOMIC_ISIZE_INIT;
+static EXIT_STATUS: AtomicIsize = AtomicIsize::new(0);
/// Sets the process exit code
///
///
/// Note that this is not synchronized against modifications of other threads.
#[unstable(feature = "exit_status", reason = "managing the exit status may change")]
+#[deprecated(since = "1.2.0", reason = "use process::exit instead")]
pub fn set_exit_status(code: i32) {
EXIT_STATUS.store(code as isize, Ordering::SeqCst)
}
/// Fetches the process's current exit code. This defaults to 0 and can change
/// by calling `set_exit_status`.
#[unstable(feature = "exit_status", reason = "managing the exit status may change")]
+#[deprecated(since = "1.2.0", reason = "use process::exit instead")]
pub fn get_exit_status() -> i32 {
EXIT_STATUS.load(Ordering::SeqCst) as i32
}
pub mod consts {
/// A string describing the architecture of the CPU that this is currently
/// in use.
+ ///
+ /// Some possible values:
+ ///
+ /// - x86
+ /// - x86_64
+ /// - arm
+ /// - aarch64
+ /// - mips
+ /// - mipsel
+ /// - powerpc
#[stable(feature = "env", since = "1.0.0")]
pub const ARCH: &'static str = super::arch::ARCH;
/// The family of the operating system. In this case, `unix`.
+ ///
+ /// Some possible values:
+ ///
+ /// - unix
+ /// - windows
#[stable(feature = "env", since = "1.0.0")]
pub const FAMILY: &'static str = super::os::FAMILY;
/// A string describing the specific operating system in use: in this
/// case, `linux`.
+ ///
+ /// Some possible values:
+ ///
+ /// - linux
+ /// - macos
+ /// - ios
+ /// - freebsd
+ /// - dragonfly
+ /// - bitrig
+ /// - openbsd
+ /// - android
+ /// - windows
#[stable(feature = "env", since = "1.0.0")]
pub const OS: &'static str = super::os::OS;
/// Specifies the filename prefix used for shared libraries on this
/// platform: in this case, `lib`.
+ ///
+ /// Some possible values:
+ ///
+ /// - lib
+ /// - `""` (an empty string)
#[stable(feature = "env", since = "1.0.0")]
pub const DLL_PREFIX: &'static str = super::os::DLL_PREFIX;
/// Specifies the filename suffix used for shared libraries on this
/// platform: in this case, `.so`.
+ ///
+ /// Some possible values:
+ ///
+ /// - .so
+ /// - .dylib
+ /// - .dll
#[stable(feature = "env", since = "1.0.0")]
pub const DLL_SUFFIX: &'static str = super::os::DLL_SUFFIX;
/// Specifies the file extension used for shared libraries on this
/// platform that goes after the dot: in this case, `so`.
+ ///
+ /// Some possible values:
+ ///
+ /// - .so
+ /// - .dylib
+ /// - .dll
#[stable(feature = "env", since = "1.0.0")]
pub const DLL_EXTENSION: &'static str = super::os::DLL_EXTENSION;
/// Specifies the filename suffix used for executable binaries on this
/// platform: in this case, the empty string.
+ ///
+ /// Some possible values:
+ ///
+ /// - exe
+ /// - `""` (an empty string)
#[stable(feature = "env", since = "1.0.0")]
pub const EXE_SUFFIX: &'static str = super::os::EXE_SUFFIX;
/// Specifies the file extension, if any, used for executable binaries
/// on this platform: in this case, the empty string.
+ ///
+ /// Some possible values:
+ ///
+ /// - exe
+ /// - `""` (an empty string)
#[stable(feature = "env", since = "1.0.0")]
pub const EXE_EXTENSION: &'static str = super::os::EXE_EXTENSION;
// reconsider what crate these items belong in.
use any::TypeId;
-use boxed::{self, Box};
+use boxed::Box;
use convert::From;
use fmt::{self, Debug, Display};
use marker::{Send, Sync, Reflect};
/// Get the `TypeId` of `self`
#[doc(hidden)]
- #[unstable(feature = "core",
+ #[unstable(feature = "error_type_id",
reason = "unclear whether to commit to this public implementation detail")]
fn type_id(&self) -> TypeId where Self: 'static {
TypeId::of::<Self>()
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, 'b> From<&'b str> for Box<Error + Send + Sync + 'a> {
fn from(err: &'b str) -> Box<Error + Send + Sync + 'a> {
- From::from(String::from_str(err))
+ From::from(String::from(err))
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl Error for num::ParseIntError {
fn description(&self) -> &str {
- self.description()
+ self.__description()
}
}
if self.is::<T>() {
unsafe {
// Get the raw representation of the trait object
- let raw = boxed::into_raw(self);
+ let raw = Box::into_raw(self);
let to: TraitObject =
transmute::<*mut Error, TraitObject>(raw);
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![unstable(feature = "std_misc")]
-
+use borrow::{Cow, ToOwned};
+use boxed::Box;
+use clone::Clone;
use convert::{Into, From};
use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering};
use error::Error;
use option::Option::{self, Some, None};
use result::Result::{self, Ok, Err};
use slice;
+use str;
use string::String;
use vec::Vec;
/// fn my_printer(s: *const libc::c_char);
/// }
///
-/// let to_print = &b"Hello, world!"[..];
-/// let c_to_print = CString::new(to_print).unwrap();
+/// let c_to_print = CString::new("Hello, world!").unwrap();
/// unsafe {
/// my_printer(c_to_print.as_ptr());
/// }
/// # }
/// ```
-#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
+#[derive(PartialEq, PartialOrd, Eq, Ord, Hash)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct CString {
- inner: Vec<u8>,
+ inner: Box<[u8]>,
}
/// Representation of a borrowed C string.
/// work(&s);
/// }
/// ```
+///
+/// Converting a foreign C string into a Rust `String`
+///
+/// ```no_run
+/// # #![feature(libc,cstr_to_str)]
+/// extern crate libc;
+/// use std::ffi::CStr;
+///
+/// extern { fn my_string() -> *const libc::c_char; }
+///
+/// fn my_string_safe() -> String {
+/// unsafe {
+/// CStr::from_ptr(my_string()).to_string_lossy().into_owned()
+/// }
+/// }
+///
+/// fn main() {
+/// println!("string: {}", my_string_safe());
+/// }
+/// ```
#[derive(Hash)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct CStr {
#[stable(feature = "rust1", since = "1.0.0")]
pub unsafe fn from_vec_unchecked(mut v: Vec<u8>) -> CString {
v.push(0);
- CString { inner: v }
+ CString { inner: v.into_boxed_slice() }
+ }
+
+ /// Retakes ownership of a CString that was transferred to C.
+ ///
+ /// The only appropriate argument is a pointer obtained by calling
+ /// `into_ptr`. The length of the string will be recalculated
+ /// using the pointer.
+ #[unstable(feature = "cstr_memory", reason = "recently added")]
+ // NB: may want to be called from_raw, needs to consider CStr::from_ptr,
+ // Box::from_raw (or whatever it's currently called), and
+ // slice::from_raw_parts
+ pub unsafe fn from_ptr(ptr: *const libc::c_char) -> CString {
+ let len = libc::strlen(ptr) + 1; // Including the NUL byte
+ let slice = slice::from_raw_parts(ptr, len as usize);
+ CString { inner: mem::transmute(slice) }
+ }
+
+ /// Transfers ownership of the string to a C caller.
+ ///
+ /// The pointer must be returned to Rust and reconstituted using
+ /// `from_ptr` to be properly deallocated. Specifically, one
+ /// should *not* use the standard C `free` function to deallocate
+ /// this string.
+ ///
+ /// Failure to call `from_ptr` will lead to a memory leak.
+ #[unstable(feature = "cstr_memory", reason = "recently added")]
+ // NB: may want to be called into_raw, see comments on from_ptr
+ pub fn into_ptr(self) -> *const libc::c_char {
+ // It is important that the bytes be sized to fit - we need
+ // the capacity to be determinable from the string length, and
+ // shrinking to fit is the only way to be sure.
+ Box::into_raw(self.inner) as *const libc::c_char
}
/// Returns the contents of this `CString` as a slice of bytes.
}
}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Clone for CString {
+ fn clone(&self) -> Self {
+ CString { inner: self.inner.to_owned().into_boxed_slice() }
+ }
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl Deref for CString {
type Target = CStr;
pub fn to_bytes_with_nul(&self) -> &[u8] {
unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.inner) }
}
+
+ /// Yields a `&str` slice if the `CStr` contains valid UTF-8.
+ ///
+ /// This function will calculate the length of this string and check for
+ /// UTF-8 validity, and then return the `&str` if it's valid.
+ ///
+ /// > **Note**: This method is currently implemented to check for validity
+ /// > after a 0-cost cast, but it is planned to alter its definition in the
+ /// > future to perform the length calculation in addition to the UTF-8
+ /// > check whenever this method is called.
+ #[unstable(feature = "cstr_to_str", reason = "recently added")]
+ pub fn to_str(&self) -> Result<&str, str::Utf8Error> {
+ // NB: When CStr is changed to perform the length check in .to_bytes() instead of in
+ // from_ptr(), it may be worth considering if this should be rewritten to do the UTF-8
+ // check inline with the length calculation instead of doing it afterwards.
+ str::from_utf8(self.to_bytes())
+ }
+
+ /// Converts a `CStr` into a `Cow<str>`.
+ ///
+ /// This function will calculate the length of this string (which normally
+ /// requires a linear amount of work to be done) and then return the
+ /// resulting slice as a `Cow<str>`, replacing any invalid UTF-8 sequences
+ /// with `U+FFFD REPLACEMENT CHARACTER`.
+ ///
+ /// > **Note**: This method is currently implemented to check for validity
+ /// > after a 0-cost cast, but it is planned to alter its definition in the
+ /// > future to perform the length calculation in addition to the UTF-8
+ /// > check whenever this method is called.
+ #[unstable(feature = "cstr_to_str", reason = "recently added")]
+ pub fn to_string_lossy(&self) -> Cow<str> {
+ String::from_utf8_lossy(self.to_bytes())
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
use prelude::v1::*;
use super::*;
use libc;
+ use borrow::Cow::{Borrowed, Owned};
#[test]
fn c_to_rust() {
assert_eq!(s.to_bytes_with_nul(), b"12\0");
}
}
+
+ #[test]
+ fn to_str() {
+ let data = b"123\xE2\x80\xA6\0";
+ let ptr = data.as_ptr() as *const libc::c_char;
+ unsafe {
+ assert_eq!(CStr::from_ptr(ptr).to_str(), Ok("123…"));
+ assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Borrowed("123…"));
+ }
+ let data = b"123\xE2\0";
+ let ptr = data.as_ptr() as *const libc::c_char;
+ unsafe {
+ assert!(CStr::from_ptr(ptr).to_str().is_err());
+ assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Owned::<str>(format!("123\u{FFFD}")));
+ }
+ }
}
/// Rename a file or directory to a new name.
///
+/// This will not work if the new name is on a different mount point.
+///
/// # Errors
///
/// This function will return an error if the provided `from` doesn't exist, if
/// # Ok(())
/// # }
/// ```
-#[deprecated(since = "1.0.0",
+#[deprecated(since = "1.1.0",
reason = "replaced with std::os::unix::fs::symlink and \
std::os::windows::fs::{symlink_file, symlink_dir}")]
#[stable(feature = "rust1", since = "1.0.0")]
/// # Examples
///
/// ```
-/// # #![feature(path_ext)]
/// use std::io;
-/// use std::fs::{self, PathExt, DirEntry};
+/// use std::fs::{self, DirEntry};
/// use std::path::Path;
///
/// // one possible implementation of fs::walk_dir only visiting files
-/// fn visit_dirs(dir: &Path, cb: &mut FnMut(DirEntry)) -> io::Result<()> {
-/// if dir.is_dir() {
+/// fn visit_dirs(dir: &Path, cb: &Fn(&DirEntry)) -> io::Result<()> {
+/// if try!(fs::metadata(dir)).is_dir() {
/// for entry in try!(fs::read_dir(dir)) {
/// let entry = try!(entry);
-/// if entry.path().is_dir() {
+/// if try!(fs::metadata(entry.path())).is_dir() {
/// try!(visit_dirs(&entry.path(), cb));
/// } else {
-/// cb(entry);
+/// cb(&entry);
/// }
/// }
/// }
/// Utility methods for paths.
#[unstable(feature = "path_ext",
- reason = "the precise set of methods exposed on this trait may \
- change and some methods may be removed")]
+ reason = "The precise set of methods exposed on this trait may \
+ change and some methods may be removed. For stable code, \
+ see the std::fs::metadata function.")]
pub trait PathExt {
/// Gets information on the file, directory, etc at this path.
///
/// For example, every call to `read` on `TcpStream` results in a system call.
/// A `BufReader` performs large, infrequent reads on the underlying `Read`
/// and maintains an in-memory buffer of the results.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::io::prelude::*;
+/// use std::io::BufReader;
+/// use std::fs::File;
+///
+/// # fn foo() -> std::io::Result<()> {
+/// let mut f = try!(File::open("log.txt"));
+/// let mut reader = BufReader::new(f);
+///
+/// let mut line = String::new();
+/// let len = try!(reader.read_line(&mut line));
+/// println!("First line is {} bytes long", len);
+/// # Ok(())
+/// # }
+/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub struct BufReader<R> {
inner: R,
#[unstable(feature = "buf_stream",
reason = "unsure about semantics of buffering two directions, \
leading to issues like #17136")]
+#[deprecated(since = "1.2.0",
+ reason = "use the crates.io `bufstream` crate instead")]
pub struct BufStream<S: Write> {
inner: BufReader<InternalBufWriter<S>>
}
#[unstable(feature = "buf_stream",
reason = "unsure about semantics of buffering two directions, \
leading to issues like #17136")]
+#[deprecated(since = "1.2.0",
+ reason = "use the crates.io `bufstream` crate instead")]
+#[allow(deprecated)]
impl<S: Read + Write> BufStream<S> {
/// Creates a new buffered stream with explicitly listed capacities for the
/// reader/writer buffer.
#[unstable(feature = "buf_stream",
reason = "unsure about semantics of buffering two directions, \
leading to issues like #17136")]
+#[allow(deprecated)]
impl<S: Read + Write> BufRead for BufStream<S> {
fn fill_buf(&mut self) -> io::Result<&[u8]> { self.inner.fill_buf() }
fn consume(&mut self, amt: usize) { self.inner.consume(amt) }
#[unstable(feature = "buf_stream",
reason = "unsure about semantics of buffering two directions, \
leading to issues like #17136")]
+#[allow(deprecated)]
impl<S: Read + Write> Read for BufStream<S> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.inner.read(buf)
#[unstable(feature = "buf_stream",
reason = "unsure about semantics of buffering two directions, \
leading to issues like #17136")]
+#[allow(deprecated)]
impl<S: Read + Write> Write for BufStream<S> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.inner.inner.get_mut().write(buf)
#[unstable(feature = "buf_stream",
reason = "unsure about semantics of buffering two directions, \
leading to issues like #17136")]
+#[allow(deprecated)]
impl<S: Write> fmt::Debug for BufStream<S> where S: fmt::Debug {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let reader = &self.inner;
repr: Repr,
}
-#[derive(Debug)]
enum Repr {
Os(i32),
Custom(Box<Custom>),
/// A parameter was incorrect.
#[stable(feature = "rust1", since = "1.0.0")]
InvalidInput,
+ /// Data not valid for the operation were encountered.
+ ///
+ /// Unlike `InvalidInput`, this typically means that the operation
+ /// parameters were valid, however the error was caused by malformed
+ /// input data.
+ #[stable(feature = "io_invalid_data", since = "1.2.0")]
+ InvalidData,
/// The I/O operation's timeout expired, causing it to be canceled.
#[stable(feature = "rust1", since = "1.0.0")]
TimedOut,
Other,
/// Any I/O error not part of this list.
- #[unstable(feature = "std_misc",
+ #[unstable(feature = "io_error_internals",
reason = "better expressed through extensible enums that this \
enum cannot be exhaustively matched against")]
#[doc(hidden)]
///
/// This function is used to generically create I/O errors which do not
/// originate from the OS itself. The `error` argument is an arbitrary
- /// payload which will be contained in this `Error`. Accessors as well as
- /// downcasting will soon be added to this type as well to access the custom
- /// information.
+ /// payload which will be contained in this `Error`.
///
/// # Examples
///
/// Returns the OS error that this error represents (if any).
///
- /// If this `Error` was constructed via `last_os_error` then this function
- /// will return `Some`, otherwise it will return `None`.
+ /// If this `Error` was constructed via `last_os_error` or
+ /// `from_raw_os_error`, then this function will return `Some`, otherwise
+ /// it will return `None`.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn raw_os_error(&self) -> Option<i32> {
match self.repr {
}
}
+ /// Returns a reference to the inner error wrapped by this error (if any).
+ ///
+ /// If this `Error` was constructed via `new` then this function will
+ /// return `Some`, otherwise it will return `None`.
+ #[unstable(feature = "io_error_inner",
+ reason = "recently added and requires UFCS to downcast")]
+ pub fn get_ref(&self) -> Option<&(error::Error+Send+Sync+'static)> {
+ match self.repr {
+ Repr::Os(..) => None,
+ Repr::Custom(ref c) => Some(&*c.error),
+ }
+ }
+
+ /// Returns a mutable reference to the inner error wrapped by this error
+ /// (if any).
+ ///
+ /// If this `Error` was constructed via `new` then this function will
+ /// return `Some`, otherwise it will return `None`.
+ #[unstable(feature = "io_error_inner",
+ reason = "recently added and requires UFCS to downcast")]
+ pub fn get_mut(&mut self) -> Option<&mut (error::Error+Send+Sync+'static)> {
+ match self.repr {
+ Repr::Os(..) => None,
+ Repr::Custom(ref mut c) => Some(&mut *c.error),
+ }
+ }
+
+ /// Consumes the `Error`, returning its inner error (if any).
+ ///
+ /// If this `Error` was constructed via `new` then this function will
+ /// return `Some`, otherwise it will return `None`.
+ #[unstable(feature = "io_error_inner",
+ reason = "recently added and requires UFCS to downcast")]
+ pub fn into_inner(self) -> Option<Box<error::Error+Send+Sync>> {
+ match self.repr {
+ Repr::Os(..) => None,
+ Repr::Custom(c) => Some(c.error)
+ }
+ }
+
/// Returns the corresponding `ErrorKind` for this error.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn kind(&self) -> ErrorKind {
}
}
+impl fmt::Debug for Repr {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ &Repr::Os(ref code) =>
+ fmt.debug_struct("Os").field("code", code)
+ .field("message", &sys::os::error_string(*code)).finish(),
+ &Repr::Custom(ref c) => fmt.debug_tuple("Custom").field(c).finish(),
+ }
+ }
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Display for Error {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
Repr::Custom(ref c) => c.error.description(),
}
}
+
+ fn cause(&self) -> Option<&error::Error> {
+ match self.repr {
+ Repr::Os(..) => None,
+ Repr::Custom(ref c) => c.error.cause(),
+ }
+ }
}
fn _assert_error_is_sync_send() {
fn _is_sync_send<T: Sync+Send>() {}
_is_sync_send::<Error>();
}
+
+#[cfg(test)]
+mod test {
+ use prelude::v1::*;
+ use super::{Error, ErrorKind};
+ use error;
+ use error::Error as error_Error;
+ use fmt;
+ use sys::os::error_string;
+
+ #[test]
+ fn test_debug_error() {
+ let code = 6;
+ let msg = error_string(code);
+ let err = Error { repr: super::Repr::Os(code) };
+ let expected = format!("Error {{ repr: Os {{ code: {:?}, message: {:?} }} }}", code, msg);
+ assert_eq!(format!("{:?}", err), expected);
+ }
+
+ #[test]
+ fn test_downcasting() {
+ #[derive(Debug)]
+ struct TestError;
+
+ impl fmt::Display for TestError {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ Ok(())
+ }
+ }
+
+ impl error::Error for TestError {
+ fn description(&self) -> &str {
+ "asdf"
+ }
+ }
+
+ // we have to call all of these UFCS style right now since method
+ // resolution won't implicitly drop the Send+Sync bounds
+ let mut err = Error::new(ErrorKind::Other, TestError);
+ assert!(error::Error::is::<TestError>(err.get_ref().unwrap()));
+ assert_eq!("asdf", err.get_ref().unwrap().description());
+ assert!(error::Error::is::<TestError>(err.get_mut().unwrap()));
+ let extracted = err.into_inner().unwrap();
+ error::Error::downcast::<TestError>(extracted).unwrap();
+ }
+}
use prelude::v1::*;
-use boxed;
-use cell::UnsafeCell;
+use cell::Cell;
use rt;
use sync::{StaticMutex, Arc};
pub struct Lazy<T> {
- pub lock: StaticMutex,
- pub ptr: UnsafeCell<*mut Arc<T>>,
- pub init: fn() -> Arc<T>,
+ lock: StaticMutex,
+ ptr: Cell<*mut Arc<T>>,
+ init: fn() -> Arc<T>,
}
unsafe impl<T> Sync for Lazy<T> {}
-macro_rules! lazy_init {
- ($init:expr) => (::io::lazy::Lazy {
- lock: ::sync::MUTEX_INIT,
- ptr: ::cell::UnsafeCell { value: 0 as *mut _ },
- init: $init,
- })
-}
-
impl<T: Send + Sync + 'static> Lazy<T> {
+ pub const fn new(init: fn() -> Arc<T>) -> Lazy<T> {
+ Lazy {
+ lock: StaticMutex::new(),
+ ptr: Cell::new(0 as *mut _),
+ init: init
+ }
+ }
+
pub fn get(&'static self) -> Option<Arc<T>> {
let _g = self.lock.lock();
+ let ptr = self.ptr.get();
unsafe {
- let ptr = *self.ptr.get();
if ptr.is_null() {
Some(self.init())
} else if ptr as usize == 1 {
// `Arc`.
let registered = rt::at_exit(move || {
let g = self.lock.lock();
- let ptr = *self.ptr.get();
- *self.ptr.get() = 1 as *mut _;
+ let ptr = self.ptr.get();
+ self.ptr.set(1 as *mut _);
drop(g);
drop(Box::from_raw(ptr))
});
let ret = (self.init)();
if registered.is_ok() {
- *self.ptr.get() = boxed::into_raw(Box::new(ret.clone()));
+ self.ptr.set(Box::into_raw(Box::new(ret.clone())));
}
return ret
}
#[doc(no_inline, hidden)]
pub use self::stdio::{set_panic, set_print};
-#[macro_use] mod lazy;
-
pub mod prelude;
mod buffered;
mod cursor;
mod error;
mod impls;
+mod lazy;
mod util;
mod stdio;
let ret = f(g.s);
if str::from_utf8(&g.s[g.len..]).is_err() {
ret.and_then(|_| {
- Err(Error::new(ErrorKind::InvalidInput,
+ Err(Error::new(ErrorKind::InvalidData,
"stream did not contain valid UTF-8"))
})
} else {
/// any wrapped object.
///
/// Calls to `write` are not guaranteed to block waiting for data to be
- /// written, and a write which would otherwise block can indicated through
+ /// written, and a write which would otherwise block can be indicated through
/// an `Err` variant.
///
/// If the return value is `Ok(n)` then it must be guaranteed that
}
}
-/// A Buffer is a type of reader which has some form of internal buffering to
+/// A `BufRead` is a type of reader which has some form of internal buffering to
/// allow certain kinds of reading operations to be more optimized than others.
///
/// This type extends the `Read` trait with a few methods that are not
/// possible to reasonably implement with purely a read interface.
+///
+/// You can use the [`BufReader` wrapper type](struct.BufReader.html) to turn any
+/// reader into a buffered reader.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait BufRead: Read {
/// Fills the internal buffer of this object, returning the buffer contents.
read_until(self, byte, buf)
}
- /// Read all bytes until a newline byte (the 0xA byte) is reached, and
+ /// Read all bytes until a newline (the 0xA byte) is reached, and
/// append them to the provided buffer.
///
/// This function will continue to read (and buffer) bytes from the
use sync::{Arc, Mutex, MutexGuard};
use sys::stdio;
use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
+use libc;
/// Stdout used by print! and println! macros
thread_local! {
/// handles is **not** available to raw handles returned from this function.
///
/// The returned handle has no external synchronization or buffering.
-fn stdin_raw() -> StdinRaw { StdinRaw(stdio::Stdin::new()) }
+fn stdin_raw() -> io::Result<StdinRaw> { stdio::Stdin::new().map(StdinRaw) }
/// Constructs a new raw handle to the standard input stream of this process.
///
///
/// The returned handle has no external synchronization or buffering layered on
/// top.
-fn stdout_raw() -> StdoutRaw { StdoutRaw(stdio::Stdout::new()) }
+fn stdout_raw() -> io::Result<StdoutRaw> { stdio::Stdout::new().map(StdoutRaw) }
/// Constructs a new raw handle to the standard input stream of this process.
///
///
/// The returned handle has no external synchronization or buffering layered on
/// top.
-fn stderr_raw() -> StderrRaw { StderrRaw(stdio::Stderr::new()) }
+fn stderr_raw() -> io::Result<StderrRaw> { stdio::Stderr::new().map(StderrRaw) }
impl Read for StdinRaw {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.0.read(buf) }
fn flush(&mut self) -> io::Result<()> { Ok(()) }
}
+enum Maybe<T> {
+ Real(T),
+ Fake,
+}
+
+impl<W: io::Write> io::Write for Maybe<W> {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ match *self {
+ Maybe::Real(ref mut w) => handle_ebadf(w.write(buf), buf.len()),
+ Maybe::Fake => Ok(buf.len())
+ }
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ match *self {
+ Maybe::Real(ref mut w) => handle_ebadf(w.flush(), ()),
+ Maybe::Fake => Ok(())
+ }
+ }
+}
+
+impl<R: io::Read> io::Read for Maybe<R> {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ match *self {
+ Maybe::Real(ref mut r) => handle_ebadf(r.read(buf), buf.len()),
+ Maybe::Fake => Ok(0)
+ }
+ }
+}
+
+fn handle_ebadf<T>(r: io::Result<T>, default: T) -> io::Result<T> {
+ #[cfg(windows)]
+ const ERR: libc::c_int = libc::ERROR_INVALID_HANDLE;
+ #[cfg(not(windows))]
+ const ERR: libc::c_int = libc::EBADF;
+
+ match r {
+ Err(ref e) if e.raw_os_error() == Some(ERR) => Ok(default),
+ r => r
+ }
+}
+
/// A handle to the standard input stream of a process.
///
/// Each handle is a shared reference to a global buffer of input data to this
/// Created by the function `io::stdin()`.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Stdin {
- inner: Arc<Mutex<BufReader<StdinRaw>>>,
+ inner: Arc<Mutex<BufReader<Maybe<StdinRaw>>>>,
}
/// A locked reference to the a `Stdin` handle.
/// constructed via the `lock` method on `Stdin`.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct StdinLock<'a> {
- inner: MutexGuard<'a, BufReader<StdinRaw>>,
+ inner: MutexGuard<'a, BufReader<Maybe<StdinRaw>>>,
}
/// Creates a new handle to the global standard input stream of this process.
/// locked version, `StdinLock`, implements both `Read` and `BufRead`, however.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn stdin() -> Stdin {
- static INSTANCE: Lazy<Mutex<BufReader<StdinRaw>>> = lazy_init!(stdin_init);
+ static INSTANCE: Lazy<Mutex<BufReader<Maybe<StdinRaw>>>> = Lazy::new(stdin_init);
return Stdin {
inner: INSTANCE.get().expect("cannot access stdin during shutdown"),
};
- fn stdin_init() -> Arc<Mutex<BufReader<StdinRaw>>> {
+ fn stdin_init() -> Arc<Mutex<BufReader<Maybe<StdinRaw>>>> {
+ let stdin = match stdin_raw() {
+ Ok(stdin) => Maybe::Real(stdin),
+ _ => Maybe::Fake
+ };
+
// The default buffer capacity is 64k, but apparently windows
// doesn't like 64k reads on stdin. See #13304 for details, but the
// idea is that on windows we use a slightly smaller buffer that's
// been seen to be acceptable.
Arc::new(Mutex::new(if cfg!(windows) {
- BufReader::with_capacity(8 * 1024, stdin_raw())
+ BufReader::with_capacity(8 * 1024, stdin)
} else {
- BufReader::new(stdin_raw())
+ BufReader::new(stdin)
}))
}
}
self.inner.read(buf)
}
}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> BufRead for StdinLock<'a> {
fn fill_buf(&mut self) -> io::Result<&[u8]> { self.inner.fill_buf() }
// FIXME: this should be LineWriter or BufWriter depending on the state of
// stdout (tty or not). Note that if this is not line buffered it
// should also flush-on-panic or some form of flush-on-abort.
- inner: Arc<ReentrantMutex<RefCell<LineWriter<StdoutRaw>>>>,
+ inner: Arc<ReentrantMutex<RefCell<LineWriter<Maybe<StdoutRaw>>>>>,
}
/// A locked reference to the a `Stdout` handle.
/// method on `Stdout`.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct StdoutLock<'a> {
- inner: ReentrantMutexGuard<'a, RefCell<LineWriter<StdoutRaw>>>,
+ inner: ReentrantMutexGuard<'a, RefCell<LineWriter<Maybe<StdoutRaw>>>>,
}
/// Constructs a new reference to the standard output of the current process.
/// The returned handle implements the `Write` trait.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn stdout() -> Stdout {
- static INSTANCE: Lazy<ReentrantMutex<RefCell<LineWriter<StdoutRaw>>>> = lazy_init!(stdout_init);
+ static INSTANCE: Lazy<ReentrantMutex<RefCell<LineWriter<Maybe<StdoutRaw>>>>>
+ = Lazy::new(stdout_init);
return Stdout {
inner: INSTANCE.get().expect("cannot access stdout during shutdown"),
};
- fn stdout_init() -> Arc<ReentrantMutex<RefCell<LineWriter<StdoutRaw>>>> {
- Arc::new(ReentrantMutex::new(RefCell::new(LineWriter::new(stdout_raw()))))
+ fn stdout_init() -> Arc<ReentrantMutex<RefCell<LineWriter<Maybe<StdoutRaw>>>>> {
+ let stdout = match stdout_raw() {
+ Ok(stdout) => Maybe::Real(stdout),
+ _ => Maybe::Fake,
+ };
+ Arc::new(ReentrantMutex::new(RefCell::new(LineWriter::new(stdout))))
}
}
/// For more information, see `stderr`
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Stderr {
- inner: Arc<ReentrantMutex<RefCell<StderrRaw>>>,
+ inner: Arc<ReentrantMutex<RefCell<Maybe<StderrRaw>>>>,
}
/// A locked reference to the a `Stderr` handle.
/// method on `Stderr`.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct StderrLock<'a> {
- inner: ReentrantMutexGuard<'a, RefCell<StderrRaw>>,
+ inner: ReentrantMutexGuard<'a, RefCell<Maybe<StderrRaw>>>,
}
/// Constructs a new reference to the standard error stream of a process.
/// The returned handle implements the `Write` trait.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn stderr() -> Stderr {
- static INSTANCE: Lazy<ReentrantMutex<RefCell<StderrRaw>>> = lazy_init!(stderr_init);
+ static INSTANCE: Lazy<ReentrantMutex<RefCell<Maybe<StderrRaw>>>> = Lazy::new(stderr_init);
return Stderr {
inner: INSTANCE.get().expect("cannot access stderr during shutdown"),
};
- fn stderr_init() -> Arc<ReentrantMutex<RefCell<StderrRaw>>> {
- Arc::new(ReentrantMutex::new(RefCell::new(stderr_raw())))
+ fn stderr_init() -> Arc<ReentrantMutex<RefCell<Maybe<StderrRaw>>>> {
+ let stderr = match stderr_raw() {
+ Ok(stderr) => Maybe::Real(stderr),
+ _ => Maybe::Fake,
+ };
+ Arc::new(ReentrantMutex::new(RefCell::new(stderr)))
}
}
/// Copies the entire contents of a reader into a writer.
///
-/// This function will continuously read data from `r` and then write it into
-/// `w` in a streaming fashion until `r` returns EOF.
+/// This function will continuously read data from `reader` and then
+/// write it into `writer` in a streaming fashion until `reader`
+/// returns EOF.
///
-/// On success the total number of bytes that were copied from `r` to `w` is
-/// returned.
+/// On success, the total number of bytes that were copied from
+/// `reader` to `writer` is returned.
///
/// # Errors
///
/// `write` returns an error. All instances of `ErrorKind::Interrupted` are
/// handled by this function and the underlying operation is retried.
#[stable(feature = "rust1", since = "1.0.0")]
-pub fn copy<R: Read, W: Write>(r: &mut R, w: &mut W) -> io::Result<u64> {
+pub fn copy<R: Read, W: Write>(reader: &mut R, writer: &mut W) -> io::Result<u64> {
let mut buf = [0; super::DEFAULT_BUF_SIZE];
let mut written = 0;
loop {
- let len = match r.read(&mut buf) {
+ let len = match reader.read(&mut buf) {
Ok(0) => return Ok(written),
Ok(len) => len,
Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
Err(e) => return Err(e),
};
- try!(w.write_all(&buf[..len]));
+ try!(writer.write_all(&buf[..len]));
written += len as u64;
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl Read for Repeat {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
- for slot in buf.iter_mut() {
+ for slot in &mut *buf {
*slot = self.byte;
}
Ok(buf.len())
//!
//! ## What is in the standard library
//!
-//! The standard library is minimal, a set of battle-tested
+//! The standard library is a set of minimal, battle-tested
//! core types and shared abstractions for the [broader Rust
//! ecosystem](https://crates.io) to build on.
//!
//! [`FromStr`](str/trait.FromStr.html) trait.
//!
//! Data may be shared by placing it in a reference-counted box or the
-//! [`Rc`][rc/index.html] type, and if further contained in a [`Cell`
+//! [`Rc`](rc/index.html) type, and if further contained in a [`Cell`
//! or `RefCell`](cell/index.html), may be mutated as well as shared.
//! Likewise, in a concurrent setting it is common to pair an
//! atomically-reference-counted box, [`Arc`](sync/struct.Arc.html),
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
- html_favicon_url = "http://www.rust-lang.org/favicon.ico",
+ html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/",
- html_playground_url = "http://play.rust-lang.org/")]
-#![doc(test(no_crate_inject, attr(deny(warnings))))]
-#![doc(test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))))]
+ html_playground_url = "http://play.rust-lang.org/",
+ test(no_crate_inject, attr(deny(warnings))),
+ test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))))]
#![feature(alloc)]
#![feature(allow_internal_unstable)]
#![feature(associated_consts)]
+#![feature(borrow_state)]
+#![feature(box_raw)]
#![feature(box_syntax)]
+#![feature(char_internals)]
+#![feature(clone_from_slice)]
#![feature(collections)]
+#![feature(collections_bound)]
+#![feature(const_fn)]
#![feature(core)]
-#![feature(debug_builders)]
+#![feature(core_float)]
+#![feature(core_intrinsics)]
+#![feature(core_prelude)]
+#![feature(core_simd)]
+#![feature(fnbox)]
+#![feature(heap_api)]
+#![feature(int_error_internals)]
#![feature(into_cow)]
+#![feature(iter_order)]
#![feature(lang_items)]
#![feature(libc)]
#![feature(linkage, thread_local, asm)]
#![feature(macro_reexport)]
+#![feature(slice_concat_ext)]
+#![feature(slice_position_elem)]
+#![feature(no_std)]
+#![feature(oom)]
#![feature(optin_builtin_traits)]
#![feature(rand)]
+#![feature(raw)]
+#![feature(reflect_marker)]
+#![feature(slice_bytes)]
#![feature(slice_patterns)]
#![feature(staged_api)]
-#![feature(std_misc)]
#![feature(str_char)]
+#![feature(str_internals)]
#![feature(unboxed_closures)]
#![feature(unicode)]
#![feature(unique)]
#![feature(unsafe_no_drop_flag, filling_drop)]
+#![feature(vec_push_all)]
+#![feature(wrapping)]
#![feature(zero_one)]
-#![cfg_attr(test, feature(float_from_str_radix))]
-#![cfg_attr(test, feature(test, rustc_private, std_misc))]
+#![cfg_attr(windows, feature(str_utf16))]
+#![cfg_attr(test, feature(float_from_str_radix, range_inclusive, float_extras))]
+#![cfg_attr(test, feature(test, rustc_private, float_consts))]
// Don't link to std. We are std.
-#![feature(no_std)]
#![no_std]
#![allow(trivial_casts)]
//! library. Each macro is available for use when linking against the standard
//! library.
-#![unstable(feature = "std_misc")]
-
/// The entry point for panic of Rust threads.
///
/// This macro is used to inject panic into a Rust thread, causing the thread to
}
/// Helper macro for unwrapping `Result` values while returning early with an
-/// error if the value of the expression is `Err`.
+/// error if the value of the expression is `Err`. Can only be used in
+/// functions that return `Result` because of the early return of `Err` that
+/// it provides.
+///
+/// # Examples
+///
+/// ```
+/// use std::io;
+/// use std::fs::File;
+/// use std::io::prelude::*;
+///
+/// fn write_to_file_using_try() -> Result<(), io::Error> {
+/// let mut file = try!(File::create("my_best_friends.txt"));
+/// try!(file.write_all(b"This is a list of my best friends."));
+/// println!("I wrote to the file");
+/// Ok(())
+/// }
+/// // This is equivalent to:
+/// fn write_to_file_using_match() -> Result<(), io::Error> {
+/// let mut file = try!(File::create("my_best_friends.txt"));
+/// match file.write_all(b"This is a list of my best friends.") {
+/// Ok(_) => (),
+/// Err(e) => return Err(e),
+/// }
+/// println!("I wrote to the file");
+/// Ok(())
+/// }
+/// ```
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
macro_rules! try {
/// # Examples
///
/// ```
-/// # #![feature(std_misc)]
+/// # #![feature(mpsc_select)]
/// use std::thread;
/// use std::sync::mpsc;
///
///
/// For more information about select, see the `std::sync::mpsc::Select` structure.
#[macro_export]
-#[unstable(feature = "std_misc")]
+#[unstable(feature = "mpsc_select")]
macro_rules! select {
(
$($name:pat = $rx:ident.$meth:ident() => $code:expr),+
/// A macro which expands to the line number on which it was invoked.
///
- /// The expanded expression has type `usize`, and the returned line is not
+ /// The expanded expression has type `u32`, and the returned line is not
/// the invocation of the `line!()` macro itself, but rather the first macro
/// invocation leading up to the invocation of the `line!()` macro.
///
/// A macro which expands to the column number on which it was invoked.
///
- /// The expanded expression has type `usize`, and the returned column is not
+ /// The expanded expression has type `u32`, and the returned column is not
/// the invocation of the `column!()` macro itself, but rather the first macro
/// invocation leading up to the invocation of the `column!()` macro.
///
mod parser;
#[cfg(test)] mod test;
-/// Possible values which can be passed to the `shutdown` method of `TcpStream`
-/// and `UdpSocket`.
+/// Possible values which can be passed to the `shutdown` method of `TcpStream`.
#[derive(Copy, Clone, PartialEq, Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
pub enum Shutdown {
// Return result of first successful parser
fn read_or<T>(&mut self, parsers: &mut [Box<FnMut(&mut Parser) -> Option<T> + 'static>])
-> Option<T> {
- for pf in parsers.iter_mut() {
+ for pf in parsers {
match self.read_atomically(|p: &mut Parser| pf(p)) {
Some(r) => return Some(r),
None => {}
use net::{ToSocketAddrs, SocketAddr, Shutdown};
use sys_common::net as net_imp;
use sys_common::{AsInner, FromInner};
+use time::Duration;
/// A structure which represents a TCP stream between a local socket and a
/// remote socket.
pub fn set_keepalive(&self, seconds: Option<u32>) -> io::Result<()> {
self.0.set_keepalive(seconds)
}
+
+ /// Sets the read timeout to the timeout specified.
+ ///
+ /// If the value specified is `None`, then `read` calls will block
+ /// indefinitely. It is an error to pass the zero `Duration` to this
+ /// method.
+ #[unstable(feature = "socket_timeout", reason = "RFC 1047 - recently added")]
+ pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
+ self.0.set_read_timeout(dur)
+ }
+
+ /// Sets the write timeout to the timeout specified.
+ ///
+ /// If the value specified is `None`, then `write` calls will block
+ /// indefinitely. It is an error to pass the zero `Duration` to this
+ /// method.
+ #[unstable(feature = "socket_timeout", reason = "RFC 1047 - recently added")]
+ pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
+ self.0.set_write_timeout(dur)
+ }
+
+ /// Returns the read timeout of this socket.
+ ///
+ /// If the timeout is `None`, then `read` calls will block indefinitely.
+ ///
+ /// # Note
+ ///
+ /// Some platforms do not provide access to the current timeout.
+ #[unstable(feature = "socket_timeout", reason = "RFC 1047 - recently added")]
+ pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+ self.0.read_timeout()
+ }
+
+ /// Returns the write timeout of this socket.
+ ///
+ /// If the timeout is `None`, then `write` calls will block indefinitely.
+ ///
+ /// # Note
+ ///
+ /// Some platforms do not provide access to the current timeout.
+ #[unstable(feature = "socket_timeout", reason = "RFC 1047 - recently added")]
+ pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+ self.0.write_timeout()
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
use net::test::{next_test_ip4, next_test_ip6};
use sync::mpsc::channel;
use sys_common::AsInner;
+ use time::Duration;
use thread;
fn each_ip(f: &mut FnMut(SocketAddr)) {
#[test]
fn multiple_connect_interleaved_greedy_schedule() {
- static MAX: usize = 10;
+ const MAX: usize = 10;
each_ip(&mut |addr| {
let acceptor = t!(TcpListener::bind(&addr));
socket_addr, name, listener_inner);
assert_eq!(format!("{:?}", listener), compare);
- let mut stream = t!(TcpStream::connect(&("localhost",
+ let stream = t!(TcpStream::connect(&("localhost",
socket_addr.port())));
let stream_inner = stream.0.socket().as_inner();
let compare = format!("TcpStream {{ addr: {:?}, \
stream_inner);
assert_eq!(format!("{:?}", stream), compare);
}
+
+ // FIXME: re-enabled bitrig/openbsd tests once their socket timeout code
+ // no longer has rounding errors.
+ #[cfg_attr(any(target_os = "bitrig", target_os = "openbsd"), ignore)]
+ #[test]
+ fn timeouts() {
+ let addr = next_test_ip4();
+ let listener = t!(TcpListener::bind(&addr));
+
+ let stream = t!(TcpStream::connect(&("localhost", addr.port())));
+ let dur = Duration::new(15410, 0);
+
+ assert_eq!(None, t!(stream.read_timeout()));
+
+ t!(stream.set_read_timeout(Some(dur)));
+ assert_eq!(Some(dur), t!(stream.read_timeout()));
+
+ assert_eq!(None, t!(stream.write_timeout()));
+
+ t!(stream.set_write_timeout(Some(dur)));
+ assert_eq!(Some(dur), t!(stream.write_timeout()));
+
+ t!(stream.set_read_timeout(None));
+ assert_eq!(None, t!(stream.read_timeout()));
+
+ t!(stream.set_write_timeout(None));
+ assert_eq!(None, t!(stream.write_timeout()));
+ }
+
+ #[test]
+ fn test_read_timeout() {
+ let addr = next_test_ip4();
+ let listener = t!(TcpListener::bind(&addr));
+
+ let mut stream = t!(TcpStream::connect(&("localhost", addr.port())));
+ t!(stream.set_read_timeout(Some(Duration::from_millis(1000))));
+
+ let mut buf = [0; 10];
+ let wait = Duration::span(|| {
+ let kind = stream.read(&mut buf).err().expect("expected error").kind();
+ assert!(kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut);
+ });
+ assert!(wait > Duration::from_millis(400));
+ assert!(wait < Duration::from_millis(1600));
+ }
+
+ #[test]
+ fn test_read_with_timeout() {
+ let addr = next_test_ip4();
+ let listener = t!(TcpListener::bind(&addr));
+
+ let mut stream = t!(TcpStream::connect(&("localhost", addr.port())));
+ t!(stream.set_read_timeout(Some(Duration::from_millis(1000))));
+
+ let mut other_end = t!(listener.accept()).0;
+ t!(other_end.write_all(b"hello world"));
+
+ let mut buf = [0; 11];
+ t!(stream.read(&mut buf));
+ assert_eq!(b"hello world", &buf[..]);
+
+ let wait = Duration::span(|| {
+ let kind = stream.read(&mut buf).err().expect("expected error").kind();
+ assert!(kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut);
+ });
+ assert!(wait > Duration::from_millis(400));
+ assert!(wait < Duration::from_millis(1600));
+ }
}
use env;
use net::{SocketAddr, SocketAddrV4, SocketAddrV6, Ipv4Addr, Ipv6Addr, ToSocketAddrs};
-use sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
+use sync::atomic::{AtomicUsize, Ordering};
-static PORT: AtomicUsize = ATOMIC_USIZE_INIT;
+static PORT: AtomicUsize = AtomicUsize::new(0);
pub fn next_test_ip4() -> SocketAddr {
let port = PORT.fetch_add(1, Ordering::SeqCst) as u16 + base_port();
use net::{ToSocketAddrs, SocketAddr, IpAddr};
use sys_common::net as net_imp;
use sys_common::{AsInner, FromInner};
+use time::Duration;
/// A User Datagram Protocol socket.
///
pub fn set_time_to_live(&self, ttl: i32) -> io::Result<()> {
self.0.time_to_live(ttl)
}
+
+ /// Sets the read timeout to the timeout specified.
+ ///
+ /// If the value specified is `None`, then `read` calls will block
+ /// indefinitely. It is an error to pass the zero `Duration` to this
+ /// method.
+ #[unstable(feature = "socket_timeout", reason = "RFC 1047 - recently added")]
+ pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
+ self.0.set_read_timeout(dur)
+ }
+
+ /// Sets the write timeout to the timeout specified.
+ ///
+ /// If the value specified is `None`, then `write` calls will block
+ /// indefinitely. It is an error to pass the zero `Duration` to this
+ /// method.
+ #[unstable(feature = "socket_timeout", reason = "RFC 1047 - recently added")]
+ pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
+ self.0.set_write_timeout(dur)
+ }
+
+ /// Returns the read timeout of this socket.
+ ///
+ /// If the timeout is `None`, then `read` calls will block indefinitely.
+ #[unstable(feature = "socket_timeout", reason = "RFC 1047 - recently added")]
+ pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+ self.0.read_timeout()
+ }
+
+ /// Returns the write timeout of this socket.
+ ///
+ /// If the timeout is `None`, then `write` calls will block indefinitely.
+ #[unstable(feature = "socket_timeout", reason = "RFC 1047 - recently added")]
+ pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+ self.0.write_timeout()
+ }
}
impl AsInner<net_imp::UdpSocket> for UdpSocket {
use net::test::{next_test_ip4, next_test_ip6};
use sync::mpsc::channel;
use sys_common::AsInner;
+ use time::Duration;
use thread;
fn each_ip(f: &mut FnMut(SocketAddr, SocketAddr)) {
socket_addr, name, udpsock_inner);
assert_eq!(format!("{:?}", udpsock), compare);
}
+
+ // FIXME: re-enabled bitrig/openbsd tests once their socket timeout code
+ // no longer has rounding errors.
+ #[cfg_attr(any(target_os = "bitrig", target_os = "openbsd"), ignore)]
+ #[test]
+ fn timeouts() {
+ let addr = next_test_ip4();
+
+ let stream = t!(UdpSocket::bind(&addr));
+ let dur = Duration::new(15410, 0);
+
+ assert_eq!(None, t!(stream.read_timeout()));
+
+ t!(stream.set_read_timeout(Some(dur)));
+ assert_eq!(Some(dur), t!(stream.read_timeout()));
+
+ assert_eq!(None, t!(stream.write_timeout()));
+
+ t!(stream.set_write_timeout(Some(dur)));
+ assert_eq!(Some(dur), t!(stream.write_timeout()));
+
+ t!(stream.set_read_timeout(None));
+ assert_eq!(None, t!(stream.read_timeout()));
+
+ t!(stream.set_write_timeout(None));
+ assert_eq!(None, t!(stream.write_timeout()));
+ }
+
+ #[test]
+ fn test_read_timeout() {
+ let addr = next_test_ip4();
+
+ let mut stream = t!(UdpSocket::bind(&addr));
+ t!(stream.set_read_timeout(Some(Duration::from_millis(1000))));
+
+ let mut buf = [0; 10];
+ let wait = Duration::span(|| {
+ let kind = stream.recv_from(&mut buf).err().expect("expected error").kind();
+ assert!(kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut);
+ });
+ assert!(wait > Duration::from_millis(400));
+ assert!(wait < Duration::from_millis(1600));
+ }
+
+ #[test]
+ fn test_read_with_timeout() {
+ let addr = next_test_ip4();
+
+ let mut stream = t!(UdpSocket::bind(&addr));
+ t!(stream.set_read_timeout(Some(Duration::from_millis(1000))));
+
+ t!(stream.send_to(b"hello world", &addr));
+
+ let mut buf = [0; 11];
+ t!(stream.recv_from(&mut buf));
+ assert_eq!(b"hello world", &buf[..]);
+
+ let wait = Duration::span(|| {
+ let kind = stream.recv_from(&mut buf).err().expect("expected error").kind();
+ assert!(kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut);
+ });
+ assert!(wait > Duration::from_millis(400));
+ assert!(wait < Duration::from_millis(1600));
+ }
}
mod cmath {
use libc::{c_float, c_int};
- #[link_name = "m"]
extern {
pub fn acosf(n: c_float) -> c_float;
pub fn asinf(n: c_float) -> c_float;
pub fn erfcf(n: c_float) -> c_float;
pub fn expm1f(n: c_float) -> c_float;
pub fn fdimf(a: c_float, b: c_float) -> c_float;
- pub fn frexpf(n: c_float, value: &mut c_int) -> c_float;
pub fn fmaxf(a: c_float, b: c_float) -> c_float;
pub fn fminf(a: c_float, b: c_float) -> c_float;
pub fn fmodf(a: c_float, b: c_float) -> c_float;
pub fn nextafterf(x: c_float, y: c_float) -> c_float;
- pub fn hypotf(x: c_float, y: c_float) -> c_float;
- pub fn ldexpf(x: c_float, n: c_int) -> c_float;
pub fn logbf(n: c_float) -> c_float;
pub fn log1pf(n: c_float) -> c_float;
pub fn ilogbf(n: c_float) -> c_int;
pub fn tanhf(n: c_float) -> c_float;
pub fn tgammaf(n: c_float) -> c_float;
- #[cfg(unix)]
+ #[cfg_attr(all(windows, target_env = "msvc"), link_name = "__lgammaf_r")]
pub fn lgammaf_r(n: c_float, sign: &mut c_int) -> c_float;
+ #[cfg_attr(all(windows, target_env = "msvc"), link_name = "_hypotf")]
+ pub fn hypotf(x: c_float, y: c_float) -> c_float;
- #[cfg(windows)]
- #[link_name="__lgammaf_r"]
- pub fn lgammaf_r(n: c_float, sign: &mut c_int) -> c_float;
+ #[cfg(any(unix, all(windows, not(target_env = "msvc"))))]
+ pub fn frexpf(n: c_float, value: &mut c_int) -> c_float;
+ #[cfg(any(unix, all(windows, not(target_env = "msvc"))))]
+ pub fn ldexpf(x: c_float, n: c_int) -> c_float;
+ }
+
+ #[cfg(all(windows, target_env = "msvc"))]
+ pub unsafe fn ldexpf(x: c_float, n: c_int) -> c_float {
+ f64::ldexp(x as f64, n as isize) as c_float
+ }
+
+ #[cfg(all(windows, target_env = "msvc"))]
+ pub unsafe fn frexpf(x: c_float, value: &mut c_int) -> c_float {
+ let (a, b) = f64::frexp(x as f64);
+ *value = b as c_int;
+ a as c_float
}
}
/// The floating point encoding is documented in the [Reference][floating-point].
///
/// ```
- /// # #![feature(std_misc)]
+ /// # #![feature(float_extras)]
/// use std::f32;
///
/// let num = 2.0f32;
/// assert!(abs_difference <= f32::EPSILON);
/// ```
/// [floating-point]: ../../../../../reference.html#machine-types
- #[unstable(feature = "std_misc", reason = "signature is undecided")]
+ #[unstable(feature = "float_extras", reason = "signature is undecided")]
#[inline]
- pub fn integer_decode(self) -> (u64, i16, i8) { num::Float::integer_decode(self) }
+ pub fn integer_decode(self) -> (u64, i16, i8) {
+ num::Float::integer_decode(self)
+ }
/// Returns the largest integer less than or equal to a number.
///
/// Converts radians to degrees.
///
/// ```
- /// # #![feature(std_misc)]
+ /// # #![feature(float_extras)]
/// use std::f32::{self, consts};
///
/// let angle = consts::PI;
///
/// assert!(abs_difference <= f32::EPSILON);
/// ```
- #[unstable(feature = "std_misc", reason = "desirability is unclear")]
+ #[unstable(feature = "float_extras", reason = "desirability is unclear")]
#[inline]
pub fn to_degrees(self) -> f32 { num::Float::to_degrees(self) }
/// Converts degrees to radians.
///
/// ```
- /// # #![feature(std_misc)]
+ /// # #![feature(float_extras)]
/// use std::f32::{self, consts};
///
/// let angle = 180.0f32;
///
/// assert!(abs_difference <= f32::EPSILON);
/// ```
- #[unstable(feature = "std_misc", reason = "desirability is unclear")]
+ #[unstable(feature = "float_extras", reason = "desirability is unclear")]
#[inline]
pub fn to_radians(self) -> f32 { num::Float::to_radians(self) }
/// Constructs a floating point number of `x*2^exp`.
///
/// ```
- /// # #![feature(std_misc)]
+ /// # #![feature(float_extras)]
/// use std::f32;
/// // 3*2^2 - 12 == 0
/// let abs_difference = (f32::ldexp(3.0, 2) - 12.0).abs();
///
/// assert!(abs_difference <= f32::EPSILON);
/// ```
- #[unstable(feature = "std_misc",
+ #[unstable(feature = "float_extras",
reason = "pending integer conventions")]
#[inline]
pub fn ldexp(x: f32, exp: isize) -> f32 {
/// * `0.5 <= abs(x) < 1.0`
///
/// ```
- /// # #![feature(std_misc)]
+ /// # #![feature(float_extras)]
/// use std::f32;
///
/// let x = 4.0f32;
/// assert!(abs_difference_0 <= f32::EPSILON);
/// assert!(abs_difference_1 <= f32::EPSILON);
/// ```
- #[unstable(feature = "std_misc",
+ #[unstable(feature = "float_extras",
reason = "pending integer conventions")]
#[inline]
pub fn frexp(self) -> (f32, isize) {
/// `other`.
///
/// ```
- /// # #![feature(std_misc)]
+ /// # #![feature(float_extras)]
/// use std::f32;
///
/// let x = 1.0f32;
///
/// assert!(abs_diff <= f32::EPSILON);
/// ```
- #[unstable(feature = "std_misc",
+ #[unstable(feature = "float_extras",
reason = "unsure about its place in the world")]
#[inline]
pub fn next_after(self, other: f32) -> f32 {
///
/// assert_eq!(x.max(y), y);
/// ```
+ ///
+ /// If one of the arguments is NaN, then the other argument is returned.
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn max(self, other: f32) -> f32 {
///
/// assert_eq!(x.min(y), x);
/// ```
+ ///
+ /// If one of the arguments is NaN, then the other argument is returned.
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn min(self, other: f32) -> f32 {
pub fn fmod(a: c_double, b: c_double) -> c_double;
pub fn nextafter(x: c_double, y: c_double) -> c_double;
pub fn frexp(n: c_double, value: &mut c_int) -> c_double;
- pub fn hypot(x: c_double, y: c_double) -> c_double;
pub fn ldexp(x: c_double, n: c_int) -> c_double;
pub fn logb(n: c_double) -> c_double;
pub fn log1p(n: c_double) -> c_double;
pub fn y1(n: c_double) -> c_double;
pub fn yn(i: c_int, n: c_double) -> c_double;
- #[cfg(unix)]
- pub fn lgamma_r(n: c_double, sign: &mut c_int) -> c_double;
- #[cfg(windows)]
- #[link_name="__lgamma_r"]
+ #[cfg_attr(all(windows, target_env = "msvc"), link_name = "__lgamma_r")]
pub fn lgamma_r(n: c_double, sign: &mut c_int) -> c_double;
+
+ #[cfg_attr(all(windows, target_env = "msvc"), link_name = "_hypot")]
+ pub fn hypot(x: c_double, y: c_double) -> c_double;
}
}
/// The floating point encoding is documented in the [Reference][floating-point].
///
/// ```
- /// # #![feature(std_misc)]
+ /// # #![feature(float_extras)]
/// let num = 2.0f64;
///
/// // (8388608, -22, 1)
/// assert!(abs_difference < 1e-10);
/// ```
/// [floating-point]: ../../../../../reference.html#machine-types
- #[unstable(feature = "std_misc", reason = "signature is undecided")]
+ #[unstable(feature = "float_extras", reason = "signature is undecided")]
#[inline]
pub fn integer_decode(self) -> (u64, i16, i8) { num::Float::integer_decode(self) }
/// Constructs a floating point number of `x*2^exp`.
///
/// ```
- /// # #![feature(std_misc)]
+ /// # #![feature(float_extras)]
/// // 3*2^2 - 12 == 0
/// let abs_difference = (f64::ldexp(3.0, 2) - 12.0).abs();
///
/// assert!(abs_difference < 1e-10);
/// ```
- #[unstable(feature = "std_misc",
+ #[unstable(feature = "float_extras",
reason = "pending integer conventions")]
#[inline]
pub fn ldexp(x: f64, exp: isize) -> f64 {
/// * `0.5 <= abs(x) < 1.0`
///
/// ```
- /// # #![feature(std_misc)]
+ /// # #![feature(float_extras)]
/// let x = 4.0_f64;
///
/// // (1/2)*2^3 -> 1 * 8/2 -> 4.0
/// assert!(abs_difference_0 < 1e-10);
/// assert!(abs_difference_1 < 1e-10);
/// ```
- #[unstable(feature = "std_misc",
+ #[unstable(feature = "float_extras",
reason = "pending integer conventions")]
#[inline]
pub fn frexp(self) -> (f64, isize) {
/// `other`.
///
/// ```
- /// # #![feature(std_misc)]
+ /// # #![feature(float_extras)]
///
/// let x = 1.0f32;
///
///
/// assert!(abs_diff < 1e-10);
/// ```
- #[unstable(feature = "std_misc",
+ #[unstable(feature = "float_extras",
reason = "unsure about its place in the world")]
#[inline]
pub fn next_after(self, other: f64) -> f64 {
///
/// assert_eq!(x.max(y), y);
/// ```
+ ///
+ /// If one of the arguments is NaN, then the other argument is returned.
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn max(self, other: f64) -> f64 {
///
/// assert_eq!(x.min(y), x);
/// ```
+ ///
+ /// If one of the arguments is NaN, then the other argument is returned.
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn min(self, other: f64) -> f64 {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![unstable(feature = "std_misc")]
#![doc(hidden)]
macro_rules! assert_approx_eq {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![unstable(feature = "std_misc")]
#![doc(hidden)]
macro_rules! int_module { ($T:ty) => (
// except according to those terms.
//! Operations and constants for pointer-sized signed integers (`isize` type)
-//!
-//! This type was recently added to replace `int`. The rollout of the
-//! new type will gradually take place over the alpha cycle along with
-//! the development of clearer conventions around integer types.
#![stable(feature = "rust1", since = "1.0.0")]
#![doc(primitive = "isize")]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![unstable(feature = "std_misc")]
#![doc(hidden)]
#![allow(unsigned_negation)]
// except according to those terms.
//! Operations and constants for pointer-sized unsigned integers (`usize` type)
-//!
-//! This type was recently added to replace `uint`. The rollout of the
-//! new type will gradually take place over the alpha cycle along with
-//! the development of clearer conventions around integer types.
#![stable(feature = "rust1", since = "1.0.0")]
#![doc(primitive = "usize")]
#![stable(feature = "raw_ext", since = "1.1.0")]
-use os::raw::{c_uint, c_uchar, c_ulonglong, c_longlong, c_ulong};
-use os::unix::raw::{uid_t, gid_t};
+#[doc(inline)]
+pub use self::arch::{dev_t, mode_t, blkcnt_t, blksize_t, ino_t, nlink_t, off_t, stat, time_t};
-#[stable(feature = "raw_ext", since = "1.1.0")]
-pub type blkcnt_t = u32;
-#[stable(feature = "raw_ext", since = "1.1.0")]
-pub type blksize_t = u32;
-#[stable(feature = "raw_ext", since = "1.1.0")]
-pub type dev_t = u32;
-#[stable(feature = "raw_ext", since = "1.1.0")]
-pub type ino_t = u32;
-#[stable(feature = "raw_ext", since = "1.1.0")]
-pub type mode_t = u16;
-#[stable(feature = "raw_ext", since = "1.1.0")]
-pub type nlink_t = u16;
-#[stable(feature = "raw_ext", since = "1.1.0")]
-pub type off_t = i32;
-#[stable(feature = "raw_ext", since = "1.1.0")]
-pub type time_t = i32;
+#[cfg(target_arch = "arm")]
+mod arch {
+ use os::raw::{c_uint, c_uchar, c_ulonglong, c_longlong, c_ulong};
+ use os::unix::raw::{uid_t, gid_t};
-#[repr(C)]
-#[stable(feature = "raw_ext", since = "1.1.0")]
-pub struct stat {
#[stable(feature = "raw_ext", since = "1.1.0")]
- pub st_dev: c_ulonglong,
+ pub type dev_t = u32;
#[stable(feature = "raw_ext", since = "1.1.0")]
- pub __pad0: [c_uchar; 4],
- #[stable(feature = "raw_ext", since = "1.1.0")]
- pub __st_ino: ino_t,
- #[stable(feature = "raw_ext", since = "1.1.0")]
- pub st_mode: c_uint,
- #[stable(feature = "raw_ext", since = "1.1.0")]
- pub st_nlink: c_uint,
+ pub type mode_t = u16;
+
#[stable(feature = "raw_ext", since = "1.1.0")]
- pub st_uid: uid_t,
+ pub type blkcnt_t = u32;
#[stable(feature = "raw_ext", since = "1.1.0")]
- pub st_gid: gid_t,
+ pub type blksize_t = u32;
#[stable(feature = "raw_ext", since = "1.1.0")]
- pub st_rdev: c_ulonglong,
+ pub type ino_t = u32;
#[stable(feature = "raw_ext", since = "1.1.0")]
- pub __pad3: [c_uchar; 4],
+ pub type nlink_t = u16;
#[stable(feature = "raw_ext", since = "1.1.0")]
- pub st_size: c_longlong,
+ pub type off_t = i32;
#[stable(feature = "raw_ext", since = "1.1.0")]
- pub st_blksize: blksize_t,
+ pub type time_t = i32;
+
+ #[repr(C)]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: c_ulonglong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad0: [c_uchar; 4],
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __st_ino: ino_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: c_uint,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: c_uint,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: uid_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: gid_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: c_ulonglong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad3: [c_uchar; 4],
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: c_longlong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: blksize_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: c_ulonglong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: c_ulonglong,
+ }
+
+}
+
+
+#[cfg(target_arch = "aarch64")]
+mod arch {
+ use os::raw::{c_uchar, c_ulong};
+ use os::unix::raw::{uid_t, gid_t};
+
#[stable(feature = "raw_ext", since = "1.1.0")]
- pub st_blocks: c_ulonglong,
+ pub type dev_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")]
- pub st_atime: time_t,
+ pub type mode_t = u32;
+
#[stable(feature = "raw_ext", since = "1.1.0")]
- pub st_atime_nsec: c_ulong,
+ pub type blkcnt_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")]
- pub st_mtime: time_t,
+ pub type blksize_t = u32;
#[stable(feature = "raw_ext", since = "1.1.0")]
- pub st_mtime_nsec: c_ulong,
+ pub type ino_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")]
- pub st_ctime: time_t,
+ pub type nlink_t = u32;
#[stable(feature = "raw_ext", since = "1.1.0")]
- pub st_ctime_nsec: c_ulong,
+ pub type off_t = i64;
#[stable(feature = "raw_ext", since = "1.1.0")]
- pub st_ino: c_ulonglong,
+ pub type time_t = i64;
+
+ #[repr(C)]
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub struct stat {
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_dev: dev_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad0: [c_uchar; 4],
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __st_ino: ino_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mode: mode_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_nlink: nlink_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_uid: uid_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_gid: gid_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_rdev: dev_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub __pad3: [c_uchar; 4],
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_size: off_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blksize: blksize_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_blocks: blkcnt_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_atime_nsec: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_mtime_nsec: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ctime_nsec: c_ulong,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_ino: ino_t,
+ }
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![unstable(feature = "std_misc")]
-
use prelude::v1::*;
use io::prelude::*;
None => "Box<Any>",
}
};
- let mut err = Stderr::new();
+ let mut err = Stderr::new().ok();
let thread = thread_info::current_thread();
let name = thread.as_ref().and_then(|t| t.name()).unwrap_or("<unnamed>");
let prev = LOCAL_STDERR.with(|s| s.borrow_mut().take());
- match prev {
- Some(mut stderr) => {
+ match (prev, err.as_mut()) {
+ (Some(mut stderr), _) => {
// FIXME: what to do when the thread printing panics?
let _ = writeln!(stderr,
"thread '{}' panicked at '{}', {}:{}\n",
*slot.borrow_mut() = s.take();
});
}
- None => {
- let _ = writeln!(&mut err, "thread '{}' panicked at '{}', {}:{}",
+ (None, Some(ref mut err)) => {
+ let _ = writeln!(err, "thread '{}' panicked at '{}', {}:{}",
name, msg, file, line);
if backtrace::log_enabled() {
- let _ = backtrace::write(&mut err);
+ let _ = backtrace::write(err);
}
}
+ _ => {}
}
// If this is a double panic, make sure that we printed a backtrace
// for this panic.
- if unwind::panicking() && !backtrace::log_enabled() {
- let _ = backtrace::write(&mut err);
+ match err {
+ Some(ref mut err) if unwind::panicking() && !backtrace::log_enabled() => {
+ let _ = backtrace::write(err);
+ }
+ _ => {}
}
}
/// Path prefixes (Windows only).
///
/// Windows uses a variety of path styles, including references to drive
-/// volumes (like `C:`), network shared (like `\\server\share`) and
+/// volumes (like `C:`), network shared folders (like `\\server\share`) and
/// others. In addition, some path prefixes are "verbatim", in which case
/// `/` is *not* treated as a separator and essentially no normalization is
/// performed.
}
- /// Determines if the prefix is verbatim, i.e. begins `\\?\`.
+ /// Determines if the prefix is verbatim, i.e. begins with `\\?\`.
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn is_verbatim(&self) -> bool {
use self::Prefix::*;
match *self {
Verbatim(_) | VerbatimDisk(_) | VerbatimUNC(_, _) => true,
- _ => false
+ _ => false,
}
}
/// ```
/// use std::path::Path;
///
- /// let s = String::from("bar.txt");
- /// let p = Path::new(&s);
- /// Path::new(&p);
+ /// let string = String::from("foo.txt");
+ /// let from_string = Path::new(&string);
+ /// let from_path = Path::new(&from_string);
+ /// assert_eq!(from_string, from_path);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new<S: AsRef<OsStr> + ?Sized>(s: &S) -> &Path {
/// use std::path::Path;
///
/// let os_str = Path::new("foo.txt").as_os_str();
+ /// assert_eq!(os_str, std::ffi::OsStr::new("foo.txt"));
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn as_os_str(&self) -> &OsStr {
/// use std::path::Path;
///
/// let path_str = Path::new("foo.txt").to_str();
+ //// assert_eq!(path_str, Some("foo.txt"));
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn to_str(&self) -> Option<&str> {
/// use std::path::Path;
///
/// let path_str = Path::new("foo.txt").to_string_lossy();
+ /// assert_eq!(path_str, "foo.txt");
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn to_string_lossy(&self) -> Cow<str> {
/// ```
/// use std::path::Path;
///
- /// let path_str = Path::new("foo.txt").to_path_buf();
+ /// let path_buf = Path::new("foo.txt").to_path_buf();
+ /// assert_eq!(path_buf, std::path::PathBuf::from("foo.txt"));
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn to_path_buf(&self) -> PathBuf {
/// ```
/// use std::path::Path;
///
- /// assert_eq!(false, Path::new("foo.txt").is_absolute());
+ /// assert!(!Path::new("foo.txt").is_absolute());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn is_absolute(&self) -> bool {
/// use std::path::Path;
///
/// let path = Path::new("/foo/bar");
- /// let foo = path.parent().unwrap();
- ///
- /// assert!(foo == Path::new("/foo"));
+ /// let parent = path.parent().unwrap();
+ /// assert_eq!(parent, Path::new("/foo"));
///
- /// let root = foo.parent().unwrap();
- ///
- /// assert!(root == Path::new("/"));
- /// assert!(root.parent() == None);
+ /// let grand_parent = parent.parent().unwrap();
+ /// assert_eq!(grand_parent, Path::new("/"));
+ /// assert_eq!(grand_parent.parent(), None);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn parent(&self) -> Option<&Path> {
/// The final component of the path, if it is a normal file.
///
- /// If the path terminates in `.`, `..`, or consists solely or a root of
+ /// If the path terminates in `.`, `..`, or consists solely of a root of
/// prefix, `file_name` will return `None`.
///
/// # Examples
///
/// ```
/// use std::path::Path;
+ /// use std::ffi::OsStr;
///
- /// let path = Path::new("hello_world.rs");
- /// let filename = "hello_world.rs";
+ /// let path = Path::new("foo.txt");
+ /// let os_str = OsStr::new("foo.txt");
///
- /// assert_eq!(filename, path.file_name().unwrap());
+ /// assert_eq!(Some(os_str), path.file_name());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn file_name(&self) -> Option<&OsStr> {
iter_after(self.components().rev(), child.as_ref().components().rev()).is_some()
}
- /// Extracts the stem (non-extension) portion of `self.file()`.
+ /// Extracts the stem (non-extension) portion of `self.file_name()`.
///
/// The stem is:
///
self.file_name().map(split_file_at_dot).and_then(|(before, after)| before.or(after))
}
- /// Extracts the extension of `self.file()`, if possible.
+ /// Extracts the extension of `self.file_name()`, if possible.
///
/// The extension is:
///
/// # Examples
///
/// ```
- /// use std::path::Path;
- ///
- /// let path = Path::new("/tmp");
+ /// use std::path::{Path, PathBuf};
///
- /// let new_path = path.join("foo");
+ /// assert_eq!(Path::new("/etc").join("passwd"), PathBuf::from("/etc/passwd"));
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn join<P: AsRef<Path>>(&self, path: P) -> PathBuf {
/// # Examples
///
/// ```
- /// use std::path::Path;
- ///
- /// let path = Path::new("/tmp/foo.rs");
+ /// use std::path::{Path, PathBuf};
///
- /// let new_path = path.with_file_name("bar.rs");
+ /// let path = Path::new("/tmp/foo.txt");
+ /// assert_eq!(path.with_file_name("bar.txt"), PathBuf::from("/tmp/bar.txt"));
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn with_file_name<S: AsRef<OsStr>>(&self, file_name: S) -> PathBuf {
/// ```
/// use std::path::{Path, PathBuf};
///
- /// let path = Path::new("/tmp/foo.rs");
- ///
- /// let new_path = path.with_extension("txt");
- /// assert_eq!(new_path, PathBuf::from("/tmp/foo.txt"));
+ /// let path = Path::new("foo.rs");
+ /// assert_eq!(path.with_extension("txt"), PathBuf::from("foo.txt"));
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn with_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf {
/// # Examples
///
/// ```
- /// use std::path::Path;
+ /// use std::path::{Path, Component};
+ /// use std::ffi::OsStr;
///
- /// let path = Path::new("/tmp/foo.rs");
+ /// let mut components = Path::new("/tmp/foo.txt").components();
///
- /// for component in path.components() {
- /// println!("{:?}", component);
- /// }
+ /// assert_eq!(components.next(), Some(Component::RootDir));
+ /// assert_eq!(components.next(), Some(Component::Normal(OsStr::new("tmp"))));
+ /// assert_eq!(components.next(), Some(Component::Normal(OsStr::new("foo.txt"))));
+ /// assert_eq!(components.next(), None)
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn components(&self) -> Components {
/// # Examples
///
/// ```
- /// use std::path::Path;
- ///
- /// let path = Path::new("/tmp/foo.rs");
- ///
- /// for component in path.iter() {
- /// println!("{:?}", component);
- /// }
+ /// use std::path::{self, Path};
+ /// use std::ffi::OsStr;
+ ///
+ /// let mut it = Path::new("/tmp/foo.txt").iter();
+ /// assert_eq!(it.next(), Some(OsStr::new(&path::MAIN_SEPARATOR.to_string())));
+ /// assert_eq!(it.next(), Some(OsStr::new("tmp")));
+ /// assert_eq!(it.next(), Some(OsStr::new("foo.txt")));
+ /// assert_eq!(it.next(), None)
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn iter(&self) -> Iter {
use path;
use sync::mpsc::{channel, Receiver};
use sys::pipe::{self, AnonPipe};
-use sys::process::Command as CommandImp;
-use sys::process::Process as ProcessImp;
-use sys::process::ExitStatus as ExitStatusImp;
-use sys::process::Stdio as StdioImp2;
-use sys_common::{AsInner, AsInnerMut};
+use sys::process as imp;
+use sys_common::{AsInner, AsInnerMut, FromInner};
use thread;
/// Representation of a running or exited child process.
/// ```
#[stable(feature = "process", since = "1.0.0")]
pub struct Child {
- handle: ProcessImp,
+ handle: imp::Process,
/// None until wait() or wait_with_output() is called.
- status: Option<ExitStatusImp>,
+ status: Option<imp::ExitStatus>,
/// The handle for writing to the child's stdin, if it has been captured
#[stable(feature = "process", since = "1.0.0")]
pub stderr: Option<ChildStderr>,
}
+impl AsInner<imp::Process> for Child {
+ fn as_inner(&self) -> &imp::Process { &self.handle }
+}
+
/// A handle to a child procesess's stdin
#[stable(feature = "process", since = "1.0.0")]
pub struct ChildStdin {
}
}
+impl AsInner<AnonPipe> for ChildStdin {
+ fn as_inner(&self) -> &AnonPipe { &self.inner }
+}
+
/// A handle to a child procesess's stdout
#[stable(feature = "process", since = "1.0.0")]
pub struct ChildStdout {
}
}
+impl AsInner<AnonPipe> for ChildStdout {
+ fn as_inner(&self) -> &AnonPipe { &self.inner }
+}
+
/// A handle to a child procesess's stderr
#[stable(feature = "process", since = "1.0.0")]
pub struct ChildStderr {
}
}
+impl AsInner<AnonPipe> for ChildStderr {
+ fn as_inner(&self) -> &AnonPipe { &self.inner }
+}
+
/// The `Command` type acts as a process builder, providing fine-grained control
/// over how a new process should be spawned. A default configuration can be
/// generated using `Command::new(program)`, where `program` gives a path to the
/// ```
#[stable(feature = "process", since = "1.0.0")]
pub struct Command {
- inner: CommandImp,
+ inner: imp::Command,
// Details explained in the builder methods
- stdin: Option<StdioImp>,
- stdout: Option<StdioImp>,
- stderr: Option<StdioImp>,
+ stdin: Option<Stdio>,
+ stdout: Option<Stdio>,
+ stderr: Option<Stdio>,
}
impl Command {
#[stable(feature = "process", since = "1.0.0")]
pub fn new<S: AsRef<OsStr>>(program: S) -> Command {
Command {
- inner: CommandImp::new(program.as_ref()),
+ inner: imp::Command::new(program.as_ref()),
stdin: None,
stdout: None,
stderr: None,
/// Configuration for the child process's stdin handle (file descriptor 0).
#[stable(feature = "process", since = "1.0.0")]
pub fn stdin(&mut self, cfg: Stdio) -> &mut Command {
- self.stdin = Some(cfg.0);
+ self.stdin = Some(cfg);
self
}
/// Configuration for the child process's stdout handle (file descriptor 1).
#[stable(feature = "process", since = "1.0.0")]
pub fn stdout(&mut self, cfg: Stdio) -> &mut Command {
- self.stdout = Some(cfg.0);
+ self.stdout = Some(cfg);
self
}
/// Configuration for the child process's stderr handle (file descriptor 2).
#[stable(feature = "process", since = "1.0.0")]
pub fn stderr(&mut self, cfg: Stdio) -> &mut Command {
- self.stderr = Some(cfg.0);
+ self.stderr = Some(cfg);
self
}
fn spawn_inner(&self, default_io: StdioImp) -> io::Result<Child> {
- let (their_stdin, our_stdin) = try!(
+ let default_io = Stdio(default_io);
+
+ // See comment on `setup_io` for what `_drop_later` is.
+ let (their_stdin, our_stdin, _drop_later) = try!(
setup_io(self.stdin.as_ref().unwrap_or(&default_io), true)
);
- let (their_stdout, our_stdout) = try!(
+ let (their_stdout, our_stdout, _drop_later) = try!(
setup_io(self.stdout.as_ref().unwrap_or(&default_io), false)
);
- let (their_stderr, our_stderr) = try!(
+ let (their_stderr, our_stderr, _drop_later) = try!(
setup_io(self.stderr.as_ref().unwrap_or(&default_io), false)
);
- match ProcessImp::spawn(&self.inner, their_stdin, their_stdout, their_stderr) {
+ match imp::Process::spawn(&self.inner, their_stdin, their_stdout,
+ their_stderr) {
Err(e) => Err(e),
Ok(handle) => Ok(Child {
handle: handle,
/// Executes the command as a child process, returning a handle to it.
///
- /// By default, stdin, stdout and stderr are inherited by the parent.
+ /// By default, stdin, stdout and stderr are inherited from the parent.
#[stable(feature = "process", since = "1.0.0")]
pub fn spawn(&mut self) -> io::Result<Child> {
self.spawn_inner(StdioImp::Inherit)
/// ```
#[stable(feature = "process", since = "1.0.0")]
pub fn output(&mut self) -> io::Result<Output> {
- self.spawn_inner(StdioImp::Piped).and_then(|p| p.wait_with_output())
+ self.spawn_inner(StdioImp::MakePipe).and_then(|p| p.wait_with_output())
}
/// Executes a command as a child process, waiting for it to finish and
/// collecting its exit status.
///
- /// By default, stdin, stdout and stderr are inherited by the parent.
+ /// By default, stdin, stdout and stderr are inherited from the parent.
///
/// # Examples
///
}
}
-impl AsInner<CommandImp> for Command {
- fn as_inner(&self) -> &CommandImp { &self.inner }
+impl AsInner<imp::Command> for Command {
+ fn as_inner(&self) -> &imp::Command { &self.inner }
}
-impl AsInnerMut<CommandImp> for Command {
- fn as_inner_mut(&mut self) -> &mut CommandImp { &mut self.inner }
+impl AsInnerMut<imp::Command> for Command {
+ fn as_inner_mut(&mut self) -> &mut imp::Command { &mut self.inner }
}
-fn setup_io(io: &StdioImp, readable: bool)
- -> io::Result<(StdioImp2, Option<AnonPipe>)>
+// Takes a `Stdio` configuration (this module) and whether the to-be-owned
+// handle will be readable.
+//
+// Returns a triple of (stdio to spawn with, stdio to store, stdio to drop). The
+// stdio to spawn with is passed down to the `sys` module and indicates how the
+// stdio stream should be set up. The "stdio to store" is an object which
+// should be returned in the `Child` that makes its way out. The "stdio to drop"
+// represents the raw value of "stdio to spawn with", but is the owned variant
+// for it. This needs to be dropped after the child spawns
+fn setup_io(io: &Stdio, readable: bool)
+ -> io::Result<(imp::Stdio, Option<AnonPipe>, Option<AnonPipe>)>
{
- use self::StdioImp::*;
- Ok(match *io {
- Null => (StdioImp2::None, None),
- Inherit => (StdioImp2::Inherit, None),
- Piped => {
+ Ok(match io.0 {
+ StdioImp::MakePipe => {
let (reader, writer) = try!(pipe::anon_pipe());
if readable {
- (StdioImp2::Piped(reader), Some(writer))
+ (imp::Stdio::Raw(reader.raw()), Some(writer), Some(reader))
} else {
- (StdioImp2::Piped(writer), Some(reader))
+ (imp::Stdio::Raw(writer.raw()), Some(reader), Some(writer))
}
}
+ StdioImp::Raw(ref owned) => (imp::Stdio::Raw(owned.raw()), None, None),
+ StdioImp::Inherit => (imp::Stdio::Inherit, None, None),
+ StdioImp::None => (imp::Stdio::None, None, None),
})
}
pub struct Stdio(StdioImp);
// The internal enum for stdio setup; see below for descriptions.
-#[derive(Clone)]
enum StdioImp {
- Piped,
+ MakePipe,
+ Raw(imp::RawStdio),
Inherit,
- Null,
+ None,
}
impl Stdio {
/// A new pipe should be arranged to connect the parent and child processes.
#[stable(feature = "process", since = "1.0.0")]
- pub fn piped() -> Stdio { Stdio(StdioImp::Piped) }
+ pub fn piped() -> Stdio { Stdio(StdioImp::MakePipe) }
/// The child inherits from the corresponding parent descriptor.
#[stable(feature = "process", since = "1.0.0")]
/// This stream will be ignored. This is the equivalent of attaching the
/// stream to `/dev/null`
#[stable(feature = "process", since = "1.0.0")]
- pub fn null() -> Stdio { Stdio(StdioImp::Null) }
+ pub fn null() -> Stdio { Stdio(StdioImp::None) }
+}
+
+impl FromInner<imp::RawStdio> for Stdio {
+ fn from_inner(inner: imp::RawStdio) -> Stdio {
+ Stdio(StdioImp::Raw(inner))
+ }
}
/// Describes the result of a process after it has terminated.
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
#[stable(feature = "process", since = "1.0.0")]
-pub struct ExitStatus(ExitStatusImp);
+pub struct ExitStatus(imp::ExitStatus);
impl ExitStatus {
/// Was termination successful? Signal termination not considered a success,
}
}
-impl AsInner<ExitStatusImp> for ExitStatus {
- fn as_inner(&self) -> &ExitStatusImp { &self.0 }
+impl AsInner<imp::ExitStatus> for ExitStatus {
+ fn as_inner(&self) -> &imp::ExitStatus { &self.0 }
}
#[stable(feature = "process", since = "1.0.0")]
unsafe { self.handle.kill() }
}
+ /// Returns the OS-assigned process identifier associated with this child.
+ #[unstable(feature = "process_id", reason = "api recently added")]
+ pub fn id(&self) -> u32 {
+ self.handle.id()
+ }
+
/// Waits for the child to exit completely, returning the status that it
/// exited with. This function will continue to have the same return value
/// after it has been called at least once.
}
}
- #[cfg(all(unix, not(target_os="android")))]
- pub fn pwd_cmd() -> Command {
- Command::new("pwd")
- }
- #[cfg(target_os="android")]
- pub fn pwd_cmd() -> Command {
- let mut cmd = Command::new("/system/bin/sh");
- cmd.arg("-c").arg("pwd");
- cmd
- }
-
- #[cfg(windows)]
- pub fn pwd_cmd() -> Command {
- let mut cmd = Command::new("cmd");
- cmd.arg("/c").arg("cd");
- cmd
- }
-
#[cfg(all(unix, not(target_os="android")))]
pub fn env_cmd() -> Command {
Command::new("env")
/// appropriate.
///
/// Reading the randomness from the OS may fail, and any error is
- /// propagated via the `IoResult` return value.
+ /// propagated via the `io::Result` return value.
pub fn new() -> io::Result<StdRng> {
OsRng::new().map(|mut r| StdRng { rng: r.gen() })
}
target_arch = "aarch64",
target_arch = "powerpc")))]
fn is_getrandom_available() -> bool {
- use sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
- use sync::{Once, ONCE_INIT};
+ use sync::atomic::{AtomicBool, Ordering};
+ use sync::Once;
- static CHECKER: Once = ONCE_INIT;
- static AVAILABLE: AtomicBool = ATOMIC_BOOL_INIT;
+ static CHECKER: Once = Once::new();
+ static AVAILABLE: AtomicBool = AtomicBool::new(false);
CHECKER.call_once(|| {
let mut buf: [u8; 0] = [];
const CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000;
#[allow(non_snake_case)]
+ #[link(name = "advapi32")]
extern "system" {
fn CryptAcquireContextA(phProv: *mut HCRYPTPROV,
pszContainer: LPCSTR,
use mem;
use ffi::CStr;
- use sync::{StaticMutex, MUTEX_INIT};
+ use sync::StaticMutex;
static mut GLOBAL_ARGS_PTR: usize = 0;
- static LOCK: StaticMutex = MUTEX_INIT;
+ static LOCK: StaticMutex = StaticMutex::new();
pub unsafe fn init(argc: isize, argv: *const *const u8) {
let args = load_argc_and_argv(argc, argv);
// segfaults (the queue's memory is mysteriously gone), so
// instead the cleanup is tied to the `std::rt` entry point.
-use boxed;
+use alloc::boxed::FnBox;
use boxed::Box;
+use sys_common::mutex::Mutex;
use vec::Vec;
-use thunk::Thunk;
-use sys_common::mutex::{Mutex, MUTEX_INIT};
-type Queue = Vec<Thunk<'static>>;
+type Queue = Vec<Box<FnBox()>>;
// NB these are specifically not types from `std::sync` as they currently rely
// on poisoning and this module needs to operate at a lower level than requiring
// the thread infrastructure to be in place (useful on the borders of
// initialization/destruction).
-static LOCK: Mutex = MUTEX_INIT;
+static LOCK: Mutex = Mutex::new();
static mut QUEUE: *mut Queue = 0 as *mut Queue;
// The maximum number of times the cleanup routines will be run. While running
unsafe fn init() -> bool {
if QUEUE.is_null() {
let state: Box<Queue> = box Vec::new();
- QUEUE = boxed::into_raw(state);
+ QUEUE = Box::into_raw(state);
} else if QUEUE as usize == 1 {
// can't re-init after a cleanup
return false
}
}
-pub fn push(f: Thunk<'static>) -> bool {
+pub fn push(f: Box<FnBox()>) -> bool {
let mut ret = true;
unsafe {
LOCK.lock();
// For now logging is turned off by default, and this function checks to see
// whether the magical environment variable is present to see if it's turned on.
pub fn log_enabled() -> bool {
- static ENABLED: atomic::AtomicIsize = atomic::ATOMIC_ISIZE_INIT;
+ static ENABLED: atomic::AtomicIsize = atomic::AtomicIsize::new(0);
match ENABLED.load(Ordering::SeqCst) {
1 => return false,
2 => return true,
//! and should be considered as private implementation details for the
//! time being.
-#![unstable(feature = "std_misc")]
+#![unstable(feature = "rt",
+ reason = "this public module should not exist and is highly likely \
+ to disappear")]
#![allow(missing_docs)]
use prelude::v1::*;
if failed {
rt::DEFAULT_ERROR_CODE
} else {
- env::get_exit_status() as isize
+ #[allow(deprecated)]
+ fn exit_status() -> isize { env::get_exit_status() as isize }
+ exit_status()
}
}
+++ /dev/null
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Implementation of Rust stack unwinding
-//!
-//! For background on exception handling and stack unwinding please see
-//! "Exception Handling in LLVM" (llvm.org/docs/ExceptionHandling.html) and
-//! documents linked from it.
-//! These are also good reads:
-//! http://theofilos.cs.columbia.edu/blog/2013/09/22/base_abi/
-//! http://monoinfinito.wordpress.com/series/exception-handling-in-c/
-//! http://www.airs.com/blog/index.php?s=exception+frames
-//!
-//! ## A brief summary
-//!
-//! Exception handling happens in two phases: a search phase and a cleanup phase.
-//!
-//! In both phases the unwinder walks stack frames from top to bottom using
-//! information from the stack frame unwind sections of the current process's
-//! modules ("module" here refers to an OS module, i.e. an executable or a
-//! dynamic library).
-//!
-//! For each stack frame, it invokes the associated "personality routine", whose
-//! address is also stored in the unwind info section.
-//!
-//! In the search phase, the job of a personality routine is to examine exception
-//! object being thrown, and to decide whether it should be caught at that stack
-//! frame. Once the handler frame has been identified, cleanup phase begins.
-//!
-//! In the cleanup phase, personality routines invoke cleanup code associated
-//! with their stack frames (i.e. destructors). Once stack has been unwound down
-//! to the handler frame level, unwinding stops and the last personality routine
-//! transfers control to its catch block.
-//!
-//! ## Frame unwind info registration
-//!
-//! Each module has its own frame unwind info section (usually ".eh_frame"), and
-//! unwinder needs to know about all of them in order for unwinding to be able to
-//! cross module boundaries.
-//!
-//! On some platforms, like Linux, this is achieved by dynamically enumerating
-//! currently loaded modules via the dl_iterate_phdr() API and finding all
-//! .eh_frame sections.
-//!
-//! Others, like Windows, require modules to actively register their unwind info
-//! sections by calling __register_frame_info() API at startup. In the latter
-//! case it is essential that there is only one copy of the unwinder runtime in
-//! the process. This is usually achieved by linking to the dynamic version of
-//! the unwind runtime.
-//!
-//! Currently Rust uses unwind runtime provided by libgcc.
-
-use prelude::v1::*;
-
-use any::Any;
-use boxed;
-use cell::Cell;
-use cmp;
-use panicking;
-use fmt;
-use intrinsics;
-use libc::c_void;
-use mem;
-use sync::atomic::{self, Ordering};
-use sys_common::mutex::{Mutex, MUTEX_INIT};
-
-use rt::libunwind as uw;
-
-struct Exception {
- uwe: uw::_Unwind_Exception,
- cause: Option<Box<Any + Send + 'static>>,
-}
-
-pub type Callback = fn(msg: &(Any + Send), file: &'static str, line: u32);
-
-// Variables used for invoking callbacks when a thread starts to unwind.
-//
-// For more information, see below.
-const MAX_CALLBACKS: usize = 16;
-static CALLBACKS: [atomic::AtomicUsize; MAX_CALLBACKS] =
- [atomic::ATOMIC_USIZE_INIT, atomic::ATOMIC_USIZE_INIT,
- atomic::ATOMIC_USIZE_INIT, atomic::ATOMIC_USIZE_INIT,
- atomic::ATOMIC_USIZE_INIT, atomic::ATOMIC_USIZE_INIT,
- atomic::ATOMIC_USIZE_INIT, atomic::ATOMIC_USIZE_INIT,
- atomic::ATOMIC_USIZE_INIT, atomic::ATOMIC_USIZE_INIT,
- atomic::ATOMIC_USIZE_INIT, atomic::ATOMIC_USIZE_INIT,
- atomic::ATOMIC_USIZE_INIT, atomic::ATOMIC_USIZE_INIT,
- atomic::ATOMIC_USIZE_INIT, atomic::ATOMIC_USIZE_INIT];
-static CALLBACK_CNT: atomic::AtomicUsize = atomic::ATOMIC_USIZE_INIT;
-
-thread_local! { static PANICKING: Cell<bool> = Cell::new(false) }
-
-/// Invoke a closure, capturing the cause of panic if one occurs.
-///
-/// This function will return `Ok(())` if the closure did not panic, and will
-/// return `Err(cause)` if the closure panics. The `cause` returned is the
-/// object with which panic was originally invoked.
-///
-/// This function also is unsafe for a variety of reasons:
-///
-/// * This is not safe to call in a nested fashion. The unwinding
-/// interface for Rust is designed to have at most one try/catch block per
-/// thread, not multiple. No runtime checking is currently performed to uphold
-/// this invariant, so this function is not safe. A nested try/catch block
-/// may result in corruption of the outer try/catch block's state, especially
-/// if this is used within a thread itself.
-///
-/// * It is not sound to trigger unwinding while already unwinding. Rust threads
-/// have runtime checks in place to ensure this invariant, but it is not
-/// guaranteed that a rust thread is in place when invoking this function.
-/// Unwinding twice can lead to resource leaks where some destructors are not
-/// run.
-pub unsafe fn try<F: FnOnce()>(f: F) -> Result<(), Box<Any + Send>> {
- let mut f = Some(f);
-
- let prev = PANICKING.with(|s| s.get());
- PANICKING.with(|s| s.set(false));
- let ep = rust_try(try_fn::<F>, &mut f as *mut _ as *mut c_void);
- PANICKING.with(|s| s.set(prev));
- return if ep.is_null() {
- Ok(())
- } else {
- let my_ep = ep as *mut Exception;
- rtdebug!("caught {}", (*my_ep).uwe.exception_class);
- let cause = (*my_ep).cause.take();
- uw::_Unwind_DeleteException(ep);
- Err(cause.unwrap())
- };
-
- extern fn try_fn<F: FnOnce()>(opt_closure: *mut c_void) {
- let opt_closure = opt_closure as *mut Option<F>;
- unsafe { (*opt_closure).take().unwrap()(); }
- }
-
- #[link(name = "rustrt_native", kind = "static")]
- #[cfg(not(test))]
- extern {}
-
- extern {
- // Rust's try-catch
- // When f(...) returns normally, the return value is null.
- // When f(...) throws, the return value is a pointer to the caught
- // exception object.
- fn rust_try(f: extern fn(*mut c_void),
- data: *mut c_void) -> *mut uw::_Unwind_Exception;
- }
-}
-
-/// Determines whether the current thread is unwinding because of panic.
-pub fn panicking() -> bool {
- PANICKING.with(|s| s.get())
-}
-
-// An uninlined, unmangled function upon which to slap yer breakpoints
-#[inline(never)]
-#[no_mangle]
-#[allow(private_no_mangle_fns)]
-fn rust_panic(cause: Box<Any + Send + 'static>) -> ! {
- rtdebug!("begin_unwind()");
-
- unsafe {
- let exception: Box<_> = box Exception {
- uwe: uw::_Unwind_Exception {
- exception_class: rust_exception_class(),
- exception_cleanup: exception_cleanup,
- private: [0; uw::unwinder_private_data_size],
- },
- cause: Some(cause),
- };
- let exception_param = boxed::into_raw(exception) as *mut uw::_Unwind_Exception;
- let error = uw::_Unwind_RaiseException(exception_param);
- rtabort!("Could not unwind stack, error = {}", error as isize)
- }
-
- extern fn exception_cleanup(_unwind_code: uw::_Unwind_Reason_Code,
- exception: *mut uw::_Unwind_Exception) {
- rtdebug!("exception_cleanup()");
- unsafe {
- let _: Box<Exception> = Box::from_raw(exception as *mut Exception);
- }
- }
-}
-
-// Rust's exception class identifier. This is used by personality routines to
-// determine whether the exception was thrown by their own runtime.
-fn rust_exception_class() -> uw::_Unwind_Exception_Class {
- // M O Z \0 R U S T -- vendor, language
- 0x4d4f5a_00_52555354
-}
-
-// We could implement our personality routine in pure Rust, however exception
-// info decoding is tedious. More importantly, personality routines have to
-// handle various platform quirks, which are not fun to maintain. For this
-// reason, we attempt to reuse personality routine of the C language:
-// __gcc_personality_v0.
-//
-// Since C does not support exception catching, __gcc_personality_v0 simply
-// always returns _URC_CONTINUE_UNWIND in search phase, and always returns
-// _URC_INSTALL_CONTEXT (i.e. "invoke cleanup code") in cleanup phase.
-//
-// This is pretty close to Rust's exception handling approach, except that Rust
-// does have a single "catch-all" handler at the bottom of each thread's stack.
-// So we have two versions of the personality routine:
-// - rust_eh_personality, used by all cleanup landing pads, which never catches,
-// so the behavior of __gcc_personality_v0 is perfectly adequate there, and
-// - rust_eh_personality_catch, used only by rust_try(), which always catches.
-//
-// Note, however, that for implementation simplicity, rust_eh_personality_catch
-// lacks code to install a landing pad, so in order to obtain exception object
-// pointer (which it needs to return upstream), rust_try() employs another trick:
-// it calls into the nested rust_try_inner(), whose landing pad does not resume
-// unwinds. Instead, it extracts the exception pointer and performs a "normal"
-// return.
-//
-// See also: rt/rust_try.ll
-
-#[cfg(all(not(target_arch = "arm"),
- not(all(windows, target_arch = "x86_64")),
- not(test)))]
-#[doc(hidden)]
-pub mod eabi {
- use rt::libunwind as uw;
- use libc::c_int;
-
- extern "C" {
- fn __gcc_personality_v0(version: c_int,
- actions: uw::_Unwind_Action,
- exception_class: uw::_Unwind_Exception_Class,
- ue_header: *mut uw::_Unwind_Exception,
- context: *mut uw::_Unwind_Context)
- -> uw::_Unwind_Reason_Code;
- }
-
- #[lang = "eh_personality"]
- #[no_mangle] // referenced from rust_try.ll
- #[allow(private_no_mangle_fns)]
- extern fn rust_eh_personality(
- version: c_int,
- actions: uw::_Unwind_Action,
- exception_class: uw::_Unwind_Exception_Class,
- ue_header: *mut uw::_Unwind_Exception,
- context: *mut uw::_Unwind_Context
- ) -> uw::_Unwind_Reason_Code
- {
- unsafe {
- __gcc_personality_v0(version, actions, exception_class, ue_header,
- context)
- }
- }
-
- #[no_mangle] // referenced from rust_try.ll
- pub extern "C" fn rust_eh_personality_catch(
- _version: c_int,
- actions: uw::_Unwind_Action,
- _exception_class: uw::_Unwind_Exception_Class,
- _ue_header: *mut uw::_Unwind_Exception,
- _context: *mut uw::_Unwind_Context
- ) -> uw::_Unwind_Reason_Code
- {
-
- if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 { // search phase
- uw::_URC_HANDLER_FOUND // catch!
- }
- else { // cleanup phase
- uw::_URC_INSTALL_CONTEXT
- }
- }
-}
-
-// iOS on armv7 is using SjLj exceptions and therefore requires to use
-// a specialized personality routine: __gcc_personality_sj0
-
-#[cfg(all(target_os = "ios", target_arch = "arm", not(test)))]
-#[doc(hidden)]
-pub mod eabi {
- use rt::libunwind as uw;
- use libc::c_int;
-
- extern "C" {
- fn __gcc_personality_sj0(version: c_int,
- actions: uw::_Unwind_Action,
- exception_class: uw::_Unwind_Exception_Class,
- ue_header: *mut uw::_Unwind_Exception,
- context: *mut uw::_Unwind_Context)
- -> uw::_Unwind_Reason_Code;
- }
-
- #[lang = "eh_personality"]
- #[no_mangle] // referenced from rust_try.ll
- pub extern "C" fn rust_eh_personality(
- version: c_int,
- actions: uw::_Unwind_Action,
- exception_class: uw::_Unwind_Exception_Class,
- ue_header: *mut uw::_Unwind_Exception,
- context: *mut uw::_Unwind_Context
- ) -> uw::_Unwind_Reason_Code
- {
- unsafe {
- __gcc_personality_sj0(version, actions, exception_class, ue_header,
- context)
- }
- }
-
- #[no_mangle] // referenced from rust_try.ll
- pub extern "C" fn rust_eh_personality_catch(
- _version: c_int,
- actions: uw::_Unwind_Action,
- _exception_class: uw::_Unwind_Exception_Class,
- _ue_header: *mut uw::_Unwind_Exception,
- _context: *mut uw::_Unwind_Context
- ) -> uw::_Unwind_Reason_Code
- {
- if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 { // search phase
- uw::_URC_HANDLER_FOUND // catch!
- }
- else { // cleanup phase
- unsafe {
- __gcc_personality_sj0(_version, actions, _exception_class, _ue_header,
- _context)
- }
- }
- }
-}
-
-
-// ARM EHABI uses a slightly different personality routine signature,
-// but otherwise works the same.
-#[cfg(all(target_arch = "arm", not(target_os = "ios"), not(test)))]
-#[doc(hidden)]
-pub mod eabi {
- use rt::libunwind as uw;
- use libc::c_int;
-
- extern "C" {
- fn __gcc_personality_v0(state: uw::_Unwind_State,
- ue_header: *mut uw::_Unwind_Exception,
- context: *mut uw::_Unwind_Context)
- -> uw::_Unwind_Reason_Code;
- }
-
- #[lang = "eh_personality"]
- #[no_mangle] // referenced from rust_try.ll
- #[allow(private_no_mangle_fns)]
- extern "C" fn rust_eh_personality(
- state: uw::_Unwind_State,
- ue_header: *mut uw::_Unwind_Exception,
- context: *mut uw::_Unwind_Context
- ) -> uw::_Unwind_Reason_Code
- {
- unsafe {
- __gcc_personality_v0(state, ue_header, context)
- }
- }
-
- #[no_mangle] // referenced from rust_try.ll
- pub extern "C" fn rust_eh_personality_catch(
- state: uw::_Unwind_State,
- _ue_header: *mut uw::_Unwind_Exception,
- _context: *mut uw::_Unwind_Context
- ) -> uw::_Unwind_Reason_Code
- {
- if (state as c_int & uw::_US_ACTION_MASK as c_int)
- == uw::_US_VIRTUAL_UNWIND_FRAME as c_int { // search phase
- uw::_URC_HANDLER_FOUND // catch!
- }
- else { // cleanup phase
- uw::_URC_INSTALL_CONTEXT
- }
- }
-}
-
-// Win64 SEH (see http://msdn.microsoft.com/en-us/library/1eyas8tf.aspx)
-//
-// This looks a bit convoluted because rather than implementing a native SEH handler,
-// GCC reuses the same personality routine as for the other architectures by wrapping it
-// with an "API translator" layer (_GCC_specific_handler).
-
-#[cfg(all(windows, target_arch = "x86_64", not(test)))]
-#[doc(hidden)]
-#[allow(non_camel_case_types, non_snake_case)]
-pub mod eabi {
- pub use self::EXCEPTION_DISPOSITION::*;
- use rt::libunwind as uw;
- use libc::{c_void, c_int};
-
- #[repr(C)]
- pub struct EXCEPTION_RECORD;
- #[repr(C)]
- pub struct CONTEXT;
- #[repr(C)]
- pub struct DISPATCHER_CONTEXT;
-
- #[repr(C)]
- #[derive(Copy, Clone)]
- pub enum EXCEPTION_DISPOSITION {
- ExceptionContinueExecution,
- ExceptionContinueSearch,
- ExceptionNestedException,
- ExceptionCollidedUnwind
- }
-
- type _Unwind_Personality_Fn =
- extern "C" fn(
- version: c_int,
- actions: uw::_Unwind_Action,
- exception_class: uw::_Unwind_Exception_Class,
- ue_header: *mut uw::_Unwind_Exception,
- context: *mut uw::_Unwind_Context
- ) -> uw::_Unwind_Reason_Code;
-
- extern "C" {
- fn __gcc_personality_seh0(
- exceptionRecord: *mut EXCEPTION_RECORD,
- establisherFrame: *mut c_void,
- contextRecord: *mut CONTEXT,
- dispatcherContext: *mut DISPATCHER_CONTEXT
- ) -> EXCEPTION_DISPOSITION;
-
- fn _GCC_specific_handler(
- exceptionRecord: *mut EXCEPTION_RECORD,
- establisherFrame: *mut c_void,
- contextRecord: *mut CONTEXT,
- dispatcherContext: *mut DISPATCHER_CONTEXT,
- personality: _Unwind_Personality_Fn
- ) -> EXCEPTION_DISPOSITION;
- }
-
- #[lang = "eh_personality"]
- #[no_mangle] // referenced from rust_try.ll
- #[allow(private_no_mangle_fns)]
- extern "C" fn rust_eh_personality(
- exceptionRecord: *mut EXCEPTION_RECORD,
- establisherFrame: *mut c_void,
- contextRecord: *mut CONTEXT,
- dispatcherContext: *mut DISPATCHER_CONTEXT
- ) -> EXCEPTION_DISPOSITION
- {
- unsafe {
- __gcc_personality_seh0(exceptionRecord, establisherFrame,
- contextRecord, dispatcherContext)
- }
- }
-
- #[no_mangle] // referenced from rust_try.ll
- pub extern "C" fn rust_eh_personality_catch(
- exceptionRecord: *mut EXCEPTION_RECORD,
- establisherFrame: *mut c_void,
- contextRecord: *mut CONTEXT,
- dispatcherContext: *mut DISPATCHER_CONTEXT
- ) -> EXCEPTION_DISPOSITION
- {
- extern "C" fn inner(
- _version: c_int,
- actions: uw::_Unwind_Action,
- _exception_class: uw::_Unwind_Exception_Class,
- _ue_header: *mut uw::_Unwind_Exception,
- _context: *mut uw::_Unwind_Context
- ) -> uw::_Unwind_Reason_Code
- {
- if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 { // search phase
- uw::_URC_HANDLER_FOUND // catch!
- }
- else { // cleanup phase
- uw::_URC_INSTALL_CONTEXT
- }
- }
-
- unsafe {
- _GCC_specific_handler(exceptionRecord, establisherFrame,
- contextRecord, dispatcherContext,
- inner)
- }
- }
-}
-
-#[cfg(not(test))]
-/// Entry point of panic from the libcore crate.
-#[lang = "panic_fmt"]
-pub extern fn rust_begin_unwind(msg: fmt::Arguments,
- file: &'static str, line: u32) -> ! {
- begin_unwind_fmt(msg, &(file, line))
-}
-
-/// The entry point for unwinding with a formatted message.
-///
-/// This is designed to reduce the amount of code required at the call
-/// site as much as possible (so that `panic!()` has as low an impact
-/// on (e.g.) the inlining of other functions as possible), by moving
-/// the actual formatting into this shared place.
-#[inline(never)] #[cold]
-pub fn begin_unwind_fmt(msg: fmt::Arguments, file_line: &(&'static str, u32)) -> ! {
- use fmt::Write;
-
- // We do two allocations here, unfortunately. But (a) they're
- // required with the current scheme, and (b) we don't handle
- // panic + OOM properly anyway (see comment in begin_unwind
- // below).
-
- let mut s = String::new();
- let _ = s.write_fmt(msg);
- begin_unwind_inner(Box::new(s), file_line)
-}
-
-/// This is the entry point of unwinding for panic!() and assert!().
-#[inline(never)] #[cold] // avoid code bloat at the call sites as much as possible
-pub fn begin_unwind<M: Any + Send>(msg: M, file_line: &(&'static str, u32)) -> ! {
- // Note that this should be the only allocation performed in this code path.
- // Currently this means that panic!() on OOM will invoke this code path,
- // but then again we're not really ready for panic on OOM anyway. If
- // we do start doing this, then we should propagate this allocation to
- // be performed in the parent of this thread instead of the thread that's
- // panicking.
-
- // see below for why we do the `Any` coercion here.
- begin_unwind_inner(Box::new(msg), file_line)
-}
-
-/// The core of the unwinding.
-///
-/// This is non-generic to avoid instantiation bloat in other crates
-/// (which makes compilation of small crates noticeably slower). (Note:
-/// we need the `Any` object anyway, we're not just creating it to
-/// avoid being generic.)
-///
-/// Doing this split took the LLVM IR line counts of `fn main() { panic!()
-/// }` from ~1900/3700 (-O/no opts) to 180/590.
-#[inline(never)] #[cold] // this is the slow path, please never inline this
-fn begin_unwind_inner(msg: Box<Any + Send>,
- file_line: &(&'static str, u32)) -> ! {
- // Make sure the default failure handler is registered before we look at the
- // callbacks. We also use a raw sys-based mutex here instead of a
- // `std::sync` one as accessing TLS can cause weird recursive problems (and
- // we don't need poison checking).
- unsafe {
- static LOCK: Mutex = MUTEX_INIT;
- static mut INIT: bool = false;
- LOCK.lock();
- if !INIT {
- register(panicking::on_panic);
- INIT = true;
- }
- LOCK.unlock();
- }
-
- // First, invoke call the user-defined callbacks triggered on thread panic.
- //
- // By the time that we see a callback has been registered (by reading
- // MAX_CALLBACKS), the actual callback itself may have not been stored yet,
- // so we just chalk it up to a race condition and move on to the next
- // callback. Additionally, CALLBACK_CNT may briefly be higher than
- // MAX_CALLBACKS, so we're sure to clamp it as necessary.
- let callbacks = {
- let amt = CALLBACK_CNT.load(Ordering::SeqCst);
- &CALLBACKS[..cmp::min(amt, MAX_CALLBACKS)]
- };
- for cb in callbacks {
- match cb.load(Ordering::SeqCst) {
- 0 => {}
- n => {
- let f: Callback = unsafe { mem::transmute(n) };
- let (file, line) = *file_line;
- f(&*msg, file, line);
- }
- }
- };
-
- // Now that we've run all the necessary unwind callbacks, we actually
- // perform the unwinding.
- if panicking() {
- // If a thread panics while it's already unwinding then we
- // have limited options. Currently our preference is to
- // just abort. In the future we may consider resuming
- // unwinding or otherwise exiting the thread cleanly.
- rterrln!("thread panicked while panicking. aborting.");
- unsafe { intrinsics::abort() }
- }
- PANICKING.with(|s| s.set(true));
- rust_panic(msg);
-}
-
-/// Register a callback to be invoked when a thread unwinds.
-///
-/// This is an unsafe and experimental API which allows for an arbitrary
-/// callback to be invoked when a thread panics. This callback is invoked on both
-/// the initial unwinding and a double unwinding if one occurs. Additionally,
-/// the local `Thread` will be in place for the duration of the callback, and
-/// the callback must ensure that it remains in place once the callback returns.
-///
-/// Only a limited number of callbacks can be registered, and this function
-/// returns whether the callback was successfully registered or not. It is not
-/// currently possible to unregister a callback once it has been registered.
-pub unsafe fn register(f: Callback) -> bool {
- match CALLBACK_CNT.fetch_add(1, Ordering::SeqCst) {
- // The invocation code has knowledge of this window where the count has
- // been incremented, but the callback has not been stored. We're
- // guaranteed that the slot we're storing into is 0.
- n if n < MAX_CALLBACKS => {
- let prev = CALLBACKS[n].swap(mem::transmute(f), Ordering::SeqCst);
- rtassert!(prev == 0);
- true
- }
- // If we accidentally bumped the count too high, pull it back.
- _ => {
- CALLBACK_CNT.store(MAX_CALLBACKS, Ordering::SeqCst);
- false
- }
- }
-}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use prelude::v1::*;
+
+use any::Any;
+use libc::c_void;
+use rt::libunwind as uw;
+
+struct Exception {
+ uwe: uw::_Unwind_Exception,
+ cause: Option<Box<Any + Send + 'static>>,
+}
+
+pub unsafe fn panic(data: Box<Any + Send + 'static>) -> ! {
+ let exception: Box<_> = box Exception {
+ uwe: uw::_Unwind_Exception {
+ exception_class: rust_exception_class(),
+ exception_cleanup: exception_cleanup,
+ private: [0; uw::unwinder_private_data_size],
+ },
+ cause: Some(data),
+ };
+ let exception_param = Box::into_raw(exception) as *mut uw::_Unwind_Exception;
+ let error = uw::_Unwind_RaiseException(exception_param);
+ rtabort!("Could not unwind stack, error = {}", error as isize);
+
+ extern fn exception_cleanup(_unwind_code: uw::_Unwind_Reason_Code,
+ exception: *mut uw::_Unwind_Exception) {
+ rtdebug!("exception_cleanup()");
+ unsafe {
+ let _: Box<Exception> = Box::from_raw(exception as *mut Exception);
+ }
+ }
+}
+
+pub unsafe fn cleanup(ptr: *mut c_void) -> Box<Any + Send + 'static> {
+ let my_ep = ptr as *mut Exception;
+ rtdebug!("caught {}", (*my_ep).uwe.exception_class);
+ let cause = (*my_ep).cause.take();
+ uw::_Unwind_DeleteException(ptr as *mut _);
+ cause.unwrap()
+}
+
+// Rust's exception class identifier. This is used by personality routines to
+// determine whether the exception was thrown by their own runtime.
+fn rust_exception_class() -> uw::_Unwind_Exception_Class {
+ // M O Z \0 R U S T -- vendor, language
+ 0x4d4f5a_00_52555354
+}
+
+// We could implement our personality routine in pure Rust, however exception
+// info decoding is tedious. More importantly, personality routines have to
+// handle various platform quirks, which are not fun to maintain. For this
+// reason, we attempt to reuse personality routine of the C language:
+// __gcc_personality_v0.
+//
+// Since C does not support exception catching, __gcc_personality_v0 simply
+// always returns _URC_CONTINUE_UNWIND in search phase, and always returns
+// _URC_INSTALL_CONTEXT (i.e. "invoke cleanup code") in cleanup phase.
+//
+// This is pretty close to Rust's exception handling approach, except that Rust
+// does have a single "catch-all" handler at the bottom of each thread's stack.
+// So we have two versions of the personality routine:
+// - rust_eh_personality, used by all cleanup landing pads, which never catches,
+// so the behavior of __gcc_personality_v0 is perfectly adequate there, and
+// - rust_eh_personality_catch, used only by rust_try(), which always catches.
+//
+// Note, however, that for implementation simplicity, rust_eh_personality_catch
+// lacks code to install a landing pad, so in order to obtain exception object
+// pointer (which it needs to return upstream), rust_try() employs another trick:
+// it calls into the nested rust_try_inner(), whose landing pad does not resume
+// unwinds. Instead, it extracts the exception pointer and performs a "normal"
+// return.
+//
+// See also: rt/rust_try.ll
+
+#[cfg(all(not(target_arch = "arm"),
+ not(all(windows, target_arch = "x86_64")),
+ not(test)))]
+pub mod eabi {
+ use rt::libunwind as uw;
+ use libc::c_int;
+
+ extern "C" {
+ fn __gcc_personality_v0(version: c_int,
+ actions: uw::_Unwind_Action,
+ exception_class: uw::_Unwind_Exception_Class,
+ ue_header: *mut uw::_Unwind_Exception,
+ context: *mut uw::_Unwind_Context)
+ -> uw::_Unwind_Reason_Code;
+ }
+
+ #[lang="eh_personality"]
+ #[no_mangle] // referenced from rust_try.ll
+ #[allow(private_no_mangle_fns)]
+ extern fn rust_eh_personality(
+ version: c_int,
+ actions: uw::_Unwind_Action,
+ exception_class: uw::_Unwind_Exception_Class,
+ ue_header: *mut uw::_Unwind_Exception,
+ context: *mut uw::_Unwind_Context
+ ) -> uw::_Unwind_Reason_Code
+ {
+ unsafe {
+ __gcc_personality_v0(version, actions, exception_class, ue_header,
+ context)
+ }
+ }
+
+ #[no_mangle] // referenced from rust_try.ll
+ pub extern "C" fn rust_eh_personality_catch(
+ _version: c_int,
+ actions: uw::_Unwind_Action,
+ _exception_class: uw::_Unwind_Exception_Class,
+ _ue_header: *mut uw::_Unwind_Exception,
+ _context: *mut uw::_Unwind_Context
+ ) -> uw::_Unwind_Reason_Code
+ {
+
+ if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 { // search phase
+ uw::_URC_HANDLER_FOUND // catch!
+ }
+ else { // cleanup phase
+ uw::_URC_INSTALL_CONTEXT
+ }
+ }
+}
+
+// iOS on armv7 is using SjLj exceptions and therefore requires to use
+// a specialized personality routine: __gcc_personality_sj0
+
+#[cfg(all(target_os = "ios", target_arch = "arm", not(test)))]
+pub mod eabi {
+ use rt::libunwind as uw;
+ use libc::c_int;
+
+ extern "C" {
+ fn __gcc_personality_sj0(version: c_int,
+ actions: uw::_Unwind_Action,
+ exception_class: uw::_Unwind_Exception_Class,
+ ue_header: *mut uw::_Unwind_Exception,
+ context: *mut uw::_Unwind_Context)
+ -> uw::_Unwind_Reason_Code;
+ }
+
+ #[lang="eh_personality"]
+ #[no_mangle] // referenced from rust_try.ll
+ pub extern "C" fn rust_eh_personality(
+ version: c_int,
+ actions: uw::_Unwind_Action,
+ exception_class: uw::_Unwind_Exception_Class,
+ ue_header: *mut uw::_Unwind_Exception,
+ context: *mut uw::_Unwind_Context
+ ) -> uw::_Unwind_Reason_Code
+ {
+ unsafe {
+ __gcc_personality_sj0(version, actions, exception_class, ue_header,
+ context)
+ }
+ }
+
+ #[no_mangle] // referenced from rust_try.ll
+ pub extern "C" fn rust_eh_personality_catch(
+ _version: c_int,
+ actions: uw::_Unwind_Action,
+ _exception_class: uw::_Unwind_Exception_Class,
+ _ue_header: *mut uw::_Unwind_Exception,
+ _context: *mut uw::_Unwind_Context
+ ) -> uw::_Unwind_Reason_Code
+ {
+ if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 { // search phase
+ uw::_URC_HANDLER_FOUND // catch!
+ }
+ else { // cleanup phase
+ unsafe {
+ __gcc_personality_sj0(_version, actions, _exception_class, _ue_header,
+ _context)
+ }
+ }
+ }
+}
+
+
+// ARM EHABI uses a slightly different personality routine signature,
+// but otherwise works the same.
+#[cfg(all(target_arch = "arm", not(target_os = "ios"), not(test)))]
+pub mod eabi {
+ use rt::libunwind as uw;
+ use libc::c_int;
+
+ extern "C" {
+ fn __gcc_personality_v0(state: uw::_Unwind_State,
+ ue_header: *mut uw::_Unwind_Exception,
+ context: *mut uw::_Unwind_Context)
+ -> uw::_Unwind_Reason_Code;
+ }
+
+ #[lang="eh_personality"]
+ #[no_mangle] // referenced from rust_try.ll
+ #[allow(private_no_mangle_fns)]
+ extern "C" fn rust_eh_personality(
+ state: uw::_Unwind_State,
+ ue_header: *mut uw::_Unwind_Exception,
+ context: *mut uw::_Unwind_Context
+ ) -> uw::_Unwind_Reason_Code
+ {
+ unsafe {
+ __gcc_personality_v0(state, ue_header, context)
+ }
+ }
+
+ #[no_mangle] // referenced from rust_try.ll
+ pub extern "C" fn rust_eh_personality_catch(
+ state: uw::_Unwind_State,
+ _ue_header: *mut uw::_Unwind_Exception,
+ _context: *mut uw::_Unwind_Context
+ ) -> uw::_Unwind_Reason_Code
+ {
+ if (state as c_int & uw::_US_ACTION_MASK as c_int)
+ == uw::_US_VIRTUAL_UNWIND_FRAME as c_int { // search phase
+ uw::_URC_HANDLER_FOUND // catch!
+ }
+ else { // cleanup phase
+ uw::_URC_INSTALL_CONTEXT
+ }
+ }
+}
+
+// Win64 SEH (see http://msdn.microsoft.com/en-us/library/1eyas8tf.aspx)
+//
+// This looks a bit convoluted because rather than implementing a native SEH
+// handler, GCC reuses the same personality routine as for the other
+// architectures by wrapping it with an "API translator" layer
+// (_GCC_specific_handler).
+
+#[cfg(all(windows, target_arch = "x86_64", not(test)))]
+#[doc(hidden)]
+#[allow(non_camel_case_types, non_snake_case)]
+pub mod eabi {
+ pub use self::EXCEPTION_DISPOSITION::*;
+ use rt::libunwind as uw;
+ use libc::{c_void, c_int};
+
+ #[repr(C)]
+ pub struct EXCEPTION_RECORD;
+ #[repr(C)]
+ pub struct CONTEXT;
+ #[repr(C)]
+ pub struct DISPATCHER_CONTEXT;
+
+ #[repr(C)]
+ #[derive(Copy, Clone)]
+ pub enum EXCEPTION_DISPOSITION {
+ ExceptionContinueExecution,
+ ExceptionContinueSearch,
+ ExceptionNestedException,
+ ExceptionCollidedUnwind
+ }
+
+ type _Unwind_Personality_Fn =
+ extern "C" fn(
+ version: c_int,
+ actions: uw::_Unwind_Action,
+ exception_class: uw::_Unwind_Exception_Class,
+ ue_header: *mut uw::_Unwind_Exception,
+ context: *mut uw::_Unwind_Context
+ ) -> uw::_Unwind_Reason_Code;
+
+ extern "C" {
+ fn __gcc_personality_seh0(
+ exceptionRecord: *mut EXCEPTION_RECORD,
+ establisherFrame: *mut c_void,
+ contextRecord: *mut CONTEXT,
+ dispatcherContext: *mut DISPATCHER_CONTEXT
+ ) -> EXCEPTION_DISPOSITION;
+
+ fn _GCC_specific_handler(
+ exceptionRecord: *mut EXCEPTION_RECORD,
+ establisherFrame: *mut c_void,
+ contextRecord: *mut CONTEXT,
+ dispatcherContext: *mut DISPATCHER_CONTEXT,
+ personality: _Unwind_Personality_Fn
+ ) -> EXCEPTION_DISPOSITION;
+ }
+
+ #[lang="eh_personality"]
+ #[no_mangle] // referenced from rust_try.ll
+ #[allow(private_no_mangle_fns)]
+ extern "C" fn rust_eh_personality(
+ exceptionRecord: *mut EXCEPTION_RECORD,
+ establisherFrame: *mut c_void,
+ contextRecord: *mut CONTEXT,
+ dispatcherContext: *mut DISPATCHER_CONTEXT
+ ) -> EXCEPTION_DISPOSITION
+ {
+ unsafe {
+ __gcc_personality_seh0(exceptionRecord, establisherFrame,
+ contextRecord, dispatcherContext)
+ }
+ }
+
+ #[no_mangle] // referenced from rust_try.ll
+ pub extern "C" fn rust_eh_personality_catch(
+ exceptionRecord: *mut EXCEPTION_RECORD,
+ establisherFrame: *mut c_void,
+ contextRecord: *mut CONTEXT,
+ dispatcherContext: *mut DISPATCHER_CONTEXT
+ ) -> EXCEPTION_DISPOSITION
+ {
+ extern "C" fn inner(
+ _version: c_int,
+ actions: uw::_Unwind_Action,
+ _exception_class: uw::_Unwind_Exception_Class,
+ _ue_header: *mut uw::_Unwind_Exception,
+ _context: *mut uw::_Unwind_Context
+ ) -> uw::_Unwind_Reason_Code
+ {
+ if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 { // search phase
+ uw::_URC_HANDLER_FOUND // catch!
+ }
+ else { // cleanup phase
+ uw::_URC_INSTALL_CONTEXT
+ }
+ }
+
+ unsafe {
+ _GCC_specific_handler(exceptionRecord, establisherFrame,
+ contextRecord, dispatcherContext,
+ inner)
+ }
+ }
+}
+
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Implementation of Rust stack unwinding
+//!
+//! For background on exception handling and stack unwinding please see
+//! "Exception Handling in LLVM" (llvm.org/docs/ExceptionHandling.html) and
+//! documents linked from it.
+//! These are also good reads:
+//! http://theofilos.cs.columbia.edu/blog/2013/09/22/base_abi/
+//! http://monoinfinito.wordpress.com/series/exception-handling-in-c/
+//! http://www.airs.com/blog/index.php?s=exception+frames
+//!
+//! ## A brief summary
+//!
+//! Exception handling happens in two phases: a search phase and a cleanup phase.
+//!
+//! In both phases the unwinder walks stack frames from top to bottom using
+//! information from the stack frame unwind sections of the current process's
+//! modules ("module" here refers to an OS module, i.e. an executable or a
+//! dynamic library).
+//!
+//! For each stack frame, it invokes the associated "personality routine", whose
+//! address is also stored in the unwind info section.
+//!
+//! In the search phase, the job of a personality routine is to examine exception
+//! object being thrown, and to decide whether it should be caught at that stack
+//! frame. Once the handler frame has been identified, cleanup phase begins.
+//!
+//! In the cleanup phase, personality routines invoke cleanup code associated
+//! with their stack frames (i.e. destructors). Once stack has been unwound down
+//! to the handler frame level, unwinding stops and the last personality routine
+//! transfers control to its catch block.
+//!
+//! ## Frame unwind info registration
+//!
+//! Each module has its own frame unwind info section (usually ".eh_frame"), and
+//! unwinder needs to know about all of them in order for unwinding to be able to
+//! cross module boundaries.
+//!
+//! On some platforms, like Linux, this is achieved by dynamically enumerating
+//! currently loaded modules via the dl_iterate_phdr() API and finding all
+//! .eh_frame sections.
+//!
+//! Others, like Windows, require modules to actively register their unwind info
+//! sections by calling __register_frame_info() API at startup. In the latter
+//! case it is essential that there is only one copy of the unwinder runtime in
+//! the process. This is usually achieved by linking to the dynamic version of
+//! the unwind runtime.
+//!
+//! Currently Rust uses unwind runtime provided by libgcc.
+
+#![allow(dead_code)]
+#![allow(unused_imports)]
+
+use prelude::v1::*;
+
+use any::Any;
+use boxed;
+use cell::Cell;
+use cmp;
+use panicking;
+use fmt;
+use intrinsics;
+use libc::c_void;
+use mem;
+use sync::atomic::{self, Ordering};
+use sys_common::mutex::Mutex;
+
+// The actual unwinding implementation is cfg'd here, and we've got two current
+// implementations. One goes through SEH on Windows and the other goes through
+// libgcc via the libunwind-like API.
+#[cfg(target_env = "msvc")] #[path = "seh.rs"] #[doc(hidden)]
+pub mod imp;
+#[cfg(not(target_env = "msvc"))] #[path = "gcc.rs"] #[doc(hidden)]
+pub mod imp;
+
+pub type Callback = fn(msg: &(Any + Send), file: &'static str, line: u32);
+
+// Variables used for invoking callbacks when a thread starts to unwind.
+//
+// For more information, see below.
+const MAX_CALLBACKS: usize = 16;
+static CALLBACKS: [atomic::AtomicUsize; MAX_CALLBACKS] =
+ [atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0),
+ atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0),
+ atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0),
+ atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0),
+ atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0),
+ atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0),
+ atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0),
+ atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0)];
+static CALLBACK_CNT: atomic::AtomicUsize = atomic::AtomicUsize::new(0);
+
+thread_local! { static PANICKING: Cell<bool> = Cell::new(false) }
+
+#[link(name = "rustrt_native", kind = "static")]
+#[cfg(not(test))]
+extern {}
+
+/// Invoke a closure, capturing the cause of panic if one occurs.
+///
+/// This function will return `Ok(())` if the closure did not panic, and will
+/// return `Err(cause)` if the closure panics. The `cause` returned is the
+/// object with which panic was originally invoked.
+///
+/// This function also is unsafe for a variety of reasons:
+///
+/// * This is not safe to call in a nested fashion. The unwinding
+/// interface for Rust is designed to have at most one try/catch block per
+/// thread, not multiple. No runtime checking is currently performed to uphold
+/// this invariant, so this function is not safe. A nested try/catch block
+/// may result in corruption of the outer try/catch block's state, especially
+/// if this is used within a thread itself.
+///
+/// * It is not sound to trigger unwinding while already unwinding. Rust threads
+/// have runtime checks in place to ensure this invariant, but it is not
+/// guaranteed that a rust thread is in place when invoking this function.
+/// Unwinding twice can lead to resource leaks where some destructors are not
+/// run.
+pub unsafe fn try<F: FnOnce()>(f: F) -> Result<(), Box<Any + Send>> {
+ let mut f = Some(f);
+ return inner_try(try_fn::<F>, &mut f as *mut _ as *mut c_void);
+
+ // If an inner function were not used here, then this generic function `try`
+ // uses the native symbol `rust_try`, for which the code is statically
+ // linked into the standard library. This means that the DLL for the
+ // standard library must have `rust_try` as an exposed symbol that
+ // downstream crates can link against (because monomorphizations of `try` in
+ // downstream crates will have a reference to the `rust_try` symbol).
+ //
+ // On MSVC this requires the symbol `rust_try` to be tagged with
+ // `dllexport`, but it's easier to not have conditional `src/rt/rust_try.ll`
+ // files and instead just have this non-generic shim the compiler can take
+ // care of exposing correctly.
+ unsafe fn inner_try(f: extern fn(*mut c_void), data: *mut c_void)
+ -> Result<(), Box<Any + Send>> {
+ let prev = PANICKING.with(|s| s.get());
+ PANICKING.with(|s| s.set(false));
+ let ep = rust_try(f, data);
+ PANICKING.with(|s| s.set(prev));
+ if ep.is_null() {
+ Ok(())
+ } else {
+ Err(imp::cleanup(ep))
+ }
+ }
+
+ extern fn try_fn<F: FnOnce()>(opt_closure: *mut c_void) {
+ let opt_closure = opt_closure as *mut Option<F>;
+ unsafe { (*opt_closure).take().unwrap()(); }
+ }
+
+ extern {
+ // Rust's try-catch
+ // When f(...) returns normally, the return value is null.
+ // When f(...) throws, the return value is a pointer to the caught
+ // exception object.
+ fn rust_try(f: extern fn(*mut c_void),
+ data: *mut c_void) -> *mut c_void;
+ }
+}
+
+/// Determines whether the current thread is unwinding because of panic.
+pub fn panicking() -> bool {
+ PANICKING.with(|s| s.get())
+}
+
+// An uninlined, unmangled function upon which to slap yer breakpoints
+#[inline(never)]
+#[no_mangle]
+#[allow(private_no_mangle_fns)]
+fn rust_panic(cause: Box<Any + Send + 'static>) -> ! {
+ rtdebug!("begin_unwind()");
+ unsafe {
+ imp::panic(cause)
+ }
+}
+
+#[cfg(not(test))]
+/// Entry point of panic from the libcore crate.
+#[lang = "panic_fmt"]
+pub extern fn rust_begin_unwind(msg: fmt::Arguments,
+ file: &'static str, line: u32) -> ! {
+ begin_unwind_fmt(msg, &(file, line))
+}
+
+/// The entry point for unwinding with a formatted message.
+///
+/// This is designed to reduce the amount of code required at the call
+/// site as much as possible (so that `panic!()` has as low an impact
+/// on (e.g.) the inlining of other functions as possible), by moving
+/// the actual formatting into this shared place.
+#[inline(never)] #[cold]
+pub fn begin_unwind_fmt(msg: fmt::Arguments, file_line: &(&'static str, u32)) -> ! {
+ use fmt::Write;
+
+ // We do two allocations here, unfortunately. But (a) they're
+ // required with the current scheme, and (b) we don't handle
+ // panic + OOM properly anyway (see comment in begin_unwind
+ // below).
+
+ let mut s = String::new();
+ let _ = s.write_fmt(msg);
+ begin_unwind_inner(Box::new(s), file_line)
+}
+
+/// This is the entry point of unwinding for panic!() and assert!().
+#[inline(never)] #[cold] // avoid code bloat at the call sites as much as possible
+pub fn begin_unwind<M: Any + Send>(msg: M, file_line: &(&'static str, u32)) -> ! {
+ // Note that this should be the only allocation performed in this code path.
+ // Currently this means that panic!() on OOM will invoke this code path,
+ // but then again we're not really ready for panic on OOM anyway. If
+ // we do start doing this, then we should propagate this allocation to
+ // be performed in the parent of this thread instead of the thread that's
+ // panicking.
+
+ // see below for why we do the `Any` coercion here.
+ begin_unwind_inner(Box::new(msg), file_line)
+}
+
+/// The core of the unwinding.
+///
+/// This is non-generic to avoid instantiation bloat in other crates
+/// (which makes compilation of small crates noticeably slower). (Note:
+/// we need the `Any` object anyway, we're not just creating it to
+/// avoid being generic.)
+///
+/// Doing this split took the LLVM IR line counts of `fn main() { panic!()
+/// }` from ~1900/3700 (-O/no opts) to 180/590.
+#[inline(never)] #[cold] // this is the slow path, please never inline this
+fn begin_unwind_inner(msg: Box<Any + Send>,
+ file_line: &(&'static str, u32)) -> ! {
+ // Make sure the default failure handler is registered before we look at the
+ // callbacks. We also use a raw sys-based mutex here instead of a
+ // `std::sync` one as accessing TLS can cause weird recursive problems (and
+ // we don't need poison checking).
+ unsafe {
+ static LOCK: Mutex = Mutex::new();
+ static mut INIT: bool = false;
+ LOCK.lock();
+ if !INIT {
+ register(panicking::on_panic);
+ INIT = true;
+ }
+ LOCK.unlock();
+ }
+
+ // First, invoke call the user-defined callbacks triggered on thread panic.
+ //
+ // By the time that we see a callback has been registered (by reading
+ // MAX_CALLBACKS), the actual callback itself may have not been stored yet,
+ // so we just chalk it up to a race condition and move on to the next
+ // callback. Additionally, CALLBACK_CNT may briefly be higher than
+ // MAX_CALLBACKS, so we're sure to clamp it as necessary.
+ let callbacks = {
+ let amt = CALLBACK_CNT.load(Ordering::SeqCst);
+ &CALLBACKS[..cmp::min(amt, MAX_CALLBACKS)]
+ };
+ for cb in callbacks {
+ match cb.load(Ordering::SeqCst) {
+ 0 => {}
+ n => {
+ let f: Callback = unsafe { mem::transmute(n) };
+ let (file, line) = *file_line;
+ f(&*msg, file, line);
+ }
+ }
+ };
+
+ // Now that we've run all the necessary unwind callbacks, we actually
+ // perform the unwinding.
+ if panicking() {
+ // If a thread panics while it's already unwinding then we
+ // have limited options. Currently our preference is to
+ // just abort. In the future we may consider resuming
+ // unwinding or otherwise exiting the thread cleanly.
+ rterrln!("thread panicked while panicking. aborting.");
+ unsafe { intrinsics::abort() }
+ }
+ PANICKING.with(|s| s.set(true));
+ rust_panic(msg);
+}
+
+/// Register a callback to be invoked when a thread unwinds.
+///
+/// This is an unsafe and experimental API which allows for an arbitrary
+/// callback to be invoked when a thread panics. This callback is invoked on both
+/// the initial unwinding and a double unwinding if one occurs. Additionally,
+/// the local `Thread` will be in place for the duration of the callback, and
+/// the callback must ensure that it remains in place once the callback returns.
+///
+/// Only a limited number of callbacks can be registered, and this function
+/// returns whether the callback was successfully registered or not. It is not
+/// currently possible to unregister a callback once it has been registered.
+pub unsafe fn register(f: Callback) -> bool {
+ match CALLBACK_CNT.fetch_add(1, Ordering::SeqCst) {
+ // The invocation code has knowledge of this window where the count has
+ // been incremented, but the callback has not been stored. We're
+ // guaranteed that the slot we're storing into is 0.
+ n if n < MAX_CALLBACKS => {
+ let prev = CALLBACKS[n].swap(mem::transmute(f), Ordering::SeqCst);
+ rtassert!(prev == 0);
+ true
+ }
+ // If we accidentally bumped the count too high, pull it back.
+ _ => {
+ CALLBACK_CNT.store(MAX_CALLBACKS, Ordering::SeqCst);
+ false
+ }
+ }
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use prelude::v1::*;
+
+use any::Any;
+use intrinsics;
+use libc::c_void;
+
+pub unsafe fn panic(_data: Box<Any + Send + 'static>) -> ! {
+ intrinsics::abort();
+}
+
+pub unsafe fn cleanup(_ptr: *mut c_void) -> Box<Any + Send + 'static> {
+ intrinsics::abort();
+}
+
+#[lang = "eh_personality"]
+#[no_mangle]
+pub extern fn rust_eh_personality() {}
+
+#[no_mangle]
+pub extern fn rust_eh_personality_catch() {}
}
pub fn min_stack() -> usize {
- static MIN: atomic::AtomicUsize = atomic::ATOMIC_USIZE_INIT;
+ static MIN: atomic::AtomicUsize = atomic::AtomicUsize::new(0);
match MIN.load(Ordering::SeqCst) {
0 => {}
n => return n - 1,
cfg!(rtassert);
pub fn dumb_print(args: fmt::Arguments) {
- let _ = Stderr::new().write_fmt(args);
+ let _ = Stderr::new().map(|mut stderr| stderr.write_fmt(args));
}
pub fn abort(args: fmt::Arguments) -> ! {
//! the standard library This varies per-platform, but these libraries are
//! necessary for running libstd.
-#![unstable(feature = "std_misc")]
-
// All platforms need to link to rustrt
#[cfg(not(test))]
#[link(name = "rust_builtin", kind = "static")]
use prelude::v1::*;
-use sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
+use sync::atomic::{AtomicUsize, Ordering};
use sync::{mutex, MutexGuard, PoisonError};
use sys_common::condvar as sys;
use sys_common::mutex as sys_mutex;
/// Constant initializer for a statically allocated condition variable.
#[unstable(feature = "static_condvar",
reason = "may be merged with Condvar in the future")]
-pub const CONDVAR_INIT: StaticCondvar = StaticCondvar {
- inner: sys::CONDVAR_INIT,
- mutex: ATOMIC_USIZE_INIT,
-};
+pub const CONDVAR_INIT: StaticCondvar = StaticCondvar::new();
impl Condvar {
/// Creates a new condition variable which is ready to be waited on and
pub fn new() -> Condvar {
Condvar {
inner: box StaticCondvar {
- inner: unsafe { sys::Condvar::new() },
+ inner: sys::Condvar::new(),
mutex: AtomicUsize::new(0),
}
}
}
impl StaticCondvar {
+ /// Creates a new condition variable
+ #[unstable(feature = "static_condvar",
+ reason = "may be merged with Condvar in the future")]
+ pub const fn new() -> StaticCondvar {
+ StaticCondvar {
+ inner: sys::Condvar::new(),
+ mutex: AtomicUsize::new(0),
+ }
+ }
+
/// Blocks the current thread until this condition variable receives a
/// notification.
///
mod tests {
use prelude::v1::*;
- use super::{StaticCondvar, CONDVAR_INIT};
+ use super::StaticCondvar;
use sync::mpsc::channel;
- use sync::{StaticMutex, MUTEX_INIT, Condvar, Mutex, Arc};
- use sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
+ use sync::{StaticMutex, Condvar, Mutex, Arc};
+ use sync::atomic::{AtomicUsize, Ordering};
use thread;
use time::Duration;
use u32;
#[test]
fn static_smoke() {
- static C: StaticCondvar = CONDVAR_INIT;
+ static C: StaticCondvar = StaticCondvar::new();
C.notify_one();
C.notify_all();
unsafe { C.destroy(); }
#[test]
fn notify_one() {
- static C: StaticCondvar = CONDVAR_INIT;
- static M: StaticMutex = MUTEX_INIT;
+ static C: StaticCondvar = StaticCondvar::new();
+ static M: StaticMutex = StaticMutex::new();
let g = M.lock().unwrap();
let _t = thread::spawn(move|| {
#[test]
fn wait_timeout_ms() {
- static C: StaticCondvar = CONDVAR_INIT;
- static M: StaticMutex = MUTEX_INIT;
+ static C: StaticCondvar = StaticCondvar::new();
+ static M: StaticMutex = StaticMutex::new();
let g = M.lock().unwrap();
let (g, _no_timeout) = C.wait_timeout_ms(g, 1).unwrap();
#[test]
fn wait_timeout_with() {
- static C: StaticCondvar = CONDVAR_INIT;
- static M: StaticMutex = MUTEX_INIT;
- static S: AtomicUsize = ATOMIC_USIZE_INIT;
+ static C: StaticCondvar = StaticCondvar::new();
+ static M: StaticMutex = StaticMutex::new();
+ static S: AtomicUsize = AtomicUsize::new(0);
let g = M.lock().unwrap();
let (g, success) = C.wait_timeout_with(g, Duration::new(0, 1000), |_| {
#[test]
#[should_panic]
fn two_mutexes() {
- static M1: StaticMutex = MUTEX_INIT;
- static M2: StaticMutex = MUTEX_INIT;
- static C: StaticCondvar = CONDVAR_INIT;
+ static M1: StaticMutex = StaticMutex::new();
+ static M2: StaticMutex = StaticMutex::new();
+ static C: StaticCondvar = StaticCondvar::new();
let mut g = M1.lock().unwrap();
let _t = thread::spawn(move|| {
//! # Examples
//!
//! ```
-//! # #![feature(std_misc)]
+//! # #![feature(future)]
//! use std::sync::Future;
//!
//! // a fake, for now
//! ```
#![allow(missing_docs)]
-#![unstable(feature = "std_misc",
+#![unstable(feature = "future",
reason = "futures as-is have yet to be deeply reevaluated with recent \
core changes to Rust's synchronization story, and will likely \
become stable in the future but are unstable until that time")]
+#![deprecated(since = "1.2.0",
+ reason = "implementation does not match the quality of the \
+ standard library and this will likely be prototyped \
+ outside in crates.io first")]
+#![allow(deprecated)]
use core::prelude::*;
use core::mem::replace;
pub use self::rwlock::{RwLock, StaticRwLock, RW_LOCK_INIT};
pub use self::semaphore::{Semaphore, SemaphoreGuard};
+#[allow(deprecated)]
pub use self::future::Future;
pub mod mpsc;
//! Generic support for building blocking abstractions.
use thread::{self, Thread};
-use sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
+use sync::atomic::{AtomicBool, Ordering};
use sync::Arc;
use marker::{Sync, Send};
use mem;
pub fn tokens() -> (WaitToken, SignalToken) {
let inner = Arc::new(Inner {
thread: thread::current(),
- woken: ATOMIC_BOOL_INIT,
+ woken: AtomicBool::new(false),
});
let wait_token = WaitToken {
inner: inner.clone(),
//! method, and see the method for more information about it. Due to this
//! caveat, this queue may not be appropriate for all use-cases.
-#![unstable(feature = "std_misc")]
-
// http://www.1024cores.net/home/lock-free-algorithms
// /queues/non-intrusive-mpsc-node-based-queue
use core::prelude::*;
-use alloc::boxed;
use alloc::boxed::Box;
use core::ptr;
use core::cell::UnsafeCell;
impl<T> Node<T> {
unsafe fn new(v: Option<T>) -> *mut Node<T> {
- boxed::into_raw(box Node {
+ Box::into_raw(box Node {
next: AtomicPtr::new(ptr::null_mut()),
value: v,
})
//! # Examples
//!
//! ```rust
-//! # #![feature(std_misc)]
+//! # #![feature(mpsc_select)]
//! use std::sync::mpsc::channel;
//!
//! let (tx1, rx1) = channel();
//! ```
#![allow(dead_code)]
-#![unstable(feature = "std_misc",
+#![unstable(feature = "mpsc_select",
reason = "This implementation, while likely sufficient, is unsafe and \
likely to be error prone. At some point in the future this \
module will likely be replaced, and it is currently \
/// # Examples
///
/// ```
- /// # #![feature(std_misc)]
+ /// # #![feature(mpsc_select)]
/// use std::sync::mpsc::Select;
///
/// let select = Select::new();
//! concurrently between two threads. This data structure is safe to use and
//! enforces the semantics that there is one pusher and one popper.
-#![unstable(feature = "std_misc")]
-
use core::prelude::*;
-use alloc::boxed;
use alloc::boxed::Box;
use core::ptr;
use core::cell::UnsafeCell;
impl<T> Node<T> {
fn new() -> *mut Node<T> {
- unsafe {
- boxed::into_raw(box Node {
- value: None,
- next: AtomicPtr::new(ptr::null_mut::<Node<T>>()),
- })
- }
+ Box::into_raw(box Node {
+ value: None,
+ next: AtomicPtr::new(ptr::null_mut::<Node<T>>()),
+ })
}
}
/// To recover from a poisoned mutex:
///
/// ```
-/// # #![feature(std_misc)]
/// use std::sync::{Arc, Mutex};
/// use std::thread;
///
/// # Examples
///
/// ```
-/// # #![feature(std_misc)]
+/// # #![feature(static_mutex)]
/// use std::sync::{StaticMutex, MUTEX_INIT};
///
/// static LOCK: StaticMutex = MUTEX_INIT;
/// }
/// // lock is unlocked here.
/// ```
-#[unstable(feature = "std_misc",
+#[unstable(feature = "static_mutex",
reason = "may be merged with Mutex in the future")]
pub struct StaticMutex {
lock: sys::Mutex,
/// Static initialization of a mutex. This constant can be used to initialize
/// other mutex constants.
-#[unstable(feature = "std_misc",
+#[unstable(feature = "static_mutex",
reason = "may be merged with Mutex in the future")]
-pub const MUTEX_INIT: StaticMutex = StaticMutex {
- lock: sys::MUTEX_INIT,
- poison: poison::FLAG_INIT,
-};
+pub const MUTEX_INIT: StaticMutex = StaticMutex::new();
impl<T> Mutex<T> {
/// Creates a new mutex in an unlocked state ready for use.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new(t: T) -> Mutex<T> {
Mutex {
- inner: box MUTEX_INIT,
+ inner: box StaticMutex::new(),
data: UnsafeCell::new(t),
}
}
/// time. You should not trust a `false` value for program correctness
/// without additional synchronization.
#[inline]
- #[unstable(feature = "std_misc")]
+ #[stable(feature = "sync_poison", since = "1.2.0")]
pub fn is_poisoned(&self) -> bool {
self.inner.poison.get()
}
struct Dummy(UnsafeCell<()>);
unsafe impl Sync for Dummy {}
-static DUMMY: Dummy = Dummy(UnsafeCell { value: () });
+static DUMMY: Dummy = Dummy(UnsafeCell::new(()));
+#[unstable(feature = "static_mutex",
+ reason = "may be merged with Mutex in the future")]
impl StaticMutex {
+ /// Creates a new mutex in an unlocked state ready for use.
+ pub const fn new() -> StaticMutex {
+ StaticMutex {
+ lock: sys::Mutex::new(),
+ poison: poison::Flag::new(),
+ }
+ }
+
/// Acquires this lock, see `Mutex::lock`
#[inline]
- #[unstable(feature = "std_misc",
- reason = "may be merged with Mutex in the future")]
pub fn lock(&'static self) -> LockResult<MutexGuard<()>> {
unsafe { self.lock.lock() }
MutexGuard::new(self, &DUMMY.0)
/// Attempts to grab this lock, see `Mutex::try_lock`
#[inline]
- #[unstable(feature = "std_misc",
- reason = "may be merged with Mutex in the future")]
pub fn try_lock(&'static self) -> TryLockResult<MutexGuard<()>> {
if unsafe { self.lock.try_lock() } {
Ok(try!(MutexGuard::new(self, &DUMMY.0)))
/// *all* platforms. It may be the case that some platforms do not leak
/// memory if this method is not called, but this is not guaranteed to be
/// true on all platforms.
- #[unstable(feature = "std_misc",
- reason = "may be merged with Mutex in the future")]
pub unsafe fn destroy(&'static self) {
self.lock.destroy()
}
use prelude::v1::*;
use sync::mpsc::channel;
- use sync::{Arc, Mutex, StaticMutex, MUTEX_INIT, Condvar};
+ use sync::{Arc, Mutex, StaticMutex, Condvar};
use thread;
struct Packet<T: Send>(Arc<(Mutex<T>, Condvar)>);
#[test]
fn smoke_static() {
- static M: StaticMutex = MUTEX_INIT;
+ static M: StaticMutex = StaticMutex::new();
unsafe {
drop(M.lock().unwrap());
drop(M.lock().unwrap());
#[test]
fn lots_and_lots() {
- static M: StaticMutex = MUTEX_INIT;
+ static M: StaticMutex = StaticMutex::new();
static mut CNT: u32 = 0;
const J: u32 = 1000;
const K: u32 = 3;
use prelude::v1::*;
use isize;
-use sync::atomic::{AtomicIsize, Ordering, ATOMIC_ISIZE_INIT};
-use sync::{StaticMutex, MUTEX_INIT};
+use sync::atomic::{AtomicIsize, Ordering};
+use sync::StaticMutex;
/// A synchronization primitive which can be used to run a one-time global
/// initialization. Useful for one-time initialization for FFI or related
/// Initialization value for static `Once` values.
#[stable(feature = "rust1", since = "1.0.0")]
-pub const ONCE_INIT: Once = Once {
- mutex: MUTEX_INIT,
- cnt: ATOMIC_ISIZE_INIT,
- lock_cnt: ATOMIC_ISIZE_INIT,
-};
+pub const ONCE_INIT: Once = Once::new();
impl Once {
+ /// Creates a new `Once` value.
+ #[stable(feature = "once_new", since = "1.2.0")]
+ pub const fn new() -> Once {
+ Once {
+ mutex: StaticMutex::new(),
+ cnt: AtomicIsize::new(0),
+ lock_cnt: AtomicIsize::new(0),
+ }
+ }
+
/// Performs an initialization routine once and only once. The given closure
/// will be executed if this is the first time `call_once` has been called,
/// and otherwise the routine will *not* be invoked.
use prelude::v1::*;
use thread;
- use super::{ONCE_INIT, Once};
+ use super::Once;
use sync::mpsc::channel;
#[test]
fn smoke_once() {
- static O: Once = ONCE_INIT;
+ static O: Once = Once::new();
let mut a = 0;
O.call_once(|| a += 1);
assert_eq!(a, 1);
#[test]
fn stampede_once() {
- static O: Once = ONCE_INIT;
+ static O: Once = Once::new();
static mut run: bool = false;
let (tx, rx) = channel();
/// of the underlying data (exclusive access) and the read portion of this lock
/// typically allows for read-only access (shared access).
///
+/// The priority policy of the lock is dependent on the underlying operating
+/// system's implementation, and this type does not guarantee that any
+/// particular policy will be used.
+///
/// The type parameter `T` represents the data that this lock protects. It is
/// required that `T` satisfies `Send` to be shared across threads and `Sync` to
/// allow concurrent access through readers. The RAII guards returned from the
/// # Examples
///
/// ```
-/// # #![feature(std_misc)]
+/// # #![feature(static_rwlock)]
/// use std::sync::{StaticRwLock, RW_LOCK_INIT};
///
/// static LOCK: StaticRwLock = RW_LOCK_INIT;
/// }
/// unsafe { LOCK.destroy() } // free all resources
/// ```
-#[unstable(feature = "std_misc",
+#[unstable(feature = "static_rwlock",
reason = "may be merged with RwLock in the future")]
pub struct StaticRwLock {
lock: sys::RWLock,
}
/// Constant initialization for a statically-initialized rwlock.
-#[unstable(feature = "std_misc",
+#[unstable(feature = "static_rwlock",
reason = "may be merged with RwLock in the future")]
-pub const RW_LOCK_INIT: StaticRwLock = StaticRwLock {
- lock: sys::RWLOCK_INIT,
- poison: poison::FLAG_INIT,
-};
+pub const RW_LOCK_INIT: StaticRwLock = StaticRwLock::new();
/// RAII structure used to release the shared read access of a lock when
/// dropped.
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new(t: T) -> RwLock<T> {
- RwLock { inner: box RW_LOCK_INIT, data: UnsafeCell::new(t) }
+ RwLock { inner: box StaticRwLock::new(), data: UnsafeCell::new(t) }
}
}
/// time. You should not trust a `false` value for program correctness
/// without additional synchronization.
#[inline]
- #[unstable(feature = "std_misc")]
+ #[stable(feature = "sync_poison", since = "1.2.0")]
pub fn is_poisoned(&self) -> bool {
self.inner.poison.get()
}
struct Dummy(UnsafeCell<()>);
unsafe impl Sync for Dummy {}
-static DUMMY: Dummy = Dummy(UnsafeCell { value: () });
+static DUMMY: Dummy = Dummy(UnsafeCell::new(()));
+#[unstable(feature = "static_rwlock",
+ reason = "may be merged with RwLock in the future")]
impl StaticRwLock {
+ /// Creates a new rwlock.
+ pub const fn new() -> StaticRwLock {
+ StaticRwLock {
+ lock: sys::RWLock::new(),
+ poison: poison::Flag::new(),
+ }
+ }
+
/// Locks this rwlock with shared read access, blocking the current thread
/// until it can be acquired.
///
/// See `RwLock::read`.
#[inline]
- #[unstable(feature = "std_misc",
- reason = "may be merged with RwLock in the future")]
pub fn read(&'static self) -> LockResult<RwLockReadGuard<'static, ()>> {
unsafe { self.lock.read() }
RwLockReadGuard::new(self, &DUMMY.0)
///
/// See `RwLock::try_read`.
#[inline]
- #[unstable(feature = "std_misc",
- reason = "may be merged with RwLock in the future")]
pub fn try_read(&'static self)
-> TryLockResult<RwLockReadGuard<'static, ()>> {
if unsafe { self.lock.try_read() } {
///
/// See `RwLock::write`.
#[inline]
- #[unstable(feature = "std_misc",
- reason = "may be merged with RwLock in the future")]
pub fn write(&'static self) -> LockResult<RwLockWriteGuard<'static, ()>> {
unsafe { self.lock.write() }
RwLockWriteGuard::new(self, &DUMMY.0)
///
/// See `RwLock::try_write`.
#[inline]
- #[unstable(feature = "std_misc",
- reason = "may be merged with RwLock in the future")]
pub fn try_write(&'static self)
-> TryLockResult<RwLockWriteGuard<'static, ()>> {
if unsafe { self.lock.try_write() } {
/// active users of the lock, and this also doesn't prevent any future users
/// of this lock. This method is required to be called to not leak memory on
/// all platforms.
- #[unstable(feature = "std_misc",
- reason = "may be merged with RwLock in the future")]
pub unsafe fn destroy(&'static self) {
self.lock.destroy()
}
use rand::{self, Rng};
use sync::mpsc::channel;
use thread;
- use sync::{Arc, RwLock, StaticRwLock, TryLockError, RW_LOCK_INIT};
+ use sync::{Arc, RwLock, StaticRwLock, TryLockError};
#[test]
fn smoke() {
#[test]
fn static_smoke() {
- static R: StaticRwLock = RW_LOCK_INIT;
+ static R: StaticRwLock = StaticRwLock::new();
drop(R.read().unwrap());
drop(R.write().unwrap());
drop((R.read().unwrap(), R.read().unwrap()));
#[test]
fn frob() {
- static R: StaticRwLock = RW_LOCK_INIT;
+ static R: StaticRwLock = StaticRwLock::new();
const N: usize = 10;
const M: usize = 1000;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![unstable(feature = "std_misc",
+#![unstable(feature = "semaphore",
reason = "the interaction between semaphores and the acquisition/release \
of resources is currently unclear")]
/// # Examples
///
/// ```
-/// # #![feature(std_misc)]
+/// # #![feature(semaphore)]
/// use std::sync::Semaphore;
///
/// // Create a semaphore that represents 5 resources
// 2. For each element of the path, emit the length plus the element
// 3. End the path with "E"
//
-// For example, "_ZN4testE" => "test" and "_ZN3foo3bar" => "foo::bar".
+// For example, "_ZN4testE" => "test" and "_ZN3foo3barE" => "foo::bar".
//
// We're the ones printing our backtraces, so we can't rely on anything else to
// demangle our symbols. It's *much* nicer to look at demangled symbols, so
/// this type.
pub struct Condvar(imp::Condvar);
-/// Static initializer for condition variables.
-pub const CONDVAR_INIT: Condvar = Condvar(imp::CONDVAR_INIT);
-
impl Condvar {
/// Creates a new condition variable for use.
///
/// Behavior is undefined if the condition variable is moved after it is
/// first used with any of the functions below.
- #[inline]
- pub unsafe fn new() -> Condvar { Condvar(imp::Condvar::new()) }
+ pub const fn new() -> Condvar { Condvar(imp::Condvar::new()) }
/// Signals one waiter on this condition variable to wake up.
#[inline]
unsafe impl Sync for Mutex {}
-/// Constant initializer for statically allocated mutexes.
-pub const MUTEX_INIT: Mutex = Mutex(imp::MUTEX_INIT);
-
impl Mutex {
+ /// Creates a new mutex for use.
+ ///
+ /// Behavior is undefined if the mutex is moved after it is
+ /// first used with any of the functions below.
+ pub const fn new() -> Mutex { Mutex(imp::Mutex::new()) }
+
/// Locks the mutex blocking the current thread until it is available.
///
/// Behavior is undefined if the mutex has been moved between this and any
use sys::c;
use sys::net::{cvt, cvt_r, cvt_gai, Socket, init, wrlen_t};
use sys_common::{AsInner, FromInner, IntoInner};
+use time::Duration;
////////////////////////////////////////////////////////////////////////////////
// sockaddr and misc bindings
////////////////////////////////////////////////////////////////////////////////
-fn setsockopt<T>(sock: &Socket, opt: c_int, val: c_int,
+pub fn setsockopt<T>(sock: &Socket, opt: c_int, val: c_int,
payload: T) -> io::Result<()> {
unsafe {
let payload = &payload as *const T as *const c_void;
}
}
-#[allow(dead_code)]
-fn getsockopt<T: Copy>(sock: &Socket, opt: c_int,
+pub fn getsockopt<T: Copy>(sock: &Socket, opt: c_int,
val: c_int) -> io::Result<T> {
unsafe {
let mut slot: T = mem::zeroed();
let mut len = mem::size_of::<T>() as socklen_t;
- let ret = try!(cvt(c::getsockopt(*sock.as_inner(), opt, val,
- &mut slot as *mut _ as *mut _,
- &mut len)));
- assert_eq!(ret as usize, mem::size_of::<T>());
+ try!(cvt(c::getsockopt(*sock.as_inner(), opt, val,
+ &mut slot as *mut _ as *mut _,
+ &mut len)));
+ assert_eq!(len as usize, mem::size_of::<T>());
Ok(slot)
}
}
Ok(())
}
+ pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
+ self.inner.set_timeout(dur, libc::SO_RCVTIMEO)
+ }
+
+ pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
+ self.inner.set_timeout(dur, libc::SO_SNDTIMEO)
+ }
+
+ pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+ self.inner.timeout(libc::SO_RCVTIMEO)
+ }
+
+ pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+ self.inner.timeout(libc::SO_SNDTIMEO)
+ }
+
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
self.inner.read(buf)
}
let mut res = f.debug_struct("TcpStream");
if let Ok(addr) = self.socket_addr() {
- res = res.field("addr", &addr);
+ res.field("addr", &addr);
}
if let Ok(peer) = self.peer_addr() {
- res = res.field("peer", &peer);
+ res.field("peer", &peer);
}
let name = if cfg!(windows) {"socket"} else {"fd"};
- res = res.field(name, &self.inner.as_inner());
- res.finish()
+ res.field(name, &self.inner.as_inner())
+ .finish()
}
}
let mut res = f.debug_struct("TcpListener");
if let Ok(addr) = self.socket_addr() {
- res = res.field("addr", &addr);
+ res.field("addr", &addr);
}
let name = if cfg!(windows) {"socket"} else {"fd"};
- res = res.field(name, &self.inner.as_inner());
- res.finish()
+ res.field(name, &self.inner.as_inner())
+ .finish()
}
}
pub fn duplicate(&self) -> io::Result<UdpSocket> {
self.inner.duplicate().map(|s| UdpSocket { inner: s })
}
+
+ pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
+ self.inner.set_timeout(dur, libc::SO_RCVTIMEO)
+ }
+
+ pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
+ self.inner.set_timeout(dur, libc::SO_SNDTIMEO)
+ }
+
+ pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+ self.inner.timeout(libc::SO_RCVTIMEO)
+ }
+
+ pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+ self.inner.timeout(libc::SO_SNDTIMEO)
+ }
}
impl FromInner<Socket> for UdpSocket {
let mut res = f.debug_struct("UdpSocket");
if let Ok(addr) = self.socket_addr() {
- res = res.field("addr", &addr);
+ res.field("addr", &addr);
}
let name = if cfg!(windows) {"socket"} else {"fd"};
- res = res.field(name, &self.inner.as_inner());
- res.finish()
+ res.field(name, &self.inner.as_inner())
+ .finish()
}
}
use prelude::v1::*;
-use marker::Reflect;
-use cell::UnsafeCell;
+use cell::Cell;
use error::{Error};
use fmt;
+use marker::Reflect;
use thread;
-pub struct Flag { failed: UnsafeCell<bool> }
+pub struct Flag { failed: Cell<bool> }
// This flag is only ever accessed with a lock previously held. Note that this
// a totally private structure.
unsafe impl Send for Flag {}
unsafe impl Sync for Flag {}
-pub const FLAG_INIT: Flag = Flag { failed: UnsafeCell { value: false } };
-
impl Flag {
+ pub const fn new() -> Flag {
+ Flag { failed: Cell::new(false) }
+ }
+
#[inline]
pub fn borrow(&self) -> LockResult<Guard> {
let ret = Guard { panicking: thread::panicking() };
- if unsafe { *self.failed.get() } {
+ if self.get() {
Err(PoisonError::new(ret))
} else {
Ok(ret)
#[inline]
pub fn done(&self, guard: &Guard) {
if !guard.panicking && thread::panicking() {
- unsafe { *self.failed.get() = true; }
+ self.failed.set(true);
}
}
#[inline]
pub fn get(&self) -> bool {
- unsafe { *self.failed.get() }
+ self.failed.get()
}
}
impl<T> PoisonError<T> {
/// Creates a `PoisonError`.
- #[unstable(feature = "std_misc")]
+ #[stable(feature = "sync_poison", since = "1.2.0")]
pub fn new(guard: T) -> PoisonError<T> {
PoisonError { guard: guard }
}
/// Consumes this error indicating that a lock is poisoned, returning the
/// underlying guard to allow access regardless.
- #[unstable(feature = "std_misc")]
+ #[stable(feature = "sync_poison", since = "1.2.0")]
pub fn into_inner(self) -> T { self.guard }
/// Reaches into this error indicating that a lock is poisoned, returning a
/// reference to the underlying guard to allow access regardless.
- #[unstable(feature = "std_misc")]
+ #[stable(feature = "sync_poison", since = "1.2.0")]
pub fn get_ref(&self) -> &T { &self.guard }
/// Reaches into this error indicating that a lock is poisoned, returning a
/// mutable reference to the underlying guard to allow access regardless.
- #[unstable(feature = "std_misc")]
+ #[stable(feature = "sync_poison", since = "1.2.0")]
pub fn get_mut(&mut self) -> &mut T { &mut self.guard }
}
unsafe {
let mut mutex = ReentrantMutex {
inner: box sys::ReentrantMutex::uninitialized(),
- poison: poison::FLAG_INIT,
+ poison: poison::Flag::new(),
data: t,
};
mutex.inner.init();
assert_eq!(*lock.borrow(), 4950);
});
for i in 0..100 {
- let mut lock = m.lock().unwrap();
+ let lock = m.lock().unwrap();
*lock.borrow_mut() += i;
}
drop(lock);
/// safer types at the top level of this crate instead of this type.
pub struct RWLock(imp::RWLock);
-/// Constant initializer for static RWLocks.
-pub const RWLOCK_INIT: RWLock = RWLock(imp::RWLOCK_INIT);
-
impl RWLock {
+ /// Creates a new reader-writer lock for use.
+ ///
+ /// Behavior is undefined if the reader-writer lock is moved after it is
+ /// first used with any of the functions below.
+ pub const fn new() -> RWLock { RWLock(imp::RWLock::new()) }
+
/// Acquires shared access to the underlying lock, blocking the current
/// thread to do so.
///
pub unsafe fn record_sp_limit(limit: usize) {
return target_record_sp_limit(limit);
- // x86-64
#[cfg(all(target_arch = "x86_64",
any(target_os = "macos", target_os = "ios")))]
#[inline(always)]
asm!("movq $0, %fs:32" :: "r"(limit) :: "volatile")
}
- // x86
#[cfg(all(target_arch = "x86",
any(target_os = "macos", target_os = "ios")))]
#[inline(always)]
unsafe fn target_record_sp_limit(_: usize) {
}
- // mips, arm - Some brave soul can port these to inline asm, but it's over
- // my head personally
+ // mips, arm - The implementations are a bit big for inline asm!
+ // They can be found in src/rt/arch/$target_arch/record_sp.S
#[cfg(any(target_arch = "mips",
target_arch = "mipsel",
all(target_arch = "arm", not(target_os = "ios"))))]
pub unsafe fn get_sp_limit() -> usize {
return target_get_sp_limit();
- // x86-64
#[cfg(all(target_arch = "x86_64",
any(target_os = "macos", target_os = "ios")))]
#[inline(always)]
return limit;
}
- // x86
#[cfg(all(target_arch = "x86",
any(target_os = "macos", target_os = "ios")))]
#[inline(always)]
return 1024;
}
- // mips, arm - Some brave soul can port these to inline asm, but it's over
- // my head personally
+ // mips, arm - The implementations are a bit big for inline asm!
+ // They can be found in src/rt/arch/$target_arch/record_sp.S
#[cfg(any(target_arch = "mips",
target_arch = "mipsel",
all(target_arch = "arm", not(target_os = "ios"))))]
/// }
/// ```
pub struct StaticKey {
- /// Inner static TLS key (internals), created with by `INIT_INNER` in this
- /// module.
- pub inner: StaticKeyInner,
+ /// Inner static TLS key (internals).
+ key: AtomicUsize,
/// Destructor for the TLS value.
///
/// See `Key::new` for information about when the destructor runs and how
/// it runs.
- pub dtor: Option<unsafe extern fn(*mut u8)>,
-}
-
-/// Inner contents of `StaticKey`, created by the `INIT_INNER` constant.
-pub struct StaticKeyInner {
- key: AtomicUsize,
+ dtor: Option<unsafe extern fn(*mut u8)>,
}
/// A type for a safely managed OS-based TLS slot.
/// type is entirely safe to use.
///
/// Implementations will likely, however, contain unsafe code as this type only
-/// operates on `*mut u8`, an unsafe pointer.
+/// operates on `*mut u8`, a raw pointer.
///
/// # Examples
///
/// Constant initialization value for static TLS keys.
///
/// This value specifies no destructor by default.
-pub const INIT: StaticKey = StaticKey {
- inner: INIT_INNER,
- dtor: None,
-};
-
-/// Constant initialization value for the inner part of static TLS keys.
-///
-/// This value allows specific configuration of the destructor for a TLS key.
-pub const INIT_INNER: StaticKeyInner = StaticKeyInner {
- key: atomic::ATOMIC_USIZE_INIT,
-};
+pub const INIT: StaticKey = StaticKey::new(None);
impl StaticKey {
+ pub const fn new(dtor: Option<unsafe extern fn(*mut u8)>) -> StaticKey {
+ StaticKey {
+ key: atomic::AtomicUsize::new(0),
+ dtor: dtor
+ }
+ }
+
/// Gets the value associated with this TLS key
///
/// This will lazily allocate a TLS key from the OS if one has not already
/// Note that this does *not* run the user-provided destructor if one was
/// specified at definition time. Doing so must be done manually.
pub unsafe fn destroy(&self) {
- match self.inner.key.swap(0, Ordering::SeqCst) {
+ match self.key.swap(0, Ordering::SeqCst) {
0 => {}
n => { imp::destroy(n as imp::Key) }
}
#[inline]
unsafe fn key(&self) -> imp::Key {
- match self.inner.key.load(Ordering::Relaxed) {
+ match self.key.load(Ordering::Relaxed) {
0 => self.lazy_init() as imp::Key,
n => n as imp::Key
}
key2
};
assert!(key != 0);
- match self.inner.key.compare_and_swap(0, key as usize, Ordering::SeqCst) {
+ match self.key.compare_and_swap(0, key as usize, Ordering::SeqCst) {
// The CAS succeeded, so we've created the actual key
0 => key as usize,
// If someone beat us to the punch, use their key instead
#[cfg(test)]
mod tests {
use prelude::v1::*;
- use super::{Key, StaticKey, INIT_INNER};
+ use super::{Key, StaticKey};
fn assert_sync<T: Sync>() {}
fn assert_send<T: Send>() {}
#[test]
fn statik() {
- static K1: StaticKey = StaticKey { inner: INIT_INNER, dtor: None };
- static K2: StaticKey = StaticKey { inner: INIT_INNER, dtor: None };
+ static K1: StaticKey = StaticKey::new(None);
+ static K2: StaticKey = StaticKey::new(None);
unsafe {
assert!(K1.get().is_null());
use core::prelude::*;
use core::char::{encode_utf8_raw, encode_utf16_raw};
-use core::str::{char_range_at_raw, next_code_point};
+use core::str::next_code_point;
use ascii::*;
use borrow::Cow;
}
}
- /// Returns the code point at `position`.
- ///
- /// # Panics
- ///
- /// Panics if `position` is not at a code point boundary,
- /// or is beyond the end of the string.
- #[inline]
- pub fn code_point_at(&self, position: usize) -> CodePoint {
- let (code_point, _) = self.code_point_range_at(position);
- code_point
- }
-
- /// Returns the code point at `position`
- /// and the position of the next code point.
- ///
- /// # Panics
- ///
- /// Panics if `position` is not at a code point boundary,
- /// or is beyond the end of the string.
- #[inline]
- pub fn code_point_range_at(&self, position: usize) -> (CodePoint, usize) {
- let (c, n) = char_range_at_raw(&self.bytes, position);
- (CodePoint { value: c }, n)
- }
-
/// Returns an iterator for the string’s code points.
#[inline]
pub fn code_points(&self) -> Wtf8CodePoints {
#[test]
fn wtf8buf_from_string() {
- assert_eq!(Wtf8Buf::from_string(String::from_str("")).bytes, b"");
- assert_eq!(Wtf8Buf::from_string(String::from_str("aé 💩")).bytes,
+ assert_eq!(Wtf8Buf::from_string(String::from("")).bytes, b"");
+ assert_eq!(Wtf8Buf::from_string(String::from("aé 💩")).bytes,
b"a\xC3\xA9 \xF0\x9F\x92\xA9");
}
#[test]
fn wtf8buf_into_string() {
let mut string = Wtf8Buf::from_str("aé 💩");
- assert_eq!(string.clone().into_string(), Ok(String::from_str("aé 💩")));
+ assert_eq!(string.clone().into_string(), Ok(String::from("aé 💩")));
string.push(CodePoint::from_u32(0xD800).unwrap());
assert_eq!(string.clone().into_string(), Err(string));
}
#[test]
fn wtf8buf_into_string_lossy() {
let mut string = Wtf8Buf::from_str("aé 💩");
- assert_eq!(string.clone().into_string_lossy(), String::from_str("aé 💩"));
+ assert_eq!(string.clone().into_string_lossy(), String::from("aé 💩"));
string.push(CodePoint::from_u32(0xD800).unwrap());
- assert_eq!(string.clone().into_string_lossy(), String::from_str("aé 💩�"));
+ assert_eq!(string.clone().into_string_lossy(), String::from("aé 💩�"));
}
#[test]
assert_eq!(slice.ascii_byte_at(4), b'\xFF');
}
- #[test]
- fn wtf8_code_point_at() {
- let mut string = Wtf8Buf::from_str("aé ");
- string.push(CodePoint::from_u32(0xD83D).unwrap());
- string.push_char('💩');
- assert_eq!(string.code_point_at(0), CodePoint::from_char('a'));
- assert_eq!(string.code_point_at(1), CodePoint::from_char('é'));
- assert_eq!(string.code_point_at(3), CodePoint::from_char(' '));
- assert_eq!(string.code_point_at(4), CodePoint::from_u32(0xD83D).unwrap());
- assert_eq!(string.code_point_at(7), CodePoint::from_char('💩'));
- }
-
- #[test]
- fn wtf8_code_point_range_at() {
- let mut string = Wtf8Buf::from_str("aé ");
- string.push(CodePoint::from_u32(0xD83D).unwrap());
- string.push_char('💩');
- assert_eq!(string.code_point_range_at(0), (CodePoint::from_char('a'), 1));
- assert_eq!(string.code_point_range_at(1), (CodePoint::from_char('é'), 3));
- assert_eq!(string.code_point_range_at(3), (CodePoint::from_char(' '), 4));
- assert_eq!(string.code_point_range_at(4), (CodePoint::from_u32(0xD83D).unwrap(), 7));
- assert_eq!(string.code_point_range_at(7), (CodePoint::from_char('💩'), 11));
- }
-
#[test]
fn wtf8_code_points() {
fn c(value: u32) -> CodePoint { CodePoint::from_u32(value).unwrap() }
assert_eq!(Wtf8::from_str("aé 💩").to_string_lossy(), Cow::Borrowed("aé 💩"));
let mut string = Wtf8Buf::from_str("aé 💩");
string.push(CodePoint::from_u32(0xD800).unwrap());
- let expected: Cow<str> = Cow::Owned(String::from_str("aé 💩�"));
+ let expected: Cow<str> = Cow::Owned(String::from("aé 💩�"));
assert_eq!(string.to_string_lossy(), expected);
}
use libc;
use mem;
use str;
-use sync::{StaticMutex, MUTEX_INIT};
+use sync::StaticMutex;
use sys_common::backtrace::*;
// while it doesn't requires lock for work as everything is
// local, it still displays much nicer backtraces when a
// couple of threads panic simultaneously
- static LOCK: StaticMutex = MUTEX_INIT;
+ static LOCK: StaticMutex = StaticMutex::new();
let _g = LOCK.lock();
try!(writeln!(w, "stack backtrace:"));
// is semi-reasonable in terms of printing anyway, and we know that all
// I/O done here is blocking I/O, not green I/O, so we don't have to
// worry about this being a native vs green mutex.
- static LOCK: StaticMutex = MUTEX_INIT;
+ static LOCK: StaticMutex = StaticMutex::new();
let _g = LOCK.lock();
try!(writeln!(w, "stack backtrace:"));
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//! C definitions used by libnative that don't belong in liblibc
+//! C definitions used by std::sys that don't belong in liblibc
+
+// These are definitions sufficient for the users in this directory.
+// This is not a general-purpose binding to this functionality, and in
+// some cases (notably the definition of siginfo_t), we intentionally
+// have incomplete bindings so that we don't need to fight with unions.
+//
+// Note that these types need to match the definitions from the platform
+// libc (currently glibc on Linux), not the kernel definitions / the
+// syscall interface. This has a few weirdnesses, like glibc's sigset_t
+// being 1024 bits on all platforms. If you're adding a new GNU/Linux
+// port, check glibc's sysdeps/unix/sysv/linux, not the kernel headers.
#![allow(dead_code)]
#![allow(non_camel_case_types)]
-pub use self::select::fd_set;
-pub use self::signal::{sigaction, siginfo, sigset_t};
-pub use self::signal::{SA_ONSTACK, SA_RESTART, SA_RESETHAND, SA_NOCLDSTOP};
-pub use self::signal::{SA_NODEFER, SA_NOCLDWAIT, SA_SIGINFO, SIGCHLD};
+pub use self::signal_os::{sigaction, siginfo, sigset_t, sigaltstack};
+pub use self::signal_os::{SA_ONSTACK, SA_SIGINFO, SIGBUS, SIGSTKSZ, SIG_SETMASK};
use libc;
target_os = "dragonfly",
target_os = "bitrig",
target_os = "openbsd"))]
-mod consts {
- use libc;
- pub const FIONBIO: libc::c_ulong = 0x8004667e;
- pub const FIOCLEX: libc::c_ulong = 0x20006601;
- pub const FIONCLEX: libc::c_ulong = 0x20006602;
-}
+pub const FIOCLEX: libc::c_ulong = 0x20006601;
+
#[cfg(any(all(target_os = "linux",
any(target_arch = "x86",
target_arch = "x86_64",
target_arch = "arm",
target_arch = "aarch64")),
target_os = "android"))]
-mod consts {
- use libc;
- pub const FIONBIO: libc::c_ulong = 0x5421;
- pub const FIOCLEX: libc::c_ulong = 0x5451;
- pub const FIONCLEX: libc::c_ulong = 0x5450;
-}
+pub const FIOCLEX: libc::c_ulong = 0x5451;
+
#[cfg(all(target_os = "linux",
any(target_arch = "mips",
target_arch = "mipsel",
target_arch = "powerpc")))]
-mod consts {
- use libc;
- pub const FIONBIO: libc::c_ulong = 0x667e;
- pub const FIOCLEX: libc::c_ulong = 0x6601;
- pub const FIONCLEX: libc::c_ulong = 0x6600;
-}
-pub use self::consts::*;
-
-#[cfg(any(target_os = "macos",
- target_os = "ios",
- target_os = "freebsd",
- target_os = "dragonfly",
- target_os = "bitrig",
- target_os = "openbsd"))]
-pub const MSG_DONTWAIT: libc::c_int = 0x80;
-#[cfg(any(target_os = "linux", target_os = "android"))]
-pub const MSG_DONTWAIT: libc::c_int = 0x40;
+pub const FIOCLEX: libc::c_ulong = 0x6601;
pub const WNOHANG: libc::c_int = 1;
pub pw_shell: *mut libc::c_char,
}
+// This is really a function pointer (or a union of multiple function
+// pointers), except for constants like SIG_DFL.
+pub type sighandler_t = *mut libc::c_void;
+
+pub const SIG_DFL: sighandler_t = 0 as sighandler_t;
+pub const SIG_ERR: sighandler_t = !0 as sighandler_t;
+
extern {
- pub fn gettimeofday(timeval: *mut libc::timeval,
- tzp: *mut libc::c_void) -> libc::c_int;
- pub fn select(nfds: libc::c_int,
- readfds: *mut fd_set,
- writefds: *mut fd_set,
- errorfds: *mut fd_set,
- timeout: *mut libc::timeval) -> libc::c_int;
pub fn getsockopt(sockfd: libc::c_int,
level: libc::c_int,
optname: libc::c_int,
pub fn waitpid(pid: libc::pid_t, status: *mut libc::c_int,
options: libc::c_int) -> libc::pid_t;
+ pub fn raise(signum: libc::c_int) -> libc::c_int;
+
pub fn sigaction(signum: libc::c_int,
act: *const sigaction,
oldact: *mut sigaction) -> libc::c_int;
- pub fn sigaddset(set: *mut sigset_t, signum: libc::c_int) -> libc::c_int;
- pub fn sigdelset(set: *mut sigset_t, signum: libc::c_int) -> libc::c_int;
+ pub fn sigaltstack(ss: *const sigaltstack,
+ oss: *mut sigaltstack) -> libc::c_int;
+
+ #[cfg(not(target_os = "android"))]
pub fn sigemptyset(set: *mut sigset_t) -> libc::c_int;
+ pub fn pthread_sigmask(how: libc::c_int, set: *const sigset_t,
+ oldset: *mut sigset_t) -> libc::c_int;
+
#[cfg(not(target_os = "ios"))]
pub fn getpwuid_r(uid: libc::uid_t,
pwd: *mut passwd,
-> *mut libc::c_char;
}
-#[cfg(any(target_os = "macos", target_os = "ios"))]
-mod select {
- pub const FD_SETSIZE: usize = 1024;
-
- #[repr(C)]
- pub struct fd_set {
- fds_bits: [i32; (FD_SETSIZE / 32)]
- }
-
- pub fn fd_set(set: &mut fd_set, fd: i32) {
- set.fds_bits[(fd / 32) as usize] |= 1 << ((fd % 32) as usize);
- }
-}
-
-#[cfg(any(target_os = "android",
- target_os = "freebsd",
- target_os = "dragonfly",
- target_os = "bitrig",
- target_os = "openbsd",
- target_os = "linux"))]
-mod select {
- use usize;
- use libc;
-
- pub const FD_SETSIZE: usize = 1024;
-
- #[repr(C)]
- pub struct fd_set {
- // FIXME: shouldn't this be a c_ulong?
- fds_bits: [libc::uintptr_t; (FD_SETSIZE / usize::BITS)]
- }
-
- pub fn fd_set(set: &mut fd_set, fd: i32) {
- let fd = fd as usize;
- set.fds_bits[fd / usize::BITS] |= 1 << (fd % usize::BITS);
- }
+// Ugh. This is only available as an inline until Android API 21.
+#[cfg(target_os = "android")]
+pub unsafe fn sigemptyset(set: *mut sigset_t) -> libc::c_int {
+ use intrinsics;
+ intrinsics::write_bytes(set, 0, 1);
+ return 0;
}
-#[cfg(any(all(target_os = "linux",
- any(target_arch = "x86",
- target_arch = "x86_64",
- target_arch = "arm",
- target_arch = "aarch64")),
+#[cfg(any(target_os = "linux",
target_os = "android"))]
-mod signal {
+mod signal_os {
+ pub use self::arch::{SA_ONSTACK, SA_SIGINFO, SIGBUS, SIG_SETMASK,
+ sigaction, sigaltstack};
use libc;
- pub const SA_NOCLDSTOP: libc::c_ulong = 0x00000001;
- pub const SA_NOCLDWAIT: libc::c_ulong = 0x00000002;
- pub const SA_NODEFER: libc::c_ulong = 0x40000000;
- pub const SA_ONSTACK: libc::c_ulong = 0x08000000;
- pub const SA_RESETHAND: libc::c_ulong = 0x80000000;
- pub const SA_RESTART: libc::c_ulong = 0x10000000;
- pub const SA_SIGINFO: libc::c_ulong = 0x00000004;
- pub const SIGCHLD: libc::c_int = 17;
-
- // This definition is not as accurate as it could be, {pid, uid, status} is
- // actually a giant union. Currently we're only interested in these fields,
- // however.
+ #[cfg(any(target_arch = "x86",
+ target_arch = "x86_64",
+ target_arch = "arm",
+ target_arch = "mips",
+ target_arch = "mipsel"))]
+ pub const SIGSTKSZ: libc::size_t = 8192;
+
+ // This is smaller on musl and Android, but no harm in being generous.
+ #[cfg(any(target_arch = "aarch64",
+ target_arch = "powerpc"))]
+ pub const SIGSTKSZ: libc::size_t = 16384;
+
+ // This definition is intentionally a subset of the C structure: the
+ // fields after si_code are actually a giant union. We're only
+ // interested in si_addr for this module, though.
#[repr(C)]
pub struct siginfo {
- si_signo: libc::c_int,
- si_errno: libc::c_int,
- si_code: libc::c_int,
- pub pid: libc::pid_t,
- pub uid: libc::uid_t,
- pub status: libc::c_int,
+ _signo: libc::c_int,
+ _errno: libc::c_int,
+ _code: libc::c_int,
+ // This structure will need extra padding here for MIPS64.
+ pub si_addr: *mut libc::c_void
}
+ #[cfg(all(target_os = "linux", target_pointer_width = "32"))]
#[repr(C)]
- pub struct sigaction {
- pub sa_handler: extern fn(libc::c_int),
- pub sa_mask: sigset_t,
- pub sa_flags: libc::c_ulong,
- sa_restorer: *mut libc::c_void,
- }
-
- unsafe impl ::marker::Send for sigaction { }
- unsafe impl ::marker::Sync for sigaction { }
-
- #[repr(C)]
- #[cfg(target_pointer_width = "32")]
pub struct sigset_t {
__val: [libc::c_ulong; 32],
}
+ #[cfg(all(target_os = "linux", target_pointer_width = "64"))]
#[repr(C)]
- #[cfg(target_pointer_width = "64")]
pub struct sigset_t {
__val: [libc::c_ulong; 16],
}
-}
-#[cfg(all(target_os = "linux",
- any(target_arch = "mips",
- target_arch = "mipsel",
- target_arch = "powerpc")))]
-mod signal {
- use libc;
-
- pub const SA_NOCLDSTOP: libc::c_ulong = 0x00000001;
- pub const SA_NOCLDWAIT: libc::c_ulong = 0x00010000;
- pub const SA_NODEFER: libc::c_ulong = 0x40000000;
- pub const SA_ONSTACK: libc::c_ulong = 0x08000000;
- pub const SA_RESETHAND: libc::c_ulong = 0x80000000;
- pub const SA_RESTART: libc::c_ulong = 0x10000000;
- pub const SA_SIGINFO: libc::c_ulong = 0x00000008;
- pub const SIGCHLD: libc::c_int = 18;
-
- // This definition is not as accurate as it could be, {pid, uid, status} is
- // actually a giant union. Currently we're only interested in these fields,
- // however.
- #[repr(C)]
- pub struct siginfo {
- si_signo: libc::c_int,
- si_code: libc::c_int,
- si_errno: libc::c_int,
- pub pid: libc::pid_t,
- pub uid: libc::uid_t,
- pub status: libc::c_int,
+ // Android for MIPS has a 128-bit sigset_t, but we don't currently
+ // support it. Android for AArch64 technically has a structure of a
+ // single ulong.
+ #[cfg(target_os = "android")]
+ pub type sigset_t = libc::c_ulong;
+
+ #[cfg(any(target_arch = "x86",
+ target_arch = "x86_64",
+ target_arch = "powerpc",
+ target_arch = "arm",
+ target_arch = "aarch64"))]
+ mod arch {
+ use libc;
+ use super::super::sighandler_t;
+ use super::sigset_t;
+
+ pub const SA_ONSTACK: libc::c_ulong = 0x08000000;
+ pub const SA_SIGINFO: libc::c_ulong = 0x00000004;
+
+ pub const SIGBUS: libc::c_int = 7;
+
+ pub const SIG_SETMASK: libc::c_int = 2;
+
+ #[cfg(target_os = "linux")]
+ #[repr(C)]
+ pub struct sigaction {
+ pub sa_sigaction: sighandler_t,
+ pub sa_mask: sigset_t,
+ pub sa_flags: libc::c_ulong,
+ _restorer: *mut libc::c_void,
+ }
+
+ #[cfg(all(target_os = "android", target_pointer_width = "32"))]
+ #[repr(C)]
+ pub struct sigaction {
+ pub sa_sigaction: sighandler_t,
+ pub sa_flags: libc::c_ulong,
+ _restorer: *mut libc::c_void,
+ pub sa_mask: sigset_t,
+ }
+
+ #[cfg(all(target_os = "android", target_pointer_width = "64"))]
+ #[repr(C)]
+ pub struct sigaction {
+ pub sa_flags: libc::c_uint,
+ pub sa_sigaction: sighandler_t,
+ pub sa_mask: sigset_t,
+ _restorer: *mut libc::c_void,
+ }
+
+ #[repr(C)]
+ pub struct sigaltstack {
+ pub ss_sp: *mut libc::c_void,
+ pub ss_flags: libc::c_int,
+ pub ss_size: libc::size_t
+ }
}
- #[repr(C)]
- pub struct sigaction {
- pub sa_flags: libc::c_uint,
- pub sa_handler: extern fn(libc::c_int),
- pub sa_mask: sigset_t,
- sa_restorer: *mut libc::c_void,
- sa_resv: [libc::c_int; 1],
- }
-
- unsafe impl ::marker::Send for sigaction { }
- unsafe impl ::marker::Sync for sigaction { }
-
- #[repr(C)]
- pub struct sigset_t {
- __val: [libc::c_ulong; 32],
+ #[cfg(any(target_arch = "mips",
+ target_arch = "mipsel"))]
+ mod arch {
+ use libc;
+ use super::super::sighandler_t;
+ use super::sigset_t;
+
+ pub const SA_ONSTACK: libc::c_ulong = 0x08000000;
+ pub const SA_SIGINFO: libc::c_ulong = 0x00000008;
+
+ pub const SIGBUS: libc::c_int = 10;
+
+ pub const SIG_SETMASK: libc::c_int = 3;
+
+ #[cfg(all(target_os = "linux", not(target_env = "musl")))]
+ #[repr(C)]
+ pub struct sigaction {
+ pub sa_flags: libc::c_uint,
+ pub sa_sigaction: sighandler_t,
+ pub sa_mask: sigset_t,
+ _restorer: *mut libc::c_void,
+ _resv: [libc::c_int; 1],
+ }
+
+ #[cfg(target_env = "musl")]
+ #[repr(C)]
+ pub struct sigaction {
+ pub sa_sigaction: sighandler_t,
+ pub sa_mask: sigset_t,
+ pub sa_flags: libc::c_ulong,
+ _restorer: *mut libc::c_void,
+ }
+
+ #[cfg(target_os = "android")]
+ #[repr(C)]
+ pub struct sigaction {
+ pub sa_flags: libc::c_uint,
+ pub sa_sigaction: sighandler_t,
+ pub sa_mask: sigset_t,
+ }
+
+ #[repr(C)]
+ pub struct sigaltstack {
+ pub ss_sp: *mut libc::c_void,
+ pub ss_size: libc::size_t,
+ pub ss_flags: libc::c_int,
+ }
}
}
#[cfg(any(target_os = "macos",
target_os = "ios",
target_os = "freebsd",
- target_os = "dragonfly"))]
-mod signal {
+ target_os = "dragonfly",
+ target_os = "bitrig",
+ target_os = "openbsd"))]
+mod signal_os {
use libc;
+ use super::sighandler_t;
pub const SA_ONSTACK: libc::c_int = 0x0001;
- pub const SA_RESTART: libc::c_int = 0x0002;
- pub const SA_RESETHAND: libc::c_int = 0x0004;
- pub const SA_NOCLDSTOP: libc::c_int = 0x0008;
- pub const SA_NODEFER: libc::c_int = 0x0010;
- pub const SA_NOCLDWAIT: libc::c_int = 0x0020;
pub const SA_SIGINFO: libc::c_int = 0x0040;
- pub const SIGCHLD: libc::c_int = 20;
+
+ pub const SIGBUS: libc::c_int = 10;
+
+ #[cfg(any(target_os = "macos", target_os = "ios"))]
+ pub const SIGSTKSZ: libc::size_t = 131072;
+ // FreeBSD's is actually arch-dependent, but never more than 40960.
+ // No harm in being generous.
+ #[cfg(not(any(target_os = "macos", target_os = "ios")))]
+ pub const SIGSTKSZ: libc::size_t = 40960;
+
+ pub const SIG_SETMASK: libc::c_int = 3;
#[cfg(any(target_os = "macos",
target_os = "ios"))]
pub struct sigset_t {
bits: [u32; 4],
}
+ #[cfg(any(target_os = "bitrig", target_os = "openbsd"))]
+ pub type sigset_t = libc::c_uint;
// This structure has more fields, but we're not all that interested in
// them.
+ #[cfg(any(target_os = "macos", target_os = "ios",
+ target_os = "freebsd", target_os = "dragonfly"))]
+ #[repr(C)]
+ pub struct siginfo {
+ pub _signo: libc::c_int,
+ pub _errno: libc::c_int,
+ pub _code: libc::c_int,
+ pub _pid: libc::pid_t,
+ pub _uid: libc::uid_t,
+ pub _status: libc::c_int,
+ pub si_addr: *mut libc::c_void
+ }
+ #[cfg(any(target_os = "bitrig", target_os = "openbsd"))]
#[repr(C)]
pub struct siginfo {
pub si_signo: libc::c_int,
- pub si_errno: libc::c_int,
pub si_code: libc::c_int,
- pub pid: libc::pid_t,
- pub uid: libc::uid_t,
- pub status: libc::c_int,
+ pub si_errno: libc::c_int,
+ pub si_addr: *mut libc::c_void
}
+ #[cfg(any(target_os = "macos", target_os = "ios",
+ target_os = "bitrig", target_os = "openbsd"))]
#[repr(C)]
pub struct sigaction {
- pub sa_handler: extern fn(libc::c_int),
- pub sa_flags: libc::c_int,
+ pub sa_sigaction: sighandler_t,
pub sa_mask: sigset_t,
+ pub sa_flags: libc::c_int,
}
-}
-
-#[cfg(any(target_os = "bitrig", target_os = "openbsd"))]
-mod signal {
- use libc;
-
- pub const SA_ONSTACK: libc::c_int = 0x0001;
- pub const SA_RESTART: libc::c_int = 0x0002;
- pub const SA_RESETHAND: libc::c_int = 0x0004;
- pub const SA_NOCLDSTOP: libc::c_int = 0x0008;
- pub const SA_NODEFER: libc::c_int = 0x0010;
- pub const SA_NOCLDWAIT: libc::c_int = 0x0020;
- pub const SA_SIGINFO: libc::c_int = 0x0040;
- pub const SIGCHLD: libc::c_int = 20;
-
- pub type sigset_t = libc::c_uint;
- // This structure has more fields, but we're not all that interested in
- // them.
+ #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
#[repr(C)]
- pub struct siginfo {
- pub si_signo: libc::c_int,
- pub si_code: libc::c_int,
- pub si_errno: libc::c_int,
- // FIXME: Bitrig has a crazy union here in the siginfo, I think this
- // layout will still work tho. The status might be off by the size of
- // a clock_t by my reading, but we can fix this later.
- pub pid: libc::pid_t,
- pub uid: libc::uid_t,
- pub status: libc::c_int,
+ pub struct sigaction {
+ pub sa_sigaction: sighandler_t,
+ pub sa_flags: libc::c_int,
+ pub sa_mask: sigset_t,
}
#[repr(C)]
- pub struct sigaction {
- pub sa_handler: extern fn(libc::c_int),
- pub sa_mask: sigset_t,
- pub sa_flags: libc::c_int,
+ pub struct sigaltstack {
+ pub ss_sp: *mut libc::c_void,
+ pub ss_size: libc::size_t,
+ pub ss_flags: libc::c_int,
}
}
unsafe impl Send for Condvar {}
unsafe impl Sync for Condvar {}
-pub const CONDVAR_INIT: Condvar = Condvar {
- inner: UnsafeCell { value: ffi::PTHREAD_COND_INITIALIZER },
-};
-
impl Condvar {
- #[inline]
- pub unsafe fn new() -> Condvar {
+ pub const fn new() -> Condvar {
// Might be moved and address is changing it is better to avoid
// initialization of potentially opaque OS data before it landed
Condvar { inner: UnsafeCell::new(ffi::PTHREAD_COND_INITIALIZER) }
let r = ffi::gettimeofday(&mut sys_now, ptr::null_mut());
debug_assert_eq!(r, 0);
+ let nsec = dur.extra_nanos() as libc::c_long +
+ (sys_now.tv_usec * 1000) as libc::c_long;
+ let extra = (nsec / 1_000_000_000) as libc::time_t;
+ let nsec = nsec % 1_000_000_000;
let seconds = dur.secs() as libc::time_t;
- let timeout = match sys_now.tv_sec.checked_add(seconds) {
- Some(sec) => {
- libc::timespec {
- tv_sec: sec,
- tv_nsec: dur.extra_nanos() as libc::c_long,
- }
- }
- None => {
- libc::timespec {
- tv_sec: <libc::time_t>::max_value(),
- tv_nsec: 1_000_000_000 - 1,
- }
+
+ let timeout = sys_now.tv_sec.checked_add(extra).and_then(|s| {
+ s.checked_add(seconds)
+ }).map(|s| {
+ libc::timespec { tv_sec: s, tv_nsec: nsec }
+ }).unwrap_or_else(|| {
+ libc::timespec {
+ tv_sec: <libc::time_t>::max_value(),
+ tv_nsec: 1_000_000_000 - 1,
}
- };
+ });
// And wait!
let r = ffi::pthread_cond_timedwait(self.inner.get(), mutex::raw(mutex),
/// # Ok(())
/// # }
/// ```
-#[stable(feature = "rust1", since = "1.0.0")]
+#[stable(feature = "symlink", since = "1.1.0")]
pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()>
{
sys::fs::symlink(src.as_ref(), dst.as_ref())
#![stable(feature = "rust1", since = "1.0.0")]
use os::unix::raw::{uid_t, gid_t};
+use os::unix::io::{FromRawFd, RawFd, AsRawFd};
use prelude::v1::*;
use process;
use sys;
-use sys_common::{AsInnerMut, AsInner};
+use sys_common::{AsInnerMut, AsInner, FromInner};
/// Unix-specific extensions to the `std::process::Command` builder
#[stable(feature = "rust1", since = "1.0.0")]
}
}
}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl FromRawFd for process::Stdio {
+ unsafe fn from_raw_fd(fd: RawFd) -> process::Stdio {
+ process::Stdio::from_inner(sys::fd::FileDesc::new(fd))
+ }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawFd for process::ChildStdin {
+ fn as_raw_fd(&self) -> RawFd {
+ self.as_inner().fd().raw()
+ }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawFd for process::ChildStdout {
+ fn as_raw_fd(&self) -> RawFd {
+ self.as_inner().fd().raw()
+ }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawFd for process::ChildStderr {
+ fn as_raw_fd(&self) -> RawFd {
+ self.as_inner().fd().raw()
+ }
+}
Ok(File(fd))
}
- pub fn into_fd(self) -> FileDesc { self.0 }
-
pub fn file_attr(&self) -> io::Result<FileAttr> {
let mut stat: raw::stat = unsafe { mem::zeroed() };
try!(cvt(unsafe {
}
let fd = self.0.raw();
- let mut b = f.debug_struct("File").field("fd", &fd);
+ let mut b = f.debug_struct("File");
+ b.field("fd", &fd);
if let Some(path) = get_path(fd) {
- b = b.field("path", &path);
+ b.field("path", &path);
}
if let Some((read, write)) = get_mode(fd) {
- b = b.field("read", &read).field("write", &write);
+ b.field("read", &read).field("write", &write);
}
b.finish()
}
m.inner.get()
}
-pub const MUTEX_INIT: Mutex = Mutex {
- inner: UnsafeCell { value: ffi::PTHREAD_MUTEX_INITIALIZER },
-};
-
unsafe impl Send for Mutex {}
unsafe impl Sync for Mutex {}
#[allow(dead_code)] // sys isn't exported yet
impl Mutex {
- #[inline]
- pub unsafe fn new() -> Mutex {
+ pub const fn new() -> Mutex {
// Might be moved and address is changing it is better to avoid
// initialization of potentially opaque OS data before it landed
- MUTEX_INIT
+ Mutex { inner: UnsafeCell::new(ffi::PTHREAD_MUTEX_INITIALIZER) }
}
#[inline]
pub unsafe fn lock(&self) {
use net::SocketAddr;
use sys::fd::FileDesc;
use sys_common::{AsInner, FromInner};
+use sys_common::net::{getsockopt, setsockopt};
+use time::Duration;
pub use sys::{cvt, cvt_r};
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
self.0.read(buf)
}
+
+ pub fn set_timeout(&self, dur: Option<Duration>, kind: libc::c_int) -> io::Result<()> {
+ let timeout = match dur {
+ Some(dur) => {
+ if dur.secs() == 0 && dur.extra_nanos() == 0 {
+ return Err(io::Error::new(io::ErrorKind::InvalidInput,
+ "cannot set a 0 duration timeout"));
+ }
+
+ let secs = if dur.secs() > libc::time_t::max_value() as u64 {
+ libc::time_t::max_value()
+ } else {
+ dur.secs() as libc::time_t
+ };
+ let mut timeout = libc::timeval {
+ tv_sec: secs,
+ tv_usec: (dur.extra_nanos() / 1000) as libc::suseconds_t,
+ };
+ if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
+ timeout.tv_usec = 1;
+ }
+ timeout
+ }
+ None => {
+ libc::timeval {
+ tv_sec: 0,
+ tv_usec: 0,
+ }
+ }
+ };
+ setsockopt(self, libc::SOL_SOCKET, kind, timeout)
+ }
+
+ pub fn timeout(&self, kind: libc::c_int) -> io::Result<Option<Duration>> {
+ let raw: libc::timeval = try!(getsockopt(self, libc::SOL_SOCKET, kind));
+ if raw.tv_sec == 0 && raw.tv_usec == 0 {
+ Ok(None)
+ } else {
+ let sec = raw.tv_sec as u64;
+ let nsec = (raw.tv_usec as u32) * 1000;
+ Ok(Some(Duration::new(sec, nsec)))
+ }
+ }
}
impl AsInner<c_int> for Socket {
#[cfg(any(target_os = "bitrig", target_os = "openbsd"))]
pub fn current_exe() -> io::Result<PathBuf> {
- use sync::{StaticMutex, MUTEX_INIT};
- static LOCK: StaticMutex = MUTEX_INIT;
+ use sync::StaticMutex;
+ static LOCK: StaticMutex = StaticMutex::new();
extern {
fn rust_current_exe() -> *const c_char;
self.0.write(buf)
}
- pub fn into_fd(self) -> FileDesc {
- self.0
- }
+ pub fn raw(&self) -> libc::c_int { self.0.raw() }
+ pub fn fd(&self) -> &FileDesc { &self.0 }
}
use fmt;
use io::{self, Error, ErrorKind};
use libc::{self, pid_t, c_void, c_int, gid_t, uid_t};
+use mem;
use ptr;
+use sys::fd::FileDesc;
+use sys::fs::{File, OpenOptions};
use sys::pipe::AnonPipe;
use sys::{self, c, cvt, cvt_r};
-use sys::fs::{File, OpenOptions};
////////////////////////////////////////////////////////////////////////////////
// Command
pub enum Stdio {
Inherit,
- Piped(AnonPipe),
None,
+ Raw(c_int),
}
+pub type RawStdio = FileDesc;
+
const CLOEXEC_MSG_FOOTER: &'static [u8] = b"NOEX";
impl Process {
}
let setup = |src: Stdio, dst: c_int| {
- let fd = match src {
- Stdio::Inherit => return true,
- Stdio::Piped(pipe) => pipe.into_fd(),
+ match src {
+ Stdio::Inherit => true,
+ Stdio::Raw(fd) => cvt_r(|| libc::dup2(fd, dst)).is_ok(),
// If a stdio file descriptor is set to be ignored, we open up
// /dev/null into that file descriptor. Otherwise, the first
let devnull = CStr::from_ptr(b"/dev/null\0".as_ptr()
as *const _);
if let Ok(f) = File::open_c(devnull, &opts) {
- f.into_fd()
+ cvt_r(|| libc::dup2(f.fd().raw(), dst)).is_ok()
} else {
- return false
+ false
}
}
- };
- cvt_r(|| libc::dup2(fd.raw(), dst)).is_ok()
+ }
};
if !setup(in_fd, libc::STDIN_FILENO) { fail(&mut output) }
if !envp.is_null() {
*sys::os::environ() = envp as *const _;
}
- let _ = libc::execvp(*argv, argv as *mut _);
+
+ // Reset signal handling so the child process starts in a
+ // standardized state. libstd ignores SIGPIPE, and signal-handling
+ // libraries often set a mask. Child processes inherit ignored
+ // signals and the signal mask from their parent, but most
+ // UNIX programs do not reset these things on their own, so we
+ // need to clean things up now to avoid confusing the program
+ // we're about to run.
+ let mut set: c::sigset_t = mem::uninitialized();
+ if c::sigemptyset(&mut set) != 0 ||
+ c::pthread_sigmask(c::SIG_SETMASK, &set, ptr::null_mut()) != 0 ||
+ libc::funcs::posix01::signal::signal(
+ libc::SIGPIPE, mem::transmute(c::SIG_DFL)
+ ) == mem::transmute(c::SIG_ERR) {
+ fail(&mut output);
+ }
+
+ let _ = libc::execvp(*argv, argv);
fail(&mut output)
}
+ pub fn id(&self) -> u32 {
+ self.pid as u32
+ }
+
pub fn wait(&self) -> io::Result<ExitStatus> {
let mut status = 0 as c_int;
try!(cvt_r(|| unsafe { c::waitpid(self.pid, &mut status, 0) }));
ExitStatus::Signal(imp::WTERMSIG(status))
}
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use prelude::v1::*;
+
+ use ffi::OsStr;
+ use mem;
+ use ptr;
+ use libc;
+ use slice;
+ use sys::{self, c, cvt, pipe};
+
+ #[cfg(not(target_os = "android"))]
+ extern {
+ fn sigaddset(set: *mut c::sigset_t, signum: libc::c_int) -> libc::c_int;
+ }
+
+ #[cfg(target_os = "android")]
+ unsafe fn sigaddset(set: *mut c::sigset_t, signum: libc::c_int) -> libc::c_int {
+ let raw = slice::from_raw_parts_mut(set as *mut u8, mem::size_of::<c::sigset_t>());
+ let bit = (signum - 1) as usize;
+ raw[bit / 8] |= 1 << (bit % 8);
+ return 0;
+ }
+
+ #[test]
+ fn test_process_mask() {
+ unsafe {
+ // Test to make sure that a signal mask does not get inherited.
+ let cmd = Command::new(OsStr::new("cat"));
+ let (stdin_read, stdin_write) = sys::pipe::anon_pipe().unwrap();
+ let (stdout_read, stdout_write) = sys::pipe::anon_pipe().unwrap();
+
+ let mut set: c::sigset_t = mem::uninitialized();
+ let mut old_set: c::sigset_t = mem::uninitialized();
+ cvt(c::sigemptyset(&mut set)).unwrap();
+ cvt(sigaddset(&mut set, libc::SIGINT)).unwrap();
+ cvt(c::pthread_sigmask(c::SIG_SETMASK, &set, &mut old_set)).unwrap();
+
+ let cat = Process::spawn(&cmd, Stdio::Raw(stdin_read.raw()),
+ Stdio::Raw(stdout_write.raw()),
+ Stdio::None).unwrap();
+ drop(stdin_read);
+ drop(stdout_write);
+
+ cvt(c::pthread_sigmask(c::SIG_SETMASK, &old_set, ptr::null_mut())).unwrap();
+
+ cvt(libc::funcs::posix88::signal::kill(cat.id() as libc::pid_t, libc::SIGINT)).unwrap();
+ // We need to wait until SIGINT is definitely delivered. The
+ // easiest way is to write something to cat, and try to read it
+ // back: if SIGINT is unmasked, it'll get delivered when cat is
+ // next scheduled.
+ let _ = stdin_write.write(b"Hello");
+ drop(stdin_write);
+
+ // Either EOF or failure (EPIPE) is okay.
+ let mut buf = [0; 5];
+ if let Ok(ret) = stdout_read.read(&mut buf) {
+ assert!(ret == 0);
+ }
+
+ cat.wait().unwrap();
+ }
+ }
+}
pub struct RWLock { inner: UnsafeCell<ffi::pthread_rwlock_t> }
-pub const RWLOCK_INIT: RWLock = RWLock {
- inner: UnsafeCell { value: ffi::PTHREAD_RWLOCK_INITIALIZER },
-};
-
unsafe impl Send for RWLock {}
unsafe impl Sync for RWLock {}
impl RWLock {
+ pub const fn new() -> RWLock {
+ RWLock { inner: UnsafeCell::new(ffi::PTHREAD_RWLOCK_INITIALIZER) }
+ }
#[inline]
pub unsafe fn read(&self) {
let r = ffi::pthread_rwlock_rdlock(self.inner.get());
use mem;
use ptr;
use intrinsics;
- use self::signal::{siginfo, sigaction, SIGBUS, SIG_DFL,
- SA_SIGINFO, SA_ONSTACK, sigaltstack,
- SIGSTKSZ};
+ use sys::c::{siginfo, sigaction, SIGBUS, SIG_DFL,
+ SA_SIGINFO, SA_ONSTACK, sigaltstack,
+ SIGSTKSZ, sighandler_t, raise};
use libc;
use libc::funcs::posix88::mman::{mmap, munmap};
+ use libc::funcs::posix01::signal::signal;
use libc::consts::os::posix88::{SIGSEGV,
PROT_READ,
PROT_WRITE,
pub unsafe fn make_handler() -> Handler {
let alt_stack = mmap(ptr::null_mut(),
- signal::SIGSTKSZ,
+ SIGSTKSZ,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANON,
-1,
pub unsafe fn drop_handler(handler: &mut Handler) {
munmap(handler._data, SIGSTKSZ);
}
-
- pub type sighandler_t = *mut libc::c_void;
-
- #[cfg(any(all(target_os = "linux", target_arch = "x86"), // may not match
- all(target_os = "linux", target_arch = "x86_64"),
- all(target_os = "linux", target_arch = "arm"), // may not match
- all(target_os = "linux", target_arch = "aarch64"),
- all(target_os = "linux", target_arch = "mips"), // may not match
- all(target_os = "linux", target_arch = "mipsel"), // may not match
- all(target_os = "linux", target_arch = "powerpc"), // may not match
- target_os = "android"))] // may not match
- mod signal {
- use libc;
- pub use super::sighandler_t;
-
- pub static SA_ONSTACK: libc::c_int = 0x08000000;
- pub static SA_SIGINFO: libc::c_int = 0x00000004;
- pub static SIGBUS: libc::c_int = 7;
-
- pub static SIGSTKSZ: libc::size_t = 8192;
-
- pub const SIG_DFL: sighandler_t = 0 as sighandler_t;
-
- // This definition is not as accurate as it could be, {si_addr} is
- // actually a giant union. Currently we're only interested in that field,
- // however.
- #[repr(C)]
- pub struct siginfo {
- si_signo: libc::c_int,
- si_errno: libc::c_int,
- si_code: libc::c_int,
- pub si_addr: *mut libc::c_void
- }
-
- #[repr(C)]
- pub struct sigaction {
- pub sa_sigaction: sighandler_t,
- pub sa_mask: sigset_t,
- pub sa_flags: libc::c_int,
- sa_restorer: *mut libc::c_void,
- }
-
- #[cfg(target_pointer_width = "32")]
- #[repr(C)]
- pub struct sigset_t {
- __val: [libc::c_ulong; 32],
- }
- #[cfg(target_pointer_width = "64")]
- #[repr(C)]
- pub struct sigset_t {
- __val: [libc::c_ulong; 16],
- }
-
- #[repr(C)]
- pub struct sigaltstack {
- pub ss_sp: *mut libc::c_void,
- pub ss_flags: libc::c_int,
- pub ss_size: libc::size_t
- }
-
- }
-
- #[cfg(any(target_os = "macos",
- target_os = "bitrig",
- target_os = "openbsd"))]
- mod signal {
- use libc;
- pub use super::sighandler_t;
-
- pub const SA_ONSTACK: libc::c_int = 0x0001;
- pub const SA_SIGINFO: libc::c_int = 0x0040;
- pub const SIGBUS: libc::c_int = 10;
-
- #[cfg(target_os = "macos")]
- pub const SIGSTKSZ: libc::size_t = 131072;
- #[cfg(any(target_os = "bitrig", target_os = "openbsd"))]
- pub const SIGSTKSZ: libc::size_t = 40960;
-
- pub const SIG_DFL: sighandler_t = 0 as sighandler_t;
-
- pub type sigset_t = u32;
-
- // This structure has more fields, but we're not all that interested in
- // them.
- #[cfg(target_os = "macos")]
- #[repr(C)]
- pub struct siginfo {
- pub si_signo: libc::c_int,
- pub si_errno: libc::c_int,
- pub si_code: libc::c_int,
- pub pid: libc::pid_t,
- pub uid: libc::uid_t,
- pub status: libc::c_int,
- pub si_addr: *mut libc::c_void
- }
-
- #[cfg(any(target_os = "bitrig", target_os = "openbsd"))]
- #[repr(C)]
- pub struct siginfo {
- pub si_signo: libc::c_int,
- pub si_code: libc::c_int,
- pub si_errno: libc::c_int,
- //union
- pub si_addr: *mut libc::c_void
- }
-
- #[repr(C)]
- pub struct sigaltstack {
- pub ss_sp: *mut libc::c_void,
- pub ss_size: libc::size_t,
- pub ss_flags: libc::c_int
- }
-
- #[repr(C)]
- pub struct sigaction {
- pub sa_sigaction: sighandler_t,
- pub sa_mask: sigset_t,
- pub sa_flags: libc::c_int,
- }
- }
-
- extern {
- pub fn signal(signum: libc::c_int, handler: sighandler_t) -> sighandler_t;
- pub fn raise(signum: libc::c_int) -> libc::c_int;
-
- pub fn sigaction(signum: libc::c_int,
- act: *const sigaction,
- oldact: *mut sigaction) -> libc::c_int;
-
- pub fn sigaltstack(ss: *const sigaltstack,
- oss: *mut sigaltstack) -> libc::c_int;
- }
}
#[cfg(not(any(target_os = "linux",
pub struct Stderr(());
impl Stdin {
- pub fn new() -> Stdin { Stdin(()) }
+ pub fn new() -> io::Result<Stdin> { Ok(Stdin(())) }
pub fn read(&self, data: &mut [u8]) -> io::Result<usize> {
let fd = FileDesc::new(libc::STDIN_FILENO);
}
impl Stdout {
- pub fn new() -> Stdout { Stdout(()) }
+ pub fn new() -> io::Result<Stdout> { Ok(Stdout(())) }
pub fn write(&self, data: &[u8]) -> io::Result<usize> {
let fd = FileDesc::new(libc::STDOUT_FILENO);
}
impl Stderr {
- pub fn new() -> Stderr { Stderr(()) }
+ pub fn new() -> io::Result<Stderr> { Ok(Stderr(())) }
pub fn write(&self, data: &[u8]) -> io::Result<usize> {
let fd = FileDesc::new(libc::STDERR_FILENO);
#[cfg(target_os = "linux")]
fn min_stack_size(attr: *const libc::pthread_attr_t) -> usize {
use dynamic_lib::DynamicLibrary;
- use sync::{Once, ONCE_INIT};
+ use sync::Once;
type F = unsafe extern "C" fn(*const libc::pthread_attr_t) -> libc::size_t;
- static INIT: Once = ONCE_INIT;
+ static INIT: Once = Once::new();
static mut __pthread_get_minstack: Option<F> = None;
INIT.call_once(|| {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)] // sys isn't exported yet
+
use prelude::v1::*;
use libc::c_int;
use libc;
use time::Duration;
use ops::Sub;
- use sync::{Once, ONCE_INIT};
+ use sync::Once;
use super::NSEC_PER_SEC;
pub struct SteadyTime {
numer: 0,
denom: 0,
};
- static ONCE: Once = ONCE_INIT;
+ static ONCE: Once = Once::new();
unsafe {
ONCE.call_once(|| {
use path::Path;
use ptr;
use str;
-use sync::{StaticMutex, MUTEX_INIT};
+use sync::StaticMutex;
use sys_common::backtrace::*;
pub fn write(w: &mut Write) -> io::Result<()> {
// According to windows documentation, all dbghelp functions are
// single-threaded.
- static LOCK: StaticMutex = MUTEX_INIT;
+ static LOCK: StaticMutex = StaticMutex::new();
let _g = LOCK.lock();
// Open up dbghelp.dll, we don't link to it explicitly because it can't
-> $rettype:ty { $fallback:expr }) => (
#[inline(always)]
pub unsafe fn $symbol($($argname: $argtype),*) -> $rettype {
- use sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
+ use sync::atomic::{AtomicUsize, Ordering};
use mem;
- static PTR: AtomicUsize = ATOMIC_USIZE_INIT;
+ static PTR: AtomicUsize = AtomicUsize::new(0);
fn load() -> usize {
::sys::c::compat::store_func(&PTR,
dwMilliseconds: libc::DWORD) -> libc::DWORD;
pub fn SwitchToThread() -> libc::BOOL;
pub fn Sleep(dwMilliseconds: libc::DWORD);
+ pub fn GetProcessId(handle: libc::HANDLE) -> libc::DWORD;
}
#[link(name = "userenv")]
unsafe impl Send for Condvar {}
unsafe impl Sync for Condvar {}
-pub const CONDVAR_INIT: Condvar = Condvar {
- inner: UnsafeCell { value: ffi::CONDITION_VARIABLE_INIT }
-};
-
impl Condvar {
- #[inline]
- pub unsafe fn new() -> Condvar { CONDVAR_INIT }
+ pub const fn new() -> Condvar {
+ Condvar { inner: UnsafeCell::new(ffi::CONDITION_VARIABLE_INIT) }
+ }
#[inline]
pub unsafe fn wait(&self, mutex: &Mutex) {
pub trait OpenOptionsExt {
/// Overrides the `dwDesiredAccess` argument to the call to `CreateFile`
/// with the specified value.
- fn desired_access(&mut self, access: i32) -> &mut Self;
+ fn desired_access(&mut self, access: u32) -> &mut Self;
/// Overrides the `dwCreationDisposition` argument to the call to
/// `CreateFile` with the specified value.
///
/// This will override any values of the standard `create` flags, for
/// example.
- fn creation_disposition(&mut self, val: i32) -> &mut Self;
+ fn creation_disposition(&mut self, val: u32) -> &mut Self;
/// Overrides the `dwFlagsAndAttributes` argument to the call to
/// `CreateFile` with the specified value.
///
/// This will override any values of the standard flags on the
/// `OpenOptions` structure.
- fn flags_and_attributes(&mut self, val: i32) -> &mut Self;
+ fn flags_and_attributes(&mut self, val: u32) -> &mut Self;
/// Overrides the `dwShareMode` argument to the call to `CreateFile` with
/// the specified value.
///
/// This will override any values of the standard flags on the
/// `OpenOptions` structure.
- fn share_mode(&mut self, val: i32) -> &mut Self;
+ fn share_mode(&mut self, val: u32) -> &mut Self;
}
impl OpenOptionsExt for OpenOptions {
- fn desired_access(&mut self, access: i32) -> &mut OpenOptions {
+ fn desired_access(&mut self, access: u32) -> &mut OpenOptions {
self.as_inner_mut().desired_access(access); self
}
- fn creation_disposition(&mut self, access: i32) -> &mut OpenOptions {
+ fn creation_disposition(&mut self, access: u32) -> &mut OpenOptions {
self.as_inner_mut().creation_disposition(access); self
}
- fn flags_and_attributes(&mut self, access: i32) -> &mut OpenOptions {
+ fn flags_and_attributes(&mut self, access: u32) -> &mut OpenOptions {
self.as_inner_mut().flags_and_attributes(access); self
}
- fn share_mode(&mut self, access: i32) -> &mut OpenOptions {
+ fn share_mode(&mut self, access: u32) -> &mut OpenOptions {
self.as_inner_mut().share_mode(access); self
}
}
/// # Ok(())
/// # }
/// ```
-#[stable(feature = "rust1", since = "1.0.0")]
+#[stable(feature = "symlink", since = "1.1.0")]
pub fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q)
-> io::Result<()> {
sys::fs::symlink_inner(src.as_ref(), dst.as_ref(), false)
/// # Ok(())
/// # }
/// ```
-#[stable(feature = "rust1", since = "1.0.0")]
+#[stable(feature = "symlink", since = "1.1.0")]
pub fn symlink_dir<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q)
-> io::Result<()> {
sys::fs::symlink_inner(src.as_ref(), dst.as_ref(), true)
pub mod fs;
pub mod io;
pub mod raw;
+pub mod process;
/// A prelude for conveniently writing platform-specific code.
///
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Extensions to `std::process` for Windows.
+
+#![stable(feature = "process_extensions", since = "1.2.0")]
+
+use os::windows::io::{FromRawHandle, RawHandle, AsRawHandle};
+use process;
+use sys;
+use sys_common::{AsInner, FromInner};
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl FromRawHandle for process::Stdio {
+ unsafe fn from_raw_handle(handle: RawHandle) -> process::Stdio {
+ let handle = sys::handle::Handle::new(handle as *mut _);
+ process::Stdio::from_inner(handle)
+ }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawHandle for process::Child {
+ fn as_raw_handle(&self) -> RawHandle {
+ self.as_inner().handle().raw() as *mut _
+ }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawHandle for process::ChildStdin {
+ fn as_raw_handle(&self) -> RawHandle {
+ self.as_inner().handle().raw() as *mut _
+ }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawHandle for process::ChildStdout {
+ fn as_raw_handle(&self) -> RawHandle {
+ self.as_inner().handle().raw() as *mut _
+ }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawHandle for process::ChildStderr {
+ fn as_raw_handle(&self) -> RawHandle {
+ self.as_inner().handle().raw() as *mut _
+ }
+}
//! Windows-specific primitives
-#[stable(feature = "raw_ext", since = "1.1.0")]
+#![stable(feature = "raw_ext", since = "1.1.0")]
use os::raw::c_void;
pub fn append(&mut self, append: bool) { self.append = append; }
pub fn create(&mut self, create: bool) { self.create = create; }
pub fn truncate(&mut self, truncate: bool) { self.truncate = truncate; }
- pub fn creation_disposition(&mut self, val: i32) {
- self.creation_disposition = Some(val as libc::DWORD);
+ pub fn creation_disposition(&mut self, val: u32) {
+ self.creation_disposition = Some(val);
}
- pub fn flags_and_attributes(&mut self, val: i32) {
- self.flags_and_attributes = Some(val as libc::DWORD);
+ pub fn flags_and_attributes(&mut self, val: u32) {
+ self.flags_and_attributes = Some(val);
}
- pub fn desired_access(&mut self, val: i32) {
- self.desired_access = Some(val as libc::DWORD);
+ pub fn desired_access(&mut self, val: u32) {
+ self.desired_access = Some(val);
}
- pub fn share_mode(&mut self, val: i32) {
- self.share_mode = Some(val as libc::DWORD);
+ pub fn share_mode(&mut self, val: u32) {
+ self.share_mode = Some(val);
}
pub fn security_attributes(&mut self, attrs: libc::LPSECURITY_ATTRIBUTES) {
self.security_attributes = attrs as usize;
fn open_reparse_point(path: &Path) -> io::Result<File> {
let mut opts = OpenOptions::new();
opts.read(true);
- opts.flags_and_attributes(c::FILE_FLAG_OPEN_REPARSE_POINT as i32);
+ opts.flags_and_attributes(c::FILE_FLAG_OPEN_REPARSE_POINT);
File::open(path, &opts)
}
}
pub fn to_utf16(s: &Path) -> Vec<u16> {
- s.as_os_str().encode_wide().chain(Some(0).into_iter()).collect()
+ s.as_os_str().encode_wide().chain(Some(0)).collect()
}
impl FileAttr {
use libc::funcs::extra::kernel32::{GetCurrentProcess, DuplicateHandle};
use libc::{self, HANDLE};
use mem;
+use ops::Deref;
use ptr;
use sys::cvt;
-pub struct Handle(HANDLE);
+/// An owned container for `HANDLE` object, closing them on Drop.
+///
+/// All methods are inherited through a `Deref` impl to `RawHandle`
+pub struct Handle(RawHandle);
-unsafe impl Send for Handle {}
-unsafe impl Sync for Handle {}
+/// A wrapper type for `HANDLE` objects to give them proper Send/Sync inference
+/// as well as Rust-y methods.
+///
+/// This does **not** drop the handle when it goes out of scope, use `Handle`
+/// instead for that.
+#[derive(Copy, Clone)]
+pub struct RawHandle(HANDLE);
+
+unsafe impl Send for RawHandle {}
+unsafe impl Sync for RawHandle {}
impl Handle {
pub fn new(handle: HANDLE) -> Handle {
- Handle(handle)
+ Handle(RawHandle::new(handle))
}
- pub fn raw(&self) -> HANDLE { self.0 }
-
pub fn into_raw(self) -> HANDLE {
- let ret = self.0;
+ let ret = self.raw();
mem::forget(self);
return ret;
}
+}
+
+impl Deref for Handle {
+ type Target = RawHandle;
+ fn deref(&self) -> &RawHandle { &self.0 }
+}
+
+impl Drop for Handle {
+ fn drop(&mut self) {
+ unsafe { let _ = libc::CloseHandle(self.raw()); }
+ }
+}
+
+impl RawHandle {
+ pub fn new(handle: HANDLE) -> RawHandle {
+ RawHandle(handle)
+ }
+
+ pub fn raw(&self) -> HANDLE { self.0 }
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
let mut read = 0;
Ok(Handle::new(ret))
}
}
-
-impl Drop for Handle {
- fn drop(&mut self) {
- unsafe { let _ = libc::CloseHandle(self.0); }
- }
-}
libc::WSAEINVAL => ErrorKind::InvalidInput,
libc::WSAENOTCONN => ErrorKind::NotConnected,
libc::WSAEWOULDBLOCK => ErrorKind::WouldBlock,
+ libc::WSAETIMEDOUT => ErrorKind::TimedOut,
_ => ErrorKind::Other,
}
pub struct Mutex { inner: UnsafeCell<ffi::SRWLOCK> }
-pub const MUTEX_INIT: Mutex = Mutex {
- inner: UnsafeCell { value: ffi::SRWLOCK_INIT }
-};
-
unsafe impl Send for Mutex {}
unsafe impl Sync for Mutex {}
// is there there are no guarantees of fairness.
impl Mutex {
+ pub const fn new() -> Mutex {
+ Mutex { inner: UnsafeCell::new(ffi::SRWLOCK_INIT) }
+ }
#[inline]
pub unsafe fn lock(&self) {
ffi::AcquireSRWLockExclusive(self.inner.get())
use num::One;
use ops::Neg;
use rt;
-use sync::{Once, ONCE_INIT};
+use sync::Once;
+use sys;
use sys::c;
use sys_common::{AsInner, FromInner};
+use sys_common::net::{setsockopt, getsockopt};
+use time::Duration;
pub type wrlen_t = i32;
/// Checks whether the Windows socket interface has been started already, and
/// if not, starts it.
pub fn init() {
- static START: Once = ONCE_INIT;
+ static START: Once = Once::new();
START.call_once(|| unsafe {
let mut data: c::WSADATA = mem::zeroed();
}
}
}
+
+ pub fn set_timeout(&self, dur: Option<Duration>, kind: libc::c_int) -> io::Result<()> {
+ let timeout = match dur {
+ Some(dur) => {
+ let timeout = sys::dur2timeout(dur);
+ if timeout == 0 {
+ return Err(io::Error::new(io::ErrorKind::InvalidInput,
+ "cannot set a 0 duration timeout"));
+ }
+ timeout
+ }
+ None => 0
+ };
+ setsockopt(self, libc::SOL_SOCKET, kind, timeout)
+ }
+
+ pub fn timeout(&self, kind: libc::c_int) -> io::Result<Option<Duration>> {
+ let raw: libc::DWORD = try!(getsockopt(self, libc::SOL_SOCKET, kind));
+ if raw == 0 {
+ Ok(None)
+ } else {
+ let secs = raw / 1000;
+ let nsec = (raw % 1000) * 1000000;
+ Ok(Some(Duration::new(secs as u64, nsec as u32)))
+ }
+ }
}
impl Drop for Socket {
impl AnonPipe {
pub fn handle(&self) -> &Handle { &self.inner }
+ pub fn raw(&self) -> libc::HANDLE { self.inner.raw() }
+
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
self.inner.read(buf)
}
use os::windows::ffi::OsStrExt;
use path::Path;
use ptr;
-use sync::{StaticMutex, MUTEX_INIT};
+use sync::StaticMutex;
use sys::c;
use sys::fs::{OpenOptions, File};
-use sys::handle::Handle;
-use sys::pipe::AnonPipe;
+use sys::handle::{Handle, RawHandle};
use sys::stdio;
use sys::{self, cvt};
use sys_common::{AsInner, FromInner};
pub enum Stdio {
Inherit,
- Piped(AnonPipe),
None,
+ Raw(libc::HANDLE),
}
+pub type RawStdio = Handle;
+
impl Process {
pub fn spawn(cfg: &Command,
in_handle: Stdio,
try!(unsafe {
// `CreateProcess` is racy!
// http://support.microsoft.com/kb/315939
- static CREATE_PROCESS_LOCK: StaticMutex = MUTEX_INIT;
+ static CREATE_PROCESS_LOCK: StaticMutex = StaticMutex::new();
let _lock = CREATE_PROCESS_LOCK.lock();
cvt(CreateProcessW(ptr::null(),
Ok(())
}
+ pub fn id(&self) -> u32 {
+ unsafe {
+ c::GetProcessId(self.handle.raw()) as u32
+ }
+ }
+
pub fn wait(&self) -> io::Result<ExitStatus> {
use libc::{STILL_ACTIVE, INFINITE, WAIT_OBJECT_0};
use libc::{GetExitCodeProcess, WaitForSingleObject};
}
}
}
+
+ pub fn handle(&self) -> &Handle { &self.handle }
}
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
io.handle().duplicate(0, true, DUPLICATE_SAME_ACCESS)
})
}
- Stdio::Piped(ref pipe) => {
- pipe.handle().duplicate(0, true, DUPLICATE_SAME_ACCESS)
+ Stdio::Raw(handle) => {
+ RawHandle::new(handle).duplicate(0, true, DUPLICATE_SAME_ACCESS)
}
// Similarly to unix, we don't actually leave holes for the
pub struct RWLock { inner: UnsafeCell<ffi::SRWLOCK> }
-pub const RWLOCK_INIT: RWLock = RWLock {
- inner: UnsafeCell { value: ffi::SRWLOCK_INIT }
-};
-
unsafe impl Send for RWLock {}
unsafe impl Sync for RWLock {}
impl RWLock {
+ pub const fn new() -> RWLock {
+ RWLock { inner: UnsafeCell::new(ffi::SRWLOCK_INIT) }
+ }
#[inline]
pub unsafe fn read(&self) {
ffi::AcquireSRWLockShared(self.inner.get())
}
impl Stdin {
- pub fn new() -> Stdin {
- Stdin {
- handle: get(c::STD_INPUT_HANDLE).unwrap(),
- utf8: Mutex::new(Cursor::new(Vec::new())),
- }
+ pub fn new() -> io::Result<Stdin> {
+ get(c::STD_INPUT_HANDLE).map(|handle| {
+ Stdin {
+ handle: handle,
+ utf8: Mutex::new(Cursor::new(Vec::new())),
+ }
+ })
}
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
}
impl Stdout {
- pub fn new() -> Stdout {
- Stdout(get(c::STD_OUTPUT_HANDLE).unwrap())
+ pub fn new() -> io::Result<Stdout> {
+ get(c::STD_OUTPUT_HANDLE).map(Stdout)
}
pub fn write(&self, data: &[u8]) -> io::Result<usize> {
}
impl Stderr {
- pub fn new() -> Stderr {
- Stderr(get(c::STD_ERROR_HANDLE).unwrap())
+ pub fn new() -> io::Result<Stderr> {
+ get(c::STD_ERROR_HANDLE).map(Stderr)
}
pub fn write(&self, data: &[u8]) -> io::Result<usize> {
}
fn invalid_encoding() -> io::Error {
- io::Error::new(io::ErrorKind::InvalidInput, "text was not valid unicode")
+ io::Error::new(io::ErrorKind::InvalidData, "text was not valid unicode")
}
use libc::types::os::arch::extra::{DWORD, LPVOID, BOOL};
-use boxed;
use ptr;
use rt;
-use sys_common::mutex::{MUTEX_INIT, Mutex};
+use sys_common::mutex::Mutex;
pub type Key = DWORD;
pub type Dtor = unsafe extern fn(*mut u8);
// on poisoning and this module needs to operate at a lower level than requiring
// the thread infrastructure to be in place (useful on the borders of
// initialization/destruction).
-static DTOR_LOCK: Mutex = MUTEX_INIT;
+static DTOR_LOCK: Mutex = Mutex::new();
static mut DTORS: *mut Vec<(Key, Dtor)> = 0 as *mut _;
// -------------------------------------------------------------------------
DTOR_LOCK.unlock();
});
if res.is_ok() {
- DTORS = boxed::into_raw(dtors);
+ DTORS = Box::into_raw(dtors);
} else {
DTORS = 1 as *mut _;
}
use libc;
use ops::Sub;
use time::Duration;
-use sync::{Once, ONCE_INIT};
+use sync::Once;
const NANOS_PER_SEC: u64 = 1_000_000_000;
fn frequency() -> libc::LARGE_INTEGER {
static mut FREQUENCY: libc::LARGE_INTEGER = 0;
- static ONCE: Once = ONCE_INIT;
+ static ONCE: Once = Once::new();
unsafe {
ONCE.call_once(|| {
// Sure wish we had macro hygiene, no?
#[doc(hidden)]
-pub mod __impl {
- pub use super::imp::Key as KeyInner;
- pub use super::imp::destroy_value;
- pub use sys_common::thread_local::INIT_INNER as OS_INIT_INNER;
- pub use sys_common::thread_local::StaticKey as OsStaticKey;
-}
+pub use self::imp::Key as __KeyInner;
/// A thread local storage key which owns its contents.
///
//
// This is trivially devirtualizable by LLVM because we never store anything
// to this field and rustc can declare the `static` as constant as well.
- #[doc(hidden)]
- pub inner: fn() -> &'static __impl::KeyInner<UnsafeCell<Option<T>>>,
+ inner: fn() -> &'static __KeyInner<T>,
// initialization routine to invoke to create a value
- #[doc(hidden)]
- pub init: fn() -> T,
-}
-
-/// Declare a new thread local storage key of type `std::thread::LocalKey`.
-///
-/// See [LocalKey documentation](thread/struct.LocalKey.html) for more information.
-#[macro_export]
-#[stable(feature = "rust1", since = "1.0.0")]
-#[allow_internal_unstable]
-macro_rules! thread_local {
- (static $name:ident: $t:ty = $init:expr) => (
- static $name: ::std::thread::LocalKey<$t> = {
- use std::cell::UnsafeCell as __UnsafeCell;
- use std::thread::__local::KeyInner as __KeyInner;
- use std::option::Option as __Option;
- use std::option::Option::None as __None;
-
- __thread_local_inner!(static __KEY: __UnsafeCell<__Option<$t>> = {
- __UnsafeCell { value: __None }
- });
- fn __init() -> $t { $init }
- fn __getit() -> &'static __KeyInner<__UnsafeCell<__Option<$t>>> {
- &__KEY
- }
- ::std::thread::LocalKey { inner: __getit, init: __init }
- };
- );
- (pub static $name:ident: $t:ty = $init:expr) => (
- pub static $name: ::std::thread::LocalKey<$t> = {
- use std::cell::UnsafeCell as __UnsafeCell;
- use std::thread::__local::KeyInner as __KeyInner;
- use std::option::Option as __Option;
- use std::option::Option::None as __None;
-
- __thread_local_inner!(static __KEY: __UnsafeCell<__Option<$t>> = {
- __UnsafeCell { value: __None }
- });
- fn __init() -> $t { $init }
- fn __getit() -> &'static __KeyInner<__UnsafeCell<__Option<$t>>> {
- &__KEY
- }
- ::std::thread::LocalKey { inner: __getit, init: __init }
- };
- );
+ init: fn() -> T,
}
// Macro pain #4586:
// To get around this, we're forced to inject the #[cfg] logic into the macro
// itself. Woohoo.
+/// Declare a new thread local storage key of type `std::thread::LocalKey`.
+///
+/// See [LocalKey documentation](thread/struct.LocalKey.html) for more
+/// information.
#[macro_export]
-#[doc(hidden)]
+#[stable(feature = "rust1", since = "1.0.0")]
#[allow_internal_unstable]
#[cfg(not(no_elf_tls))]
-macro_rules! __thread_local_inner {
+macro_rules! thread_local {
(static $name:ident: $t:ty = $init:expr) => (
- #[cfg_attr(all(any(target_os = "macos", target_os = "linux"),
- not(target_arch = "aarch64")),
- thread_local)]
- static $name: ::std::thread::__local::KeyInner<$t> =
- __thread_local_inner!($init, $t);
+ static $name: ::std::thread::LocalKey<$t> =
+ __thread_local_inner!($t, $init,
+ #[cfg_attr(all(any(target_os = "macos", target_os = "linux"),
+ not(target_arch = "aarch64")),
+ thread_local)]);
);
(pub static $name:ident: $t:ty = $init:expr) => (
- #[cfg_attr(all(any(target_os = "macos", target_os = "linux"),
- not(target_arch = "aarch64")),
- thread_local)]
- pub static $name: ::std::thread::__local::KeyInner<$t> =
- __thread_local_inner!($init, $t);
+ pub static $name: ::std::thread::LocalKey<$t> =
+ __thread_local_inner!($t, $init,
+ #[cfg_attr(all(any(target_os = "macos", target_os = "linux"),
+ not(target_arch = "aarch64")),
+ thread_local)]);
);
- ($init:expr, $t:ty) => ({
- #[cfg(all(any(target_os = "macos", target_os = "linux"), not(target_arch = "aarch64")))]
- const _INIT: ::std::thread::__local::KeyInner<$t> = {
- ::std::thread::__local::KeyInner {
- inner: ::std::cell::UnsafeCell { value: $init },
- dtor_registered: ::std::cell::UnsafeCell { value: false },
- dtor_running: ::std::cell::UnsafeCell { value: false },
- }
- };
-
- #[allow(trivial_casts)]
- #[cfg(any(not(any(target_os = "macos", target_os = "linux")), target_arch = "aarch64"))]
- const _INIT: ::std::thread::__local::KeyInner<$t> = {
- ::std::thread::__local::KeyInner {
- inner: ::std::cell::UnsafeCell { value: $init },
- os: ::std::thread::__local::OsStaticKey {
- inner: ::std::thread::__local::OS_INIT_INNER,
- dtor: ::std::option::Option::Some(
- ::std::thread::__local::destroy_value::<$t>
- ),
- },
- }
- };
-
- _INIT
- });
}
#[macro_export]
-#[doc(hidden)]
+#[stable(feature = "rust1", since = "1.0.0")]
#[allow_internal_unstable]
#[cfg(no_elf_tls)]
-macro_rules! __thread_local_inner {
+macro_rules! thread_local {
(static $name:ident: $t:ty = $init:expr) => (
- static $name: ::std::thread::__local::KeyInner<$t> =
- __thread_local_inner!($init, $t);
+ static $name: ::std::thread::LocalKey<$t> =
+ __thread_local_inner!($t, $init, #[]);
);
(pub static $name:ident: $t:ty = $init:expr) => (
- pub static $name: ::std::thread::__local::KeyInner<$t> =
- __thread_local_inner!($init, $t);
+ pub static $name: ::std::thread::LocalKey<$t> =
+ __thread_local_inner!($t, $init, #[]);
);
- ($init:expr, $t:ty) => ({
- #[allow(trivial_casts)]
- const _INIT: ::std::thread::__local::KeyInner<$t> = {
- ::std::thread::__local::KeyInner {
- inner: ::std::cell::UnsafeCell { value: $init },
- os: ::std::thread::__local::OsStaticKey {
- inner: ::std::thread::__local::OS_INIT_INNER,
- dtor: ::std::option::Option::Some(
- ::std::thread::__local::destroy_value::<$t>
- ),
- },
- }
- };
+}
- _INIT
- });
+#[doc(hidden)]
+#[unstable(feature = "thread_local_internals",
+ reason = "should not be necessary")]
+#[macro_export]
+#[allow_internal_unstable]
+macro_rules! __thread_local_inner {
+ ($t:ty, $init:expr, #[$($attr:meta),*]) => {{
+ $(#[$attr])*
+ static __KEY: ::std::thread::__LocalKeyInner<$t> =
+ ::std::thread::__LocalKeyInner::new();
+ fn __init() -> $t { $init }
+ fn __getit() -> &'static ::std::thread::__LocalKeyInner<$t> { &__KEY }
+ ::std::thread::LocalKey::new(__getit, __init)
+ }}
}
/// Indicator of the state of a thread local storage key.
-#[unstable(feature = "std_misc",
+#[unstable(feature = "thread_local_state",
reason = "state querying was recently added")]
#[derive(Eq, PartialEq, Copy, Clone)]
pub enum LocalKeyState {
}
impl<T: 'static> LocalKey<T> {
+ #[doc(hidden)]
+ #[unstable(feature = "thread_local_internals",
+ reason = "recently added to create a key")]
+ pub const fn new(inner: fn() -> &'static __KeyInner<T>,
+ init: fn() -> T) -> LocalKey<T> {
+ LocalKey {
+ inner: inner,
+ init: init
+ }
+ }
+
/// Acquires a reference to the value in this TLS key.
///
/// This will lazily initialize the value if this thread has not referenced
/// initialization does not panic. Keys in the `Valid` state are guaranteed
/// to be able to be accessed. Keys in the `Destroyed` state will panic on
/// any call to `with`.
- #[unstable(feature = "std_misc",
+ #[unstable(feature = "thread_local_state",
reason = "state querying was recently added")]
pub fn state(&'static self) -> LocalKeyState {
unsafe {
mod imp {
use prelude::v1::*;
- use cell::UnsafeCell;
+ use cell::{Cell, UnsafeCell};
use intrinsics;
- use ptr;
pub struct Key<T> {
- // Place the inner bits in an `UnsafeCell` to currently get around the
- // "only Sync statics" restriction. This allows any type to be placed in
- // the cell.
- //
- // Note that all access requires `T: 'static` so it can't be a type with
- // any borrowed pointers still.
- pub inner: UnsafeCell<T>,
+ inner: UnsafeCell<Option<T>>,
// Metadata to keep track of the state of the destructor. Remember that
// these variables are thread-local, not global.
- pub dtor_registered: UnsafeCell<bool>, // should be Cell
- pub dtor_running: UnsafeCell<bool>, // should be Cell
+ dtor_registered: Cell<bool>,
+ dtor_running: Cell<bool>,
}
unsafe impl<T> ::marker::Sync for Key<T> { }
impl<T> Key<T> {
- pub unsafe fn get(&'static self) -> Option<&'static T> {
- if intrinsics::needs_drop::<T>() && *self.dtor_running.get() {
+ pub const fn new() -> Key<T> {
+ Key {
+ inner: UnsafeCell::new(None),
+ dtor_registered: Cell::new(false),
+ dtor_running: Cell::new(false)
+ }
+ }
+
+ pub unsafe fn get(&'static self) -> Option<&'static UnsafeCell<Option<T>>> {
+ if intrinsics::needs_drop::<T>() && self.dtor_running.get() {
return None
}
self.register_dtor();
- Some(&*self.inner.get())
+ Some(&self.inner)
}
unsafe fn register_dtor(&self) {
- if !intrinsics::needs_drop::<T>() || *self.dtor_registered.get() {
+ if !intrinsics::needs_drop::<T>() || self.dtor_registered.get() {
return
}
register_dtor(self as *const _ as *mut u8,
destroy_value::<T>);
- *self.dtor_registered.get() = true;
+ self.dtor_registered.set(true);
}
}
// Due to rust-lang/rust#18804, make sure this is not generic!
#[cfg(target_os = "linux")]
unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
- use boxed;
use mem;
+ use ptr;
use libc;
use sys_common::thread_local as os;
// *should* be the case that this loop always terminates because we
// provide the guarantee that a TLS key cannot be set after it is
// flagged for destruction.
- static DTORS: os::StaticKey = os::StaticKey {
- inner: os::INIT_INNER,
- dtor: Some(run_dtors as unsafe extern "C" fn(*mut u8)),
- };
+ static DTORS: os::StaticKey = os::StaticKey::new(Some(run_dtors));
type List = Vec<(*mut u8, unsafe extern fn(*mut u8))>;
if DTORS.get().is_null() {
let v: Box<List> = box Vec::new();
- DTORS.set(boxed::into_raw(v) as *mut u8);
+ DTORS.set(Box::into_raw(v) as *mut u8);
}
let list: &mut List = &mut *(DTORS.get() as *mut List);
list.push((t, dtor));
unsafe extern fn run_dtors(mut ptr: *mut u8) {
while !ptr.is_null() {
let list: Box<List> = Box::from_raw(ptr as *mut List);
- for &(ptr, dtor) in &*list {
+ for &(ptr, dtor) in list.iter() {
dtor(ptr);
}
ptr = DTORS.get();
// Right before we run the user destructor be sure to flag the
// destructor as running for this thread so calls to `get` will return
// `None`.
- *(*ptr).dtor_running.get() = true;
- ptr::read((*ptr).inner.get());
+ (*ptr).dtor_running.set(true);
+ intrinsics::drop_in_place((*ptr).inner.get());
}
}
mod imp {
use prelude::v1::*;
- use alloc::boxed;
- use cell::UnsafeCell;
- use mem;
+ use cell::{Cell, UnsafeCell};
+ use marker;
use ptr;
use sys_common::thread_local::StaticKey as OsStaticKey;
pub struct Key<T> {
- // Statically allocated initialization expression, using an `UnsafeCell`
- // for the same reasons as above.
- pub inner: UnsafeCell<T>,
-
// OS-TLS key that we'll use to key off.
- pub os: OsStaticKey,
+ os: OsStaticKey,
+ marker: marker::PhantomData<Cell<T>>,
}
unsafe impl<T> ::marker::Sync for Key<T> { }
struct Value<T: 'static> {
key: &'static Key<T>,
- value: T,
+ value: UnsafeCell<Option<T>>,
}
- impl<T> Key<T> {
- pub unsafe fn get(&'static self) -> Option<&'static T> {
- self.ptr().map(|p| &*p)
+ impl<T: 'static> Key<T> {
+ pub const fn new() -> Key<T> {
+ Key {
+ os: OsStaticKey::new(Some(destroy_value::<T>)),
+ marker: marker::PhantomData
+ }
}
- unsafe fn ptr(&'static self) -> Option<*mut T> {
+ pub unsafe fn get(&'static self) -> Option<&'static UnsafeCell<Option<T>>> {
let ptr = self.os.get() as *mut Value<T>;
if !ptr.is_null() {
if ptr as usize == 1 {
return None
}
- return Some(&mut (*ptr).value as *mut T);
+ return Some(&(*ptr).value);
}
// If the lookup returned null, we haven't initialized our own local
// copy, so do that now.
- //
- // Also note that this transmute_copy should be ok because the value
- // `inner` is already validated to be a valid `static` value, so we
- // should be able to freely copy the bits.
let ptr: Box<Value<T>> = box Value {
key: self,
- value: mem::transmute_copy(&self.inner),
+ value: UnsafeCell::new(None),
};
- let ptr = boxed::into_raw(ptr);
+ let ptr = Box::into_raw(ptr);
self.os.set(ptr as *mut u8);
- Some(&mut (*ptr).value as *mut T)
+ Some(&(*ptr).value)
}
}
use prelude::v1::*;
use sync::mpsc::{channel, Sender};
- use cell::UnsafeCell;
+ use cell::{Cell, UnsafeCell};
use super::LocalKeyState;
use thread;
#[test]
fn smoke_no_dtor() {
- thread_local!(static FOO: UnsafeCell<i32> = UnsafeCell { value: 1 });
+ thread_local!(static FOO: Cell<i32> = Cell::new(1));
- FOO.with(|f| unsafe {
- assert_eq!(*f.get(), 1);
- *f.get() = 2;
+ FOO.with(|f| {
+ assert_eq!(f.get(), 1);
+ f.set(2);
});
let (tx, rx) = channel();
let _t = thread::spawn(move|| {
- FOO.with(|f| unsafe {
- assert_eq!(*f.get(), 1);
+ FOO.with(|f| {
+ assert_eq!(f.get(), 1);
});
tx.send(()).unwrap();
});
rx.recv().unwrap();
- FOO.with(|f| unsafe {
- assert_eq!(*f.get(), 2);
+ FOO.with(|f| {
+ assert_eq!(f.get(), 2);
});
}
#[test]
fn smoke_dtor() {
- thread_local!(static FOO: UnsafeCell<Option<Foo>> = UnsafeCell {
- value: None
- });
+ thread_local!(static FOO: UnsafeCell<Option<Foo>> = UnsafeCell::new(None));
let (tx, rx) = channel();
let _t = thread::spawn(move|| unsafe {
fn circular() {
struct S1;
struct S2;
- thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell {
- value: None
- });
- thread_local!(static K2: UnsafeCell<Option<S2>> = UnsafeCell {
- value: None
- });
+ thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell::new(None));
+ thread_local!(static K2: UnsafeCell<Option<S2>> = UnsafeCell::new(None));
static mut HITS: u32 = 0;
impl Drop for S1 {
#[test]
fn self_referential() {
struct S1;
- thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell {
- value: None
- });
+ thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell::new(None));
impl Drop for S1 {
fn drop(&mut self) {
#[test]
fn dtors_in_dtors_in_dtors() {
struct S1(Sender<()>);
- thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell {
- value: None
- });
- thread_local!(static K2: UnsafeCell<Option<Foo>> = UnsafeCell {
- value: None
- });
+ thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell::new(None));
+ thread_local!(static K2: UnsafeCell<Option<Foo>> = UnsafeCell::new(None));
impl Drop for S1 {
fn drop(&mut self) {
consider stabilizing its interface")]
pub use self::scoped_tls::ScopedKey;
-#[doc(hidden)] pub use self::local::__impl as __local;
-#[doc(hidden)] pub use self::scoped_tls::__impl as __scoped;
+#[doc(hidden)] pub use self::local::__KeyInner as __LocalKeyInner;
+#[doc(hidden)] pub use self::scoped_tls::__KeyInner as __ScopedKeyInner;
////////////////////////////////////////////////////////////////////////////////
// Builder
/// the OS level.
#[unstable(feature = "scoped",
reason = "memory unsafe if destructor is avoided, see #24292")]
+ #[deprecated(since = "1.2.0",
+ reason = "this unsafe API is unlikely to ever be stabilized \
+ in this form")]
pub fn scoped<'a, T, F>(self, f: F) -> io::Result<JoinGuard<'a, T>> where
T: Send + 'a, F: FnOnce() -> T, F: Send + 'a
{
/// to recover from such errors.
#[unstable(feature = "scoped",
reason = "memory unsafe if destructor is avoided, see #24292")]
+#[deprecated(since = "1.2.0",
+ reason = "this unsafe API is unlikely to ever be stabilized \
+ in this form")]
+#[allow(deprecated)]
pub fn scoped<'a, T, F>(f: F) -> JoinGuard<'a, T> where
T: Send + 'a, F: FnOnce() -> T, F: Send + 'a
{
use prelude::v1::*;
-// macro hygiene sure would be nice, wouldn't it?
#[doc(hidden)]
-pub mod __impl {
- pub use super::imp::KeyInner;
- pub use sys_common::thread_local::INIT as OS_INIT;
-}
+pub use self::imp::KeyInner as __KeyInner;
/// Type representing a thread local storage key corresponding to a reference
/// to the type parameter `T`.
#[unstable(feature = "scoped_tls",
reason = "scoped TLS has yet to have wide enough use to fully consider \
stabilizing its interface")]
-pub struct ScopedKey<T> { #[doc(hidden)] pub inner: __impl::KeyInner<T> }
+pub struct ScopedKey<T> { inner: fn() -> &'static imp::KeyInner<T> }
/// Declare a new scoped thread local storage key.
///
/// information.
#[macro_export]
#[allow_internal_unstable]
-#[cfg(not(no_elf_tls))]
macro_rules! scoped_thread_local {
(static $name:ident: $t:ty) => (
- __scoped_thread_local_inner!(static $name: $t);
+ static $name: ::std::thread::ScopedKey<$t> =
+ __scoped_thread_local_inner!($t);
);
(pub static $name:ident: $t:ty) => (
- __scoped_thread_local_inner!(pub static $name: $t);
+ pub static $name: ::std::thread::ScopedKey<$t> =
+ __scoped_thread_local_inner!($t);
);
}
+#[doc(hidden)]
+#[unstable(feature = "thread_local_internals",
+ reason = "should not be necessary")]
#[macro_export]
+#[allow_internal_unstable]
+#[cfg(no_elf_tls)]
+macro_rules! __scoped_thread_local_inner {
+ ($t:ty) => {{
+ static _KEY: ::std::thread::__ScopedKeyInner<$t> =
+ ::std::thread::__ScopedKeyInner::new();
+ fn _getit() -> &'static ::std::thread::__ScopedKeyInner<$t> { &_KEY }
+ ::std::thread::ScopedKey::new(_getit)
+ }}
+}
+
#[doc(hidden)]
+#[unstable(feature = "thread_local_internals",
+ reason = "should not be necessary")]
+#[macro_export]
#[allow_internal_unstable]
+#[cfg(not(no_elf_tls))]
macro_rules! __scoped_thread_local_inner {
- (static $name:ident: $t:ty) => (
+ ($t:ty) => {{
#[cfg_attr(not(any(windows,
target_os = "android",
target_os = "ios",
target_os = "openbsd",
target_arch = "aarch64")),
thread_local)]
- static $name: ::std::thread::ScopedKey<$t> =
- __scoped_thread_local_inner!($t);
- );
- (pub static $name:ident: $t:ty) => (
- #[cfg_attr(not(any(windows,
- target_os = "android",
- target_os = "ios",
- target_os = "openbsd",
- target_arch = "aarch64")),
- thread_local)]
- pub static $name: ::std::thread::ScopedKey<$t> =
- __scoped_thread_local_inner!($t);
- );
- ($t:ty) => ({
- use std::thread::ScopedKey as __Key;
-
- #[cfg(not(any(windows,
- target_os = "android",
- target_os = "ios",
- target_os = "openbsd",
- target_arch = "aarch64")))]
- const _INIT: __Key<$t> = __Key {
- inner: ::std::thread::__scoped::KeyInner {
- inner: ::std::cell::UnsafeCell { value: 0 as *mut _ },
- }
- };
-
- #[cfg(any(windows,
- target_os = "android",
- target_os = "ios",
- target_os = "openbsd",
- target_arch = "aarch64"))]
- const _INIT: __Key<$t> = __Key {
- inner: ::std::thread::__scoped::KeyInner {
- inner: ::std::thread::__scoped::OS_INIT,
- marker: ::std::marker::PhantomData::<::std::cell::Cell<$t>>,
- }
- };
-
- _INIT
- })
-}
-
-#[macro_export]
-#[allow_internal_unstable]
-#[cfg(no_elf_tls)]
-macro_rules! scoped_thread_local {
- (static $name:ident: $t:ty) => (
- static $name: ::std::thread::ScopedKey<$t> =
- ::std::thread::ScopedKey::new();
- );
- (pub static $name:ident: $t:ty) => (
- pub static $name: ::std::thread::ScopedKey<$t> =
- ::std::thread::ScopedKey::new();
- );
+ static _KEY: ::std::thread::__ScopedKeyInner<$t> =
+ ::std::thread::__ScopedKeyInner::new();
+ fn _getit() -> &'static ::std::thread::__ScopedKeyInner<$t> { &_KEY }
+ ::std::thread::ScopedKey::new(_getit)
+ }}
}
#[unstable(feature = "scoped_tls",
reason = "scoped TLS has yet to have wide enough use to fully consider \
stabilizing its interface")]
impl<T> ScopedKey<T> {
+ #[doc(hidden)]
+ pub const fn new(inner: fn() -> &'static imp::KeyInner<T>) -> ScopedKey<T> {
+ ScopedKey { inner: inner }
+ }
+
/// Inserts a value into this scoped thread local storage slot for a
/// duration of a closure.
///
F: FnOnce() -> R,
{
struct Reset<'a, T: 'a> {
- key: &'a __impl::KeyInner<T>,
+ key: &'a imp::KeyInner<T>,
val: *mut T,
}
impl<'a, T> Drop for Reset<'a, T> {
}
}
+ let inner = (self.inner)();
let prev = unsafe {
- let prev = self.inner.get();
- self.inner.set(t as *const T as *mut T);
+ let prev = inner.get();
+ inner.set(t as *const T as *mut T);
prev
};
- let _reset = Reset { key: &self.inner, val: prev };
+ let _reset = Reset { key: inner, val: prev };
cb()
}
F: FnOnce(&T) -> R
{
unsafe {
- let ptr = self.inner.get();
+ let ptr = (self.inner)().get();
assert!(!ptr.is_null(), "cannot access a scoped thread local \
variable without calling `set` first");
cb(&*ptr)
/// Test whether this TLS key has been `set` for the current thread.
pub fn is_set(&'static self) -> bool {
- unsafe { !self.inner.get().is_null() }
+ unsafe { !(self.inner)().get().is_null() }
}
}
target_os = "openbsd",
target_arch = "aarch64",
no_elf_tls)))]
+#[doc(hidden)]
mod imp {
- use std::cell::UnsafeCell;
+ use std::cell::Cell;
- #[doc(hidden)]
- pub struct KeyInner<T> { pub inner: UnsafeCell<*mut T> }
+ pub struct KeyInner<T> { inner: Cell<*mut T> }
unsafe impl<T> ::marker::Sync for KeyInner<T> { }
- #[doc(hidden)]
impl<T> KeyInner<T> {
- #[doc(hidden)]
- pub unsafe fn set(&self, ptr: *mut T) { *self.inner.get() = ptr; }
- #[doc(hidden)]
- pub unsafe fn get(&self) -> *mut T { *self.inner.get() }
+ pub const fn new() -> KeyInner<T> {
+ KeyInner { inner: Cell::new(0 as *mut _) }
+ }
+ pub unsafe fn set(&self, ptr: *mut T) { self.inner.set(ptr); }
+ pub unsafe fn get(&self) -> *mut T { self.inner.get() }
}
}
target_os = "openbsd",
target_arch = "aarch64",
no_elf_tls))]
+#[doc(hidden)]
mod imp {
+ use prelude::v1::*;
+
+ use cell::Cell;
use marker;
- use std::cell::Cell;
use sys_common::thread_local::StaticKey as OsStaticKey;
- #[doc(hidden)]
pub struct KeyInner<T> {
pub inner: OsStaticKey,
pub marker: marker::PhantomData<Cell<T>>,
}
- unsafe impl<T> ::marker::Sync for KeyInner<T> { }
+ unsafe impl<T> marker::Sync for KeyInner<T> { }
- #[doc(hidden)]
impl<T> KeyInner<T> {
- #[doc(hidden)]
+ pub const fn new() -> KeyInner<T> {
+ KeyInner {
+ inner: OsStaticKey::new(None),
+ marker: marker::PhantomData
+ }
+ }
pub unsafe fn set(&self, ptr: *mut T) { self.inner.set(ptr as *mut _) }
- #[doc(hidden)]
pub unsafe fn get(&self) -> *mut T { self.inner.get() as *mut _ }
}
}
// Because this module is temporary...
#![allow(missing_docs)]
-#![unstable(feature = "std_misc")]
+#![unstable(feature = "thunk")]
+#![deprecated(since = "1.2.0", reason = "use FnBox instead")]
use alloc::boxed::{Box, FnBox};
use core::marker::Send;
use parse::token::{InternedString, str_to_ident};
use parse::token;
use parse::lexer;
+use print::pprust;
use ptr::P;
+use std::cell::Cell;
use std::fmt;
use std::rc::Rc;
use serialize::{Encodable, Decodable, Encoder, Decoder};
/// Function name (not all functions have names)
pub type FnIdent = Option<Ident>;
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash,
- Debug, Copy)]
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)]
pub struct Lifetime {
pub id: NodeId,
pub span: Span,
pub name: Name
}
+impl fmt::Debug for Lifetime {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "lifetime({}: {})", self.id, pprust::lifetime_to_string(self))
+ }
+}
+
/// A lifetime definition, eg `'a: 'b+'c+'d`
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct LifetimeDef {
/// A "Path" is essentially Rust's notion of a name; for instance:
/// std::cmp::PartialEq . It's represented as a sequence of identifiers,
/// along with a bunch of supporting information.
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)]
pub struct Path {
pub span: Span,
/// A `::foo` path, is relative to the crate root rather than current
pub segments: Vec<PathSegment>,
}
+impl fmt::Debug for Path {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "path({})", pprust::path_to_string(self))
+ }
+}
+
+impl fmt::Display for Path {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{}", pprust::path_to_string(self))
+ }
+}
+
/// A segment of a path: an identifier, an optional lifetime, and a set of
/// types.
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub type NodeId = u32;
#[derive(Clone, Eq, Ord, PartialOrd, PartialEq, RustcEncodable,
- RustcDecodable, Hash, Debug, Copy)]
+ RustcDecodable, Hash, Copy)]
pub struct DefId {
pub krate: CrateNum,
pub node: NodeId,
}
+fn default_def_id_debug(_: DefId, _: &mut fmt::Formatter) -> fmt::Result { Ok(()) }
+
+thread_local!(pub static DEF_ID_DEBUG: Cell<fn(DefId, &mut fmt::Formatter) -> fmt::Result> =
+ Cell::new(default_def_id_debug));
+
+impl fmt::Debug for DefId {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ try!(write!(f, "DefId {{ krate: {}, node: {} }}",
+ self.krate, self.node));
+ DEF_ID_DEBUG.with(|def_id_debug| def_id_debug.get()(*self, f))
+ }
+}
+
impl DefId {
/// Read the node id, asserting that this def-id is krate-local.
pub fn local_id(&self) -> NodeId {
pub span: Span,
}
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)]
pub struct Pat {
pub id: NodeId,
pub node: Pat_,
pub span: Span,
}
+impl fmt::Debug for Pat {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "pat({}: {})", self.id, pprust::pat_to_string(self))
+ }
+}
+
/// A single field in a struct pattern
///
/// Patterns like the fields of Foo `{ x, ref y, ref mut z }`
/// A statement
pub type Stmt = Spanned<Stmt_>;
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+impl fmt::Debug for Stmt {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "stmt({}: {})",
+ ast_util::stmt_id(self),
+ pprust::stmt_to_string(self))
+ }
+}
+
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)]
pub enum Stmt_ {
/// Could be an item or a local (let) binding:
StmtDecl(P<Decl>, NodeId),
StmtMac(P<Mac>, MacStmtStyle),
}
-
#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum MacStmtStyle {
/// The macro statement had a trailing semicolon, e.g. `foo! { ... };`
}
/// An expression
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash,)]
pub struct Expr {
pub id: NodeId,
pub node: Expr_,
pub span: Span,
}
+impl fmt::Debug for Expr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "expr({}: {})", self.id, pprust::expr_to_string(self))
+ }
+}
+
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum Expr_ {
/// First expr is the place; second expr is the value.
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct MethodSig {
pub unsafety: Unsafety,
+ pub constness: Constness,
pub abi: Abi,
pub decl: P<FnDecl>,
pub generics: Generics,
// NB PartialEq method appears below.
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)]
pub struct Ty {
pub id: NodeId,
pub node: Ty_,
pub span: Span,
}
+impl fmt::Debug for Ty {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "type({})", pprust::ty_to_string(self))
+ }
+}
+
/// Not represented directly in the AST, referred to by name through a ty_path.
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
pub enum PrimTy {
Normal,
}
+#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub enum Constness {
+ Const,
+ NotConst,
+}
+
impl fmt::Display for Unsafety {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(match *self {
/// A `const` item
ItemConst(P<Ty>, P<Expr>),
/// A function declaration
- ItemFn(P<FnDecl>, Unsafety, Abi, Generics, P<Block>),
+ ItemFn(P<FnDecl>, Unsafety, Constness, Abi, Generics, P<Block>),
/// A module
ItemMod(Mod),
/// An external module
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! This module provides a simplified abstraction for working with
-//! code blocks identified by their integer node-id. In particular,
-//! it captures a common set of attributes that all "function-like
-//! things" (represented by `FnLike` instances) share. For example,
-//! all `FnLike` instances have a type signature (be it explicit or
-//! inferred). And all `FnLike` instances have a body, i.e. the code
-//! that is run when the function-like thing it represents is invoked.
-//!
-//! With the above abstraction in place, one can treat the program
-//! text as a collection of blocks of code (and most such blocks are
-//! nested within a uniquely determined `FnLike`), and users can ask
-//! for the `Code` associated with a particular NodeId.
-
-pub use self::Code::*;
-
-use abi;
-use ast::{Block, FnDecl, NodeId};
-use ast;
-use ast_map::Node;
-use ast_map;
-use codemap::Span;
-use visit;
-
-/// An FnLikeNode is a Node that is like a fn, in that it has a decl
-/// and a body (as well as a NodeId, a span, etc).
-///
-/// More specifically, it is one of either:
-/// - A function item,
-/// - A closure expr (i.e. an ExprClosure), or
-/// - The default implementation for a trait method.
-///
-/// To construct one, use the `Code::from_node` function.
-#[derive(Copy, Clone)]
-pub struct FnLikeNode<'a> { node: ast_map::Node<'a> }
-
-/// MaybeFnLike wraps a method that indicates if an object
-/// corresponds to some FnLikeNode.
-pub trait MaybeFnLike { fn is_fn_like(&self) -> bool; }
-
-/// Components shared by fn-like things (fn items, methods, closures).
-pub struct FnParts<'a> {
- pub decl: &'a FnDecl,
- pub body: &'a Block,
- pub kind: visit::FnKind<'a>,
- pub span: Span,
- pub id: NodeId,
-}
-
-impl MaybeFnLike for ast::Item {
- fn is_fn_like(&self) -> bool {
- match self.node { ast::ItemFn(..) => true, _ => false, }
- }
-}
-
-impl MaybeFnLike for ast::TraitItem {
- fn is_fn_like(&self) -> bool {
- match self.node { ast::MethodTraitItem(_, Some(_)) => true, _ => false, }
- }
-}
-
-impl MaybeFnLike for ast::Expr {
- fn is_fn_like(&self) -> bool {
- match self.node {
- ast::ExprClosure(..) => true,
- _ => false,
- }
- }
-}
-
-/// Carries either an FnLikeNode or a Block, as these are the two
-/// constructs that correspond to "code" (as in, something from which
-/// we can construct a control-flow graph).
-#[derive(Copy, Clone)]
-pub enum Code<'a> {
- FnLikeCode(FnLikeNode<'a>),
- BlockCode(&'a Block),
-}
-
-impl<'a> Code<'a> {
- pub fn id(&self) -> ast::NodeId {
- match *self {
- FnLikeCode(node) => node.id(),
- BlockCode(block) => block.id,
- }
- }
-
- /// Attempts to construct a Code from presumed FnLike or Block node input.
- pub fn from_node(node: Node) -> Option<Code> {
- fn new(node: Node) -> FnLikeNode { FnLikeNode { node: node } }
- match node {
- ast_map::NodeItem(item) if item.is_fn_like() =>
- Some(FnLikeCode(new(node))),
- ast_map::NodeTraitItem(tm) if tm.is_fn_like() =>
- Some(FnLikeCode(new(node))),
- ast_map::NodeImplItem(_) =>
- Some(FnLikeCode(new(node))),
- ast_map::NodeExpr(e) if e.is_fn_like() =>
- Some(FnLikeCode(new(node))),
- ast_map::NodeBlock(block) =>
- Some(BlockCode(block)),
- _ =>
- None,
- }
- }
-}
-
-/// These are all the components one can extract from a fn item for
-/// use when implementing FnLikeNode operations.
-struct ItemFnParts<'a> {
- ident: ast::Ident,
- decl: &'a ast::FnDecl,
- unsafety: ast::Unsafety,
- abi: abi::Abi,
- vis: ast::Visibility,
- generics: &'a ast::Generics,
- body: &'a Block,
- id: ast::NodeId,
- span: Span
-}
-
-/// These are all the components one can extract from a closure expr
-/// for use when implementing FnLikeNode operations.
-struct ClosureParts<'a> {
- decl: &'a FnDecl,
- body: &'a Block,
- id: NodeId,
- span: Span
-}
-
-impl<'a> ClosureParts<'a> {
- fn new(d: &'a FnDecl, b: &'a Block, id: NodeId, s: Span) -> ClosureParts<'a> {
- ClosureParts { decl: d, body: b, id: id, span: s }
- }
-}
-
-impl<'a> FnLikeNode<'a> {
- pub fn to_fn_parts(self) -> FnParts<'a> {
- FnParts {
- decl: self.decl(),
- body: self.body(),
- kind: self.kind(),
- span: self.span(),
- id: self.id(),
- }
- }
-
- pub fn body(self) -> &'a Block {
- self.handle(|i: ItemFnParts<'a>| &*i.body,
- |_, _, _: &'a ast::MethodSig, _, body: &'a ast::Block, _| body,
- |c: ClosureParts<'a>| c.body)
- }
-
- pub fn decl(self) -> &'a FnDecl {
- self.handle(|i: ItemFnParts<'a>| &*i.decl,
- |_, _, sig: &'a ast::MethodSig, _, _, _| &sig.decl,
- |c: ClosureParts<'a>| c.decl)
- }
-
- pub fn span(self) -> Span {
- self.handle(|i: ItemFnParts| i.span,
- |_, _, _: &'a ast::MethodSig, _, _, span| span,
- |c: ClosureParts| c.span)
- }
-
- pub fn id(self) -> NodeId {
- self.handle(|i: ItemFnParts| i.id,
- |id, _, _: &'a ast::MethodSig, _, _, _| id,
- |c: ClosureParts| c.id)
- }
-
- pub fn kind(self) -> visit::FnKind<'a> {
- let item = |p: ItemFnParts<'a>| -> visit::FnKind<'a> {
- visit::FkItemFn(p.ident, p.generics, p.unsafety, p.abi, p.vis)
- };
- let closure = |_: ClosureParts| {
- visit::FkFnBlock
- };
- let method = |_, ident, sig: &'a ast::MethodSig, vis, _, _| {
- visit::FkMethod(ident, sig, vis)
- };
- self.handle(item, method, closure)
- }
-
- fn handle<A, I, M, C>(self, item_fn: I, method: M, closure: C) -> A where
- I: FnOnce(ItemFnParts<'a>) -> A,
- M: FnOnce(NodeId,
- ast::Ident,
- &'a ast::MethodSig,
- Option<ast::Visibility>,
- &'a ast::Block,
- Span)
- -> A,
- C: FnOnce(ClosureParts<'a>) -> A,
- {
- match self.node {
- ast_map::NodeItem(i) => match i.node {
- ast::ItemFn(ref decl, unsafety, abi, ref generics, ref block) =>
- item_fn(ItemFnParts{
- ident: i.ident, decl: &**decl, unsafety: unsafety, body: &**block,
- generics: generics, abi: abi, vis: i.vis, id: i.id, span: i.span
- }),
- _ => panic!("item FnLikeNode that is not fn-like"),
- },
- ast_map::NodeTraitItem(ti) => match ti.node {
- ast::MethodTraitItem(ref sig, Some(ref body)) => {
- method(ti.id, ti.ident, sig, None, body, ti.span)
- }
- _ => panic!("trait method FnLikeNode that is not fn-like"),
- },
- ast_map::NodeImplItem(ii) => {
- match ii.node {
- ast::MethodImplItem(ref sig, ref body) => {
- method(ii.id, ii.ident, sig, Some(ii.vis), body, ii.span)
- }
- _ => {
- panic!("impl method FnLikeNode that is not fn-like")
- }
- }
- }
- ast_map::NodeExpr(e) => match e.node {
- ast::ExprClosure(_, ref decl, ref block) =>
- closure(ClosureParts::new(&**decl, &**block, e.id, e.span)),
- _ => panic!("expr FnLikeNode that is not fn-like"),
- },
- _ => panic!("other FnLikeNode that is not fn-like"),
- }
- }
-}
+++ /dev/null
-// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-pub use self::Node::*;
-pub use self::PathElem::*;
-use self::MapEntry::*;
-
-use abi;
-use ast::*;
-use ast_util;
-use codemap::{DUMMY_SP, Span, Spanned};
-use fold::Folder;
-use parse::token;
-use print::pprust;
-use visit::{self, Visitor};
-
-use arena::TypedArena;
-use std::cell::RefCell;
-use std::fmt;
-use std::io;
-use std::iter::{self, repeat};
-use std::mem;
-use std::slice;
-
-pub mod blocks;
-
-#[derive(Clone, Copy, PartialEq, Debug)]
-pub enum PathElem {
- PathMod(Name),
- PathName(Name)
-}
-
-impl PathElem {
- pub fn name(&self) -> Name {
- match *self {
- PathMod(name) | PathName(name) => name
- }
- }
-}
-
-impl fmt::Display for PathElem {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- let slot = token::get_name(self.name());
- write!(f, "{}", slot)
- }
-}
-
-#[derive(Clone)]
-pub struct LinkedPathNode<'a> {
- node: PathElem,
- next: LinkedPath<'a>,
-}
-
-#[derive(Copy, Clone)]
-pub struct LinkedPath<'a>(Option<&'a LinkedPathNode<'a>>);
-
-impl<'a> LinkedPath<'a> {
- pub fn empty() -> LinkedPath<'a> {
- LinkedPath(None)
- }
-
- pub fn from(node: &'a LinkedPathNode) -> LinkedPath<'a> {
- LinkedPath(Some(node))
- }
-}
-
-impl<'a> Iterator for LinkedPath<'a> {
- type Item = PathElem;
-
- fn next(&mut self) -> Option<PathElem> {
- match self.0 {
- Some(node) => {
- *self = node.next;
- Some(node.node)
- }
- None => None
- }
- }
-}
-
-/// The type of the iterator used by with_path.
-pub type PathElems<'a, 'b> = iter::Chain<iter::Cloned<slice::Iter<'a, PathElem>>, LinkedPath<'b>>;
-
-pub fn path_to_string<PI: Iterator<Item=PathElem>>(path: PI) -> String {
- let itr = token::get_ident_interner();
-
- path.fold(String::new(), |mut s, e| {
- let e = itr.get(e.name());
- if !s.is_empty() {
- s.push_str("::");
- }
- s.push_str(&e[..]);
- s
- })
-}
-
-#[derive(Copy, Clone, Debug)]
-pub enum Node<'ast> {
- NodeItem(&'ast Item),
- NodeForeignItem(&'ast ForeignItem),
- NodeTraitItem(&'ast TraitItem),
- NodeImplItem(&'ast ImplItem),
- NodeVariant(&'ast Variant),
- NodeExpr(&'ast Expr),
- NodeStmt(&'ast Stmt),
- NodeArg(&'ast Pat),
- NodeLocal(&'ast Pat),
- NodePat(&'ast Pat),
- NodeBlock(&'ast Block),
-
- /// NodeStructCtor represents a tuple struct.
- NodeStructCtor(&'ast StructDef),
-
- NodeLifetime(&'ast Lifetime),
-}
-
-/// Represents an entry and its parent Node ID
-/// The odd layout is to bring down the total size.
-#[derive(Copy, Debug)]
-enum MapEntry<'ast> {
- /// Placeholder for holes in the map.
- NotPresent,
-
- /// All the node types, with a parent ID.
- EntryItem(NodeId, &'ast Item),
- EntryForeignItem(NodeId, &'ast ForeignItem),
- EntryTraitItem(NodeId, &'ast TraitItem),
- EntryImplItem(NodeId, &'ast ImplItem),
- EntryVariant(NodeId, &'ast Variant),
- EntryExpr(NodeId, &'ast Expr),
- EntryStmt(NodeId, &'ast Stmt),
- EntryArg(NodeId, &'ast Pat),
- EntryLocal(NodeId, &'ast Pat),
- EntryPat(NodeId, &'ast Pat),
- EntryBlock(NodeId, &'ast Block),
- EntryStructCtor(NodeId, &'ast StructDef),
- EntryLifetime(NodeId, &'ast Lifetime),
-
- /// Roots for node trees.
- RootCrate,
- RootInlinedParent(&'ast InlinedParent)
-}
-
-impl<'ast> Clone for MapEntry<'ast> {
- fn clone(&self) -> MapEntry<'ast> {
- *self
- }
-}
-
-#[derive(Debug)]
-struct InlinedParent {
- path: Vec<PathElem>,
- ii: InlinedItem
-}
-
-impl<'ast> MapEntry<'ast> {
- fn from_node(p: NodeId, node: Node<'ast>) -> MapEntry<'ast> {
- match node {
- NodeItem(n) => EntryItem(p, n),
- NodeForeignItem(n) => EntryForeignItem(p, n),
- NodeTraitItem(n) => EntryTraitItem(p, n),
- NodeImplItem(n) => EntryImplItem(p, n),
- NodeVariant(n) => EntryVariant(p, n),
- NodeExpr(n) => EntryExpr(p, n),
- NodeStmt(n) => EntryStmt(p, n),
- NodeArg(n) => EntryArg(p, n),
- NodeLocal(n) => EntryLocal(p, n),
- NodePat(n) => EntryPat(p, n),
- NodeBlock(n) => EntryBlock(p, n),
- NodeStructCtor(n) => EntryStructCtor(p, n),
- NodeLifetime(n) => EntryLifetime(p, n)
- }
- }
-
- fn parent(self) -> Option<NodeId> {
- Some(match self {
- EntryItem(id, _) => id,
- EntryForeignItem(id, _) => id,
- EntryTraitItem(id, _) => id,
- EntryImplItem(id, _) => id,
- EntryVariant(id, _) => id,
- EntryExpr(id, _) => id,
- EntryStmt(id, _) => id,
- EntryArg(id, _) => id,
- EntryLocal(id, _) => id,
- EntryPat(id, _) => id,
- EntryBlock(id, _) => id,
- EntryStructCtor(id, _) => id,
- EntryLifetime(id, _) => id,
- _ => return None
- })
- }
-
- fn to_node(self) -> Option<Node<'ast>> {
- Some(match self {
- EntryItem(_, n) => NodeItem(n),
- EntryForeignItem(_, n) => NodeForeignItem(n),
- EntryTraitItem(_, n) => NodeTraitItem(n),
- EntryImplItem(_, n) => NodeImplItem(n),
- EntryVariant(_, n) => NodeVariant(n),
- EntryExpr(_, n) => NodeExpr(n),
- EntryStmt(_, n) => NodeStmt(n),
- EntryArg(_, n) => NodeArg(n),
- EntryLocal(_, n) => NodeLocal(n),
- EntryPat(_, n) => NodePat(n),
- EntryBlock(_, n) => NodeBlock(n),
- EntryStructCtor(_, n) => NodeStructCtor(n),
- EntryLifetime(_, n) => NodeLifetime(n),
- _ => return None
- })
- }
-}
-
-/// Stores a crate and any number of inlined items from other crates.
-pub struct Forest {
- krate: Crate,
- inlined_items: TypedArena<InlinedParent>
-}
-
-impl Forest {
- pub fn new(krate: Crate) -> Forest {
- Forest {
- krate: krate,
- inlined_items: TypedArena::new()
- }
- }
-
- pub fn krate<'ast>(&'ast self) -> &'ast Crate {
- &self.krate
- }
-}
-
-/// Represents a mapping from Node IDs to AST elements and their parent
-/// Node IDs
-pub struct Map<'ast> {
- /// The backing storage for all the AST nodes.
- forest: &'ast Forest,
-
- /// NodeIds are sequential integers from 0, so we can be
- /// super-compact by storing them in a vector. Not everything with
- /// a NodeId is in the map, but empirically the occupancy is about
- /// 75-80%, so there's not too much overhead (certainly less than
- /// a hashmap, since they (at the time of writing) have a maximum
- /// of 75% occupancy).
- ///
- /// Also, indexing is pretty quick when you've got a vector and
- /// plain old integers.
- map: RefCell<Vec<MapEntry<'ast>>>
-}
-
-impl<'ast> Map<'ast> {
- fn entry_count(&self) -> usize {
- self.map.borrow().len()
- }
-
- fn find_entry(&self, id: NodeId) -> Option<MapEntry<'ast>> {
- self.map.borrow().get(id as usize).cloned()
- }
-
- pub fn krate(&self) -> &'ast Crate {
- &self.forest.krate
- }
-
- /// Retrieve the Node corresponding to `id`, panicking if it cannot
- /// be found.
- pub fn get(&self, id: NodeId) -> Node<'ast> {
- match self.find(id) {
- Some(node) => node,
- None => panic!("couldn't find node id {} in the AST map", id)
- }
- }
-
- /// Retrieve the Node corresponding to `id`, returning None if
- /// cannot be found.
- pub fn find(&self, id: NodeId) -> Option<Node<'ast>> {
- self.find_entry(id).and_then(|x| x.to_node())
- }
-
- /// Retrieve the parent NodeId for `id`, or `id` itself if no
- /// parent is registered in this map.
- pub fn get_parent(&self, id: NodeId) -> NodeId {
- self.find_entry(id).and_then(|x| x.parent()).unwrap_or(id)
- }
-
- pub fn get_parent_did(&self, id: NodeId) -> DefId {
- let parent = self.get_parent(id);
- match self.find_entry(parent) {
- Some(RootInlinedParent(&InlinedParent {ii: IITraitItem(did, _), ..})) => did,
- Some(RootInlinedParent(&InlinedParent {ii: IIImplItem(did, _), ..})) => did,
- _ => ast_util::local_def(parent)
- }
- }
-
- pub fn get_foreign_abi(&self, id: NodeId) -> abi::Abi {
- let parent = self.get_parent(id);
- let abi = match self.find_entry(parent) {
- Some(EntryItem(_, i)) => {
- match i.node {
- ItemForeignMod(ref nm) => Some(nm.abi),
- _ => None
- }
- }
- /// Wrong but OK, because the only inlined foreign items are intrinsics.
- Some(RootInlinedParent(_)) => Some(abi::RustIntrinsic),
- _ => None
- };
- match abi {
- Some(abi) => abi,
- None => panic!("expected foreign mod or inlined parent, found {}",
- self.node_to_string(parent))
- }
- }
-
- pub fn get_foreign_vis(&self, id: NodeId) -> Visibility {
- let vis = self.expect_foreign_item(id).vis;
- match self.find(self.get_parent(id)) {
- Some(NodeItem(i)) => vis.inherit_from(i.vis),
- _ => vis
- }
- }
-
- pub fn expect_item(&self, id: NodeId) -> &'ast Item {
- match self.find(id) {
- Some(NodeItem(item)) => item,
- _ => panic!("expected item, found {}", self.node_to_string(id))
- }
- }
-
- pub fn expect_struct(&self, id: NodeId) -> &'ast StructDef {
- match self.find(id) {
- Some(NodeItem(i)) => {
- match i.node {
- ItemStruct(ref struct_def, _) => &**struct_def,
- _ => panic!("struct ID bound to non-struct")
- }
- }
- Some(NodeVariant(variant)) => {
- match variant.node.kind {
- StructVariantKind(ref struct_def) => &**struct_def,
- _ => panic!("struct ID bound to enum variant that isn't struct-like"),
- }
- }
- _ => panic!(format!("expected struct, found {}", self.node_to_string(id))),
- }
- }
-
- pub fn expect_variant(&self, id: NodeId) -> &'ast Variant {
- match self.find(id) {
- Some(NodeVariant(variant)) => variant,
- _ => panic!(format!("expected variant, found {}", self.node_to_string(id))),
- }
- }
-
- pub fn expect_foreign_item(&self, id: NodeId) -> &'ast ForeignItem {
- match self.find(id) {
- Some(NodeForeignItem(item)) => item,
- _ => panic!("expected foreign item, found {}", self.node_to_string(id))
- }
- }
-
- pub fn expect_expr(&self, id: NodeId) -> &'ast Expr {
- match self.find(id) {
- Some(NodeExpr(expr)) => expr,
- _ => panic!("expected expr, found {}", self.node_to_string(id))
- }
- }
-
- /// returns the name associated with the given NodeId's AST
- pub fn get_path_elem(&self, id: NodeId) -> PathElem {
- let node = self.get(id);
- match node {
- NodeItem(item) => {
- match item.node {
- ItemMod(_) | ItemForeignMod(_) => {
- PathMod(item.ident.name)
- }
- _ => PathName(item.ident.name)
- }
- }
- NodeForeignItem(i) => PathName(i.ident.name),
- NodeImplItem(ii) => PathName(ii.ident.name),
- NodeTraitItem(ti) => PathName(ti.ident.name),
- NodeVariant(v) => PathName(v.node.name.name),
- _ => panic!("no path elem for {:?}", node)
- }
- }
-
- pub fn with_path<T, F>(&self, id: NodeId, f: F) -> T where
- F: FnOnce(PathElems) -> T,
- {
- self.with_path_next(id, LinkedPath::empty(), f)
- }
-
- pub fn path_to_string(&self, id: NodeId) -> String {
- self.with_path(id, |path| path_to_string(path))
- }
-
- fn path_to_str_with_ident(&self, id: NodeId, i: Ident) -> String {
- self.with_path(id, |path| {
- path_to_string(path.chain(Some(PathName(i.name)).into_iter()))
- })
- }
-
- fn with_path_next<T, F>(&self, id: NodeId, next: LinkedPath, f: F) -> T where
- F: FnOnce(PathElems) -> T,
- {
- let parent = self.get_parent(id);
- let parent = match self.find_entry(id) {
- Some(EntryForeignItem(..)) | Some(EntryVariant(..)) => {
- // Anonymous extern items, enum variants and struct ctors
- // go in the parent scope.
- self.get_parent(parent)
- }
- // But tuple struct ctors don't have names, so use the path of its
- // parent, the struct item. Similarly with closure expressions.
- Some(EntryStructCtor(..)) | Some(EntryExpr(..)) => {
- return self.with_path_next(parent, next, f);
- }
- _ => parent
- };
- if parent == id {
- match self.find_entry(id) {
- Some(RootInlinedParent(data)) => {
- f(data.path.iter().cloned().chain(next))
- }
- _ => f([].iter().cloned().chain(next))
- }
- } else {
- self.with_path_next(parent, LinkedPath::from(&LinkedPathNode {
- node: self.get_path_elem(id),
- next: next
- }), f)
- }
- }
-
- /// Given a node ID, get a list of of attributes associated with the AST
- /// corresponding to the Node ID
- pub fn attrs(&self, id: NodeId) -> &'ast [Attribute] {
- let attrs = match self.find(id) {
- Some(NodeItem(i)) => Some(&i.attrs[..]),
- Some(NodeForeignItem(fi)) => Some(&fi.attrs[..]),
- Some(NodeTraitItem(ref ti)) => Some(&ti.attrs[..]),
- Some(NodeImplItem(ref ii)) => Some(&ii.attrs[..]),
- Some(NodeVariant(ref v)) => Some(&v.node.attrs[..]),
- // unit/tuple structs take the attributes straight from
- // the struct definition.
- Some(NodeStructCtor(_)) => {
- return self.attrs(self.get_parent(id));
- }
- _ => None
- };
- attrs.unwrap_or(&[])
- }
-
- /// Returns an iterator that yields the node id's with paths that
- /// match `parts`. (Requires `parts` is non-empty.)
- ///
- /// For example, if given `parts` equal to `["bar", "quux"]`, then
- /// the iterator will produce node id's for items with paths
- /// such as `foo::bar::quux`, `bar::quux`, `other::bar::quux`, and
- /// any other such items it can find in the map.
- pub fn nodes_matching_suffix<'a>(&'a self, parts: &'a [String])
- -> NodesMatchingSuffix<'a, 'ast> {
- NodesMatchingSuffix {
- map: self,
- item_name: parts.last().unwrap(),
- in_which: &parts[..parts.len() - 1],
- idx: 0,
- }
- }
-
- pub fn opt_span(&self, id: NodeId) -> Option<Span> {
- let sp = match self.find(id) {
- Some(NodeItem(item)) => item.span,
- Some(NodeForeignItem(foreign_item)) => foreign_item.span,
- Some(NodeTraitItem(trait_method)) => trait_method.span,
- Some(NodeImplItem(ref impl_item)) => impl_item.span,
- Some(NodeVariant(variant)) => variant.span,
- Some(NodeExpr(expr)) => expr.span,
- Some(NodeStmt(stmt)) => stmt.span,
- Some(NodeArg(pat)) | Some(NodeLocal(pat)) => pat.span,
- Some(NodePat(pat)) => pat.span,
- Some(NodeBlock(block)) => block.span,
- Some(NodeStructCtor(_)) => self.expect_item(self.get_parent(id)).span,
- _ => return None,
- };
- Some(sp)
- }
-
- pub fn span(&self, id: NodeId) -> Span {
- self.opt_span(id)
- .unwrap_or_else(|| panic!("AstMap.span: could not find span for id {:?}", id))
- }
-
- pub fn def_id_span(&self, def_id: DefId, fallback: Span) -> Span {
- if def_id.krate == LOCAL_CRATE {
- self.opt_span(def_id.node).unwrap_or(fallback)
- } else {
- fallback
- }
- }
-
- pub fn node_to_string(&self, id: NodeId) -> String {
- node_id_to_string(self, id, true)
- }
-
- pub fn node_to_user_string(&self, id: NodeId) -> String {
- node_id_to_string(self, id, false)
- }
-}
-
-pub struct NodesMatchingSuffix<'a, 'ast:'a> {
- map: &'a Map<'ast>,
- item_name: &'a String,
- in_which: &'a [String],
- idx: NodeId,
-}
-
-impl<'a, 'ast> NodesMatchingSuffix<'a, 'ast> {
- /// Returns true only if some suffix of the module path for parent
- /// matches `self.in_which`.
- ///
- /// In other words: let `[x_0,x_1,...,x_k]` be `self.in_which`;
- /// returns true if parent's path ends with the suffix
- /// `x_0::x_1::...::x_k`.
- fn suffix_matches(&self, parent: NodeId) -> bool {
- let mut cursor = parent;
- for part in self.in_which.iter().rev() {
- let (mod_id, mod_name) = match find_first_mod_parent(self.map, cursor) {
- None => return false,
- Some((node_id, name)) => (node_id, name),
- };
- if &part[..] != mod_name.as_str() {
- return false;
- }
- cursor = self.map.get_parent(mod_id);
- }
- return true;
-
- // Finds the first mod in parent chain for `id`, along with
- // that mod's name.
- //
- // If `id` itself is a mod named `m` with parent `p`, then
- // returns `Some(id, m, p)`. If `id` has no mod in its parent
- // chain, then returns `None`.
- fn find_first_mod_parent<'a>(map: &'a Map, mut id: NodeId) -> Option<(NodeId, Name)> {
- loop {
- match map.find(id) {
- None => return None,
- Some(NodeItem(item)) if item_is_mod(&*item) =>
- return Some((id, item.ident.name)),
- _ => {}
- }
- let parent = map.get_parent(id);
- if parent == id { return None }
- id = parent;
- }
-
- fn item_is_mod(item: &Item) -> bool {
- match item.node {
- ItemMod(_) => true,
- _ => false,
- }
- }
- }
- }
-
- // We are looking at some node `n` with a given name and parent
- // id; do their names match what I am seeking?
- fn matches_names(&self, parent_of_n: NodeId, name: Name) -> bool {
- name.as_str() == &self.item_name[..] &&
- self.suffix_matches(parent_of_n)
- }
-}
-
-impl<'a, 'ast> Iterator for NodesMatchingSuffix<'a, 'ast> {
- type Item = NodeId;
-
- fn next(&mut self) -> Option<NodeId> {
- loop {
- let idx = self.idx;
- if idx as usize >= self.map.entry_count() {
- return None;
- }
- self.idx += 1;
- let (p, name) = match self.map.find_entry(idx) {
- Some(EntryItem(p, n)) => (p, n.name()),
- Some(EntryForeignItem(p, n))=> (p, n.name()),
- Some(EntryTraitItem(p, n)) => (p, n.name()),
- Some(EntryImplItem(p, n)) => (p, n.name()),
- Some(EntryVariant(p, n)) => (p, n.name()),
- _ => continue,
- };
- if self.matches_names(p, name) {
- return Some(idx)
- }
- }
- }
-}
-
-trait Named {
- fn name(&self) -> Name;
-}
-
-impl<T:Named> Named for Spanned<T> { fn name(&self) -> Name { self.node.name() } }
-
-impl Named for Item { fn name(&self) -> Name { self.ident.name } }
-impl Named for ForeignItem { fn name(&self) -> Name { self.ident.name } }
-impl Named for Variant_ { fn name(&self) -> Name { self.name.name } }
-impl Named for TraitItem { fn name(&self) -> Name { self.ident.name } }
-impl Named for ImplItem { fn name(&self) -> Name { self.ident.name } }
-
-pub trait FoldOps {
- fn new_id(&self, id: NodeId) -> NodeId {
- id
- }
- fn new_def_id(&self, def_id: DefId) -> DefId {
- def_id
- }
- fn new_span(&self, span: Span) -> Span {
- span
- }
-}
-
-/// A Folder that updates IDs and Span's according to fold_ops.
-struct IdAndSpanUpdater<F> {
- fold_ops: F
-}
-
-impl<F: FoldOps> Folder for IdAndSpanUpdater<F> {
- fn new_id(&mut self, id: NodeId) -> NodeId {
- self.fold_ops.new_id(id)
- }
-
- fn new_span(&mut self, span: Span) -> Span {
- self.fold_ops.new_span(span)
- }
-}
-
-/// A Visitor that walks over an AST and collects Node's into an AST Map.
-struct NodeCollector<'ast> {
- map: Vec<MapEntry<'ast>>,
- /// The node in which we are currently mapping (an item or a method).
- parent: NodeId
-}
-
-impl<'ast> NodeCollector<'ast> {
- fn insert_entry(&mut self, id: NodeId, entry: MapEntry<'ast>) {
- debug!("ast_map: {:?} => {:?}", id, entry);
- let len = self.map.len();
- if id as usize >= len {
- self.map.extend(repeat(NotPresent).take(id as usize - len + 1));
- }
- self.map[id as usize] = entry;
- }
-
- fn insert(&mut self, id: NodeId, node: Node<'ast>) {
- let entry = MapEntry::from_node(self.parent, node);
- self.insert_entry(id, entry);
- }
-
- fn visit_fn_decl(&mut self, decl: &'ast FnDecl) {
- for a in &decl.inputs {
- self.insert(a.id, NodeArg(&*a.pat));
- }
- }
-}
-
-impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
- fn visit_item(&mut self, i: &'ast Item) {
- self.insert(i.id, NodeItem(i));
- let parent = self.parent;
- self.parent = i.id;
- match i.node {
- ItemImpl(_, _, _, _, _, ref impl_items) => {
- for ii in impl_items {
- self.insert(ii.id, NodeImplItem(ii));
- }
- }
- ItemEnum(ref enum_definition, _) => {
- for v in &enum_definition.variants {
- self.insert(v.node.id, NodeVariant(&**v));
- }
- }
- ItemForeignMod(ref nm) => {
- for nitem in &nm.items {
- self.insert(nitem.id, NodeForeignItem(&**nitem));
- }
- }
- ItemStruct(ref struct_def, _) => {
- // If this is a tuple-like struct, register the constructor.
- match struct_def.ctor_id {
- Some(ctor_id) => {
- self.insert(ctor_id, NodeStructCtor(&**struct_def));
- }
- None => {}
- }
- }
- ItemTrait(_, _, ref bounds, ref trait_items) => {
- for b in &**bounds {
- if let TraitTyParamBound(ref t, TraitBoundModifier::None) = *b {
- self.insert(t.trait_ref.ref_id, NodeItem(i));
- }
- }
-
- for ti in trait_items {
- self.insert(ti.id, NodeTraitItem(ti));
- }
- }
- _ => {}
- }
- visit::walk_item(self, i);
- self.parent = parent;
- }
-
- fn visit_trait_item(&mut self, ti: &'ast TraitItem) {
- let parent = self.parent;
- self.parent = ti.id;
- visit::walk_trait_item(self, ti);
- self.parent = parent;
- }
-
- fn visit_impl_item(&mut self, ii: &'ast ImplItem) {
- let parent = self.parent;
- self.parent = ii.id;
- visit::walk_impl_item(self, ii);
- self.parent = parent;
- }
-
- fn visit_pat(&mut self, pat: &'ast Pat) {
- self.insert(pat.id, match pat.node {
- // Note: this is at least *potentially* a pattern...
- PatIdent(..) => NodeLocal(pat),
- _ => NodePat(pat)
- });
- visit::walk_pat(self, pat);
- }
-
- fn visit_expr(&mut self, expr: &'ast Expr) {
- self.insert(expr.id, NodeExpr(expr));
- visit::walk_expr(self, expr);
- }
-
- fn visit_stmt(&mut self, stmt: &'ast Stmt) {
- self.insert(ast_util::stmt_id(stmt), NodeStmt(stmt));
- visit::walk_stmt(self, stmt);
- }
-
- fn visit_fn(&mut self, fk: visit::FnKind<'ast>, fd: &'ast FnDecl,
- b: &'ast Block, s: Span, _: NodeId) {
- self.visit_fn_decl(fd);
- visit::walk_fn(self, fk, fd, b, s);
- }
-
- fn visit_ty(&mut self, ty: &'ast Ty) {
- match ty.node {
- TyBareFn(ref fd) => {
- self.visit_fn_decl(&*fd.decl);
- }
- _ => {}
- }
- visit::walk_ty(self, ty);
- }
-
- fn visit_block(&mut self, block: &'ast Block) {
- self.insert(block.id, NodeBlock(block));
- visit::walk_block(self, block);
- }
-
- fn visit_lifetime_ref(&mut self, lifetime: &'ast Lifetime) {
- self.insert(lifetime.id, NodeLifetime(lifetime));
- }
-
- fn visit_lifetime_def(&mut self, def: &'ast LifetimeDef) {
- self.visit_lifetime_ref(&def.lifetime);
- }
-}
-
-pub fn map_crate<'ast, F: FoldOps>(forest: &'ast mut Forest, fold_ops: F) -> Map<'ast> {
- // Replace the crate with an empty one to take it out.
- let krate = mem::replace(&mut forest.krate, Crate {
- module: Mod {
- inner: DUMMY_SP,
- items: vec![],
- },
- attrs: vec![],
- config: vec![],
- exported_macros: vec![],
- span: DUMMY_SP
- });
- forest.krate = IdAndSpanUpdater { fold_ops: fold_ops }.fold_crate(krate);
-
- let mut collector = NodeCollector {
- map: vec![],
- parent: CRATE_NODE_ID
- };
- collector.insert_entry(CRATE_NODE_ID, RootCrate);
- visit::walk_crate(&mut collector, &forest.krate);
- let map = collector.map;
-
- if log_enabled!(::log::DEBUG) {
- // This only makes sense for ordered stores; note the
- // enumerate to count the number of entries.
- let (entries_less_1, _) = map.iter().filter(|&x| {
- match *x {
- NotPresent => false,
- _ => true
- }
- }).enumerate().last().expect("AST map was empty after folding?");
-
- let entries = entries_less_1 + 1;
- let vector_length = map.len();
- debug!("The AST map has {} entries with a maximum of {}: occupancy {:.1}%",
- entries, vector_length, (entries as f64 / vector_length as f64) * 100.);
- }
-
- Map {
- forest: forest,
- map: RefCell::new(map)
- }
-}
-
-/// Used for items loaded from external crate that are being inlined into this
-/// crate. The `path` should be the path to the item but should not include
-/// the item itself.
-pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>,
- path: Vec<PathElem>,
- ii: InlinedItem,
- fold_ops: F)
- -> &'ast InlinedItem {
- let mut fld = IdAndSpanUpdater { fold_ops: fold_ops };
- let ii = match ii {
- IIItem(i) => IIItem(fld.fold_item(i).expect_one("expected one item")),
- IITraitItem(d, ti) => {
- IITraitItem(fld.fold_ops.new_def_id(d),
- fld.fold_trait_item(ti).expect_one("expected one trait item"))
- }
- IIImplItem(d, ii) => {
- IIImplItem(fld.fold_ops.new_def_id(d),
- fld.fold_impl_item(ii).expect_one("expected one impl item"))
- }
- IIForeign(i) => IIForeign(fld.fold_foreign_item(i))
- };
-
- let ii_parent = map.forest.inlined_items.alloc(InlinedParent {
- path: path,
- ii: ii
- });
-
- let mut collector = NodeCollector {
- map: mem::replace(&mut *map.map.borrow_mut(), vec![]),
- parent: fld.new_id(DUMMY_NODE_ID)
- };
- let ii_parent_id = collector.parent;
- collector.insert_entry(ii_parent_id, RootInlinedParent(ii_parent));
- visit::walk_inlined_item(&mut collector, &ii_parent.ii);
-
- // Methods get added to the AST map when their impl is visited. Since we
- // don't decode and instantiate the impl, but just the method, we have to
- // add it to the table now. Likewise with foreign items.
- match ii_parent.ii {
- IIItem(_) => {}
- IITraitItem(_, ref ti) => {
- collector.insert(ti.id, NodeTraitItem(ti));
- }
- IIImplItem(_, ref ii) => {
- collector.insert(ii.id, NodeImplItem(ii));
- }
- IIForeign(ref i) => {
- collector.insert(i.id, NodeForeignItem(i));
- }
- }
- *map.map.borrow_mut() = collector.map;
- &ii_parent.ii
-}
-
-pub trait NodePrinter {
- fn print_node(&mut self, node: &Node) -> io::Result<()>;
-}
-
-impl<'a> NodePrinter for pprust::State<'a> {
- fn print_node(&mut self, node: &Node) -> io::Result<()> {
- match *node {
- NodeItem(a) => self.print_item(&*a),
- NodeForeignItem(a) => self.print_foreign_item(&*a),
- NodeTraitItem(a) => self.print_trait_item(a),
- NodeImplItem(a) => self.print_impl_item(a),
- NodeVariant(a) => self.print_variant(&*a),
- NodeExpr(a) => self.print_expr(&*a),
- NodeStmt(a) => self.print_stmt(&*a),
- NodePat(a) => self.print_pat(&*a),
- NodeBlock(a) => self.print_block(&*a),
- NodeLifetime(a) => self.print_lifetime(&*a),
-
- // these cases do not carry enough information in the
- // ast_map to reconstruct their full structure for pretty
- // printing.
- NodeLocal(_) => panic!("cannot print isolated Local"),
- NodeArg(_) => panic!("cannot print isolated Arg"),
- NodeStructCtor(_) => panic!("cannot print isolated StructCtor"),
- }
- }
-}
-
-fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String {
- let id_str = format!(" (id={})", id);
- let id_str = if include_id { &id_str[..] } else { "" };
-
- match map.find(id) {
- Some(NodeItem(item)) => {
- let path_str = map.path_to_str_with_ident(id, item.ident);
- let item_str = match item.node {
- ItemExternCrate(..) => "extern crate",
- ItemUse(..) => "use",
- ItemStatic(..) => "static",
- ItemConst(..) => "const",
- ItemFn(..) => "fn",
- ItemMod(..) => "mod",
- ItemForeignMod(..) => "foreign mod",
- ItemTy(..) => "ty",
- ItemEnum(..) => "enum",
- ItemStruct(..) => "struct",
- ItemTrait(..) => "trait",
- ItemImpl(..) => "impl",
- ItemDefaultImpl(..) => "default impl",
- ItemMac(..) => "macro"
- };
- format!("{} {}{}", item_str, path_str, id_str)
- }
- Some(NodeForeignItem(item)) => {
- let path_str = map.path_to_str_with_ident(id, item.ident);
- format!("foreign item {}{}", path_str, id_str)
- }
- Some(NodeImplItem(ii)) => {
- match ii.node {
- ConstImplItem(..) => {
- format!("assoc const {} in {}{}",
- token::get_ident(ii.ident),
- map.path_to_string(id),
- id_str)
- }
- MethodImplItem(..) => {
- format!("method {} in {}{}",
- token::get_ident(ii.ident),
- map.path_to_string(id), id_str)
- }
- TypeImplItem(_) => {
- format!("assoc type {} in {}{}",
- token::get_ident(ii.ident),
- map.path_to_string(id),
- id_str)
- }
- MacImplItem(ref mac) => {
- format!("method macro {}{}",
- pprust::mac_to_string(mac), id_str)
- }
- }
- }
- Some(NodeTraitItem(ti)) => {
- let kind = match ti.node {
- ConstTraitItem(..) => "assoc constant",
- MethodTraitItem(..) => "trait method",
- TypeTraitItem(..) => "assoc type",
- };
-
- format!("{} {} in {}{}",
- kind,
- token::get_ident(ti.ident),
- map.path_to_string(id),
- id_str)
- }
- Some(NodeVariant(ref variant)) => {
- format!("variant {} in {}{}",
- token::get_ident(variant.node.name),
- map.path_to_string(id), id_str)
- }
- Some(NodeExpr(ref expr)) => {
- format!("expr {}{}", pprust::expr_to_string(&**expr), id_str)
- }
- Some(NodeStmt(ref stmt)) => {
- format!("stmt {}{}", pprust::stmt_to_string(&**stmt), id_str)
- }
- Some(NodeArg(ref pat)) => {
- format!("arg {}{}", pprust::pat_to_string(&**pat), id_str)
- }
- Some(NodeLocal(ref pat)) => {
- format!("local {}{}", pprust::pat_to_string(&**pat), id_str)
- }
- Some(NodePat(ref pat)) => {
- format!("pat {}{}", pprust::pat_to_string(&**pat), id_str)
- }
- Some(NodeBlock(ref block)) => {
- format!("block {}{}", pprust::block_to_string(&**block), id_str)
- }
- Some(NodeStructCtor(_)) => {
- format!("struct_ctor {}{}", map.path_to_string(id), id_str)
- }
- Some(NodeLifetime(ref l)) => {
- format!("lifetime {}{}",
- pprust::lifetime_to_string(&**l), id_str)
- }
- None => {
- format!("unknown node{}", id_str)
- }
- }
-}
impl<'a, O: IdVisitingOperation> IdVisitor<'a, O> {
fn visit_generics_helper(&mut self, generics: &Generics) {
- for type_parameter in &*generics.ty_params {
+ for type_parameter in generics.ty_params.iter() {
self.operation.visit_id(type_parameter.id)
}
for lifetime in &generics.lifetimes {
self.operation.visit_id(node_id);
match function_kind {
- visit::FkItemFn(_, generics, _, _, _) => {
+ visit::FkItemFn(_, generics, _, _, _, _) => {
self.visit_generics_helper(generics)
}
visit::FkMethod(_, sig, _) => {
// are two arrays of segments equal when compared unhygienically?
pub fn segments_name_eq(a : &[ast::PathSegment], b : &[ast::PathSegment]) -> bool {
a.len() == b.len() &&
- a.iter().zip(b.iter()).all(|(s, t)| {
+ a.iter().zip(b).all(|(s, t)| {
s.identifier.name == t.identifier.name &&
// FIXME #7743: ident -> name problems in lifetime comparison?
// can types contain idents?
}
/// Represents the #[deprecated] and friends attributes.
-#[derive(RustcEncodable,RustcDecodable,Clone,Debug)]
+#[derive(RustcEncodable, RustcDecodable, Clone, Debug, PartialEq, Eq, Hash)]
pub struct Stability {
pub level: StabilityLevel,
pub feature: InternedString,
}
/// The available stability levels.
-#[derive(RustcEncodable,RustcDecodable,PartialEq,PartialOrd,Clone,Debug,Copy)]
+#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Copy, Eq, Hash)]
pub enum StabilityLevel {
Unstable,
Stable,
let mut feature = None;
let mut since = None;
let mut reason = None;
- for meta in metas.iter() {
+ for meta in metas {
if meta.name() == "feature" {
match meta.value_str() {
Some(v) => feature = Some(v),
pub use self::ExpnFormat::*;
-use std::cell::RefCell;
+use std::cell::{Cell, RefCell};
use std::ops::{Add, Sub};
+use std::path::Path;
use std::rc::Rc;
-use std::fmt;
+use std::{fmt, fs};
+use std::io::{self, Read};
use serialize::{Encodable, Decodable, Encoder, Decoder};
/// are *absolute* positions from the beginning of the codemap, not positions
/// relative to FileMaps. Methods on the CodeMap can be used to relate spans back
/// to the original source.
-#[derive(Clone, Copy, Debug, Hash)]
+#[derive(Clone, Copy, Hash)]
pub struct Span {
pub lo: BytePos,
pub hi: BytePos,
}
}
+fn default_span_debug(span: Span, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "Span {{ lo: {:?}, hi: {:?}, expn_id: {:?} }}",
+ span.lo, span.hi, span.expn_id)
+}
+
+thread_local!(pub static SPAN_DEBUG: Cell<fn(Span, &mut fmt::Formatter) -> fmt::Result> =
+ Cell::new(default_span_debug));
+
+impl fmt::Debug for Span {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ SPAN_DEBUG.with(|span_debug| span_debug.get()(*self, f))
+ }
+}
+
pub fn spanned<T>(lo: BytePos, hi: BytePos, t: T) -> Spanned<T> {
respan(mk_sp(lo, hi), t)
}
}
}
+/// An abstraction over the fs operations used by the Parser.
+pub trait FileLoader {
+ /// Query the existence of a file.
+ fn file_exists(&self, path: &Path) -> bool;
+
+ /// Read the contents of an UTF-8 file into memory.
+ fn read_file(&self, path: &Path) -> io::Result<String>;
+}
+
+/// A FileLoader that uses std::fs to load real files.
+pub struct RealFileLoader;
+
+impl FileLoader for RealFileLoader {
+ fn file_exists(&self, path: &Path) -> bool {
+ fs::metadata(path).is_ok()
+ }
+
+ fn read_file(&self, path: &Path) -> io::Result<String> {
+ let mut src = String::new();
+ try!(try!(fs::File::open(path)).read_to_string(&mut src));
+ Ok(src)
+ }
+}
// _____________________________________________________________________________
// CodeMap
pub struct CodeMap {
pub files: RefCell<Vec<Rc<FileMap>>>,
- expansions: RefCell<Vec<ExpnInfo>>
+ expansions: RefCell<Vec<ExpnInfo>>,
+ file_loader: Box<FileLoader>
}
impl CodeMap {
CodeMap {
files: RefCell::new(Vec::new()),
expansions: RefCell::new(Vec::new()),
+ file_loader: Box::new(RealFileLoader)
+ }
+ }
+
+ pub fn with_file_loader(file_loader: Box<FileLoader>) -> CodeMap {
+ CodeMap {
+ files: RefCell::new(Vec::new()),
+ expansions: RefCell::new(Vec::new()),
+ file_loader: file_loader
}
}
+ pub fn file_exists(&self, path: &Path) -> bool {
+ self.file_loader.file_exists(path)
+ }
+
+ pub fn load_file(&self, path: &Path) -> io::Result<Rc<FileMap>> {
+ let src = try!(self.file_loader.read_file(path));
+ Ok(self.new_filemap(path.to_str().unwrap().to_string(), src))
+ }
+
pub fn new_filemap(&self, filename: FileName, mut src: String) -> Rc<FileMap> {
let mut files = self.files.borrow_mut();
let start_pos = match files.last() {
}
pub fn get_filemap(&self, filename: &str) -> Rc<FileMap> {
- for fm in &*self.files.borrow() {
+ for fm in self.files.borrow().iter() {
if filename == fm.name {
return fm.clone();
}
// The number of extra bytes due to multibyte chars in the FileMap
let mut total_extra_bytes = 0;
- for mbc in &*map.multibyte_chars.borrow() {
+ for mbc in map.multibyte_chars.borrow().iter() {
debug!("{}-byte char at {:?}", mbc.bytes, mbc.pos);
if mbc.pos < bpos {
// every character is at least one byte, so we only
}
impl SpanHandler {
+ pub fn new(handler: Handler, cm: codemap::CodeMap) -> SpanHandler {
+ SpanHandler {
+ handler: handler,
+ cm: cm,
+ }
+ }
pub fn span_fatal(&self, sp: Span, msg: &str) -> FatalError {
self.handler.emit(Some((&self.cm, sp)), msg, Fatal);
return FatalError;
}
impl Handler {
+ pub fn new(color_config: ColorConfig,
+ registry: Option<diagnostics::registry::Registry>,
+ can_emit_warnings: bool) -> Handler {
+ let emitter = Box::new(EmitterWriter::stderr(color_config, registry));
+ Handler::with_emitter(can_emit_warnings, emitter)
+ }
+ pub fn with_emitter(can_emit_warnings: bool, e: Box<Emitter + Send>) -> Handler {
+ Handler {
+ err_count: Cell::new(0),
+ emit: RefCell::new(e),
+ can_emit_warnings: can_emit_warnings
+ }
+ }
pub fn fatal(&self, msg: &str) -> ! {
self.emit.borrow_mut().emit(None, msg, None, Fatal);
panic!(FatalError);
}
}
-pub fn mk_span_handler(handler: Handler, cm: codemap::CodeMap) -> SpanHandler {
- SpanHandler {
- handler: handler,
- cm: cm,
- }
-}
-
-pub fn default_handler(color_config: ColorConfig,
- registry: Option<diagnostics::registry::Registry>,
- can_emit_warnings: bool) -> Handler {
- mk_handler(can_emit_warnings, Box::new(EmitterWriter::stderr(color_config, registry)))
-}
-
-pub fn mk_handler(can_emit_warnings: bool, e: Box<Emitter + Send>) -> Handler {
- Handler {
- err_count: Cell::new(0),
- emit: RefCell::new(e),
- can_emit_warnings: can_emit_warnings
- }
-}
-
#[derive(Copy, PartialEq, Clone, Debug)]
pub enum Level {
Bug,
let display_line_strings = &line_strings[..display_lines];
// Print the offending lines
- for (line_info, line) in display_line_infos.iter().zip(display_line_strings.iter()) {
+ for (line_info, line) in display_line_infos.iter().zip(display_line_strings) {
try!(write!(&mut err.dst, "{}:{} {}\n",
fm.name,
line_info.line_index + 1,
//! currently always a crate name.
use std::collections::BTreeMap;
-use std::env;
use std::path::PathBuf;
-use std::fs::{read_dir, create_dir_all, OpenOptions, File};
-use std::io::{Read, Write};
+use std::fs::{remove_file, create_dir_all, File};
+use std::io::Write;
use std::error::Error;
-use rustc_serialize::json::{self, as_json};
+use rustc_serialize::json::as_json;
use codemap::Span;
use ext::base::ExtCtxt;
use diagnostics::plugin::{ErrorMap, ErrorInfo};
-pub use self::Uniqueness::*;
-
// Default metadata directory to use for extended error JSON.
-const ERROR_METADATA_DIR_DEFAULT: &'static str = "tmp/extended-errors";
-
-// The name of the environment variable that sets the metadata dir.
-const ERROR_METADATA_VAR: &'static str = "ERROR_METADATA_DIR";
+const ERROR_METADATA_PREFIX: &'static str = "tmp/extended-errors";
/// JSON encodable/decodable version of `ErrorInfo`.
#[derive(PartialEq, RustcDecodable, RustcEncodable)]
}
}
-/// Type for describing the uniqueness of a set of error codes, as returned by `check_uniqueness`.
-pub enum Uniqueness {
- /// All errors in the set checked are unique according to the metadata files checked.
- Unique,
- /// One or more errors in the set occur in another metadata file.
- /// This variant contains the first duplicate error code followed by the name
- /// of the metadata file where the duplicate appears.
- Duplicate(String, String)
-}
-
-/// Get the directory where metadata files should be stored.
-pub fn get_metadata_dir() -> PathBuf {
- match env::var(ERROR_METADATA_VAR) {
- Ok(v) => From::from(v),
- Err(_) => From::from(ERROR_METADATA_DIR_DEFAULT)
- }
-}
-
-/// Get the path where error metadata for the set named by `name` should be stored.
-fn get_metadata_path(name: &str) -> PathBuf {
- get_metadata_dir().join(format!("{}.json", name))
+/// Get the directory where metadata for a given `prefix` should be stored.
+///
+/// See `output_metadata`.
+pub fn get_metadata_dir(prefix: &str) -> PathBuf {
+ PathBuf::from(ERROR_METADATA_PREFIX).join(prefix)
}
-/// Check that the errors in `err_map` aren't present in any metadata files in the
-/// metadata directory except the metadata file corresponding to `name`.
-pub fn check_uniqueness(name: &str, err_map: &ErrorMap) -> Result<Uniqueness, Box<Error>> {
- let metadata_dir = get_metadata_dir();
- let metadata_path = get_metadata_path(name);
-
- // Create the error directory if it does not exist.
- try!(create_dir_all(&metadata_dir));
-
- // Check each file in the metadata directory.
- for entry in try!(read_dir(&metadata_dir)) {
- let path = try!(entry).path();
-
- // Skip any existing file for this set.
- if path == metadata_path {
- continue;
- }
-
- // Read the metadata file into a string.
- let mut metadata_str = String::new();
- try!(
- File::open(&path).and_then(|mut f|
- f.read_to_string(&mut metadata_str))
- );
-
- // Parse the JSON contents.
- let metadata: ErrorMetadataMap = try!(json::decode(&metadata_str));
-
- // Check for duplicates.
- for err in err_map.keys() {
- let err_code = err.as_str();
- if metadata.contains_key(err_code) {
- return Ok(Duplicate(
- err_code.to_string(),
- path.to_string_lossy().into_owned()
- ));
- }
- }
- }
-
- Ok(Unique)
+/// Map `name` to a path in the given directory: <directory>/<name>.json
+fn get_metadata_path(directory: PathBuf, name: &str) -> PathBuf {
+ directory.join(format!("{}.json", name))
}
-/// Write metadata for the errors in `err_map` to disk, to a file corresponding to `name`.
-pub fn output_metadata(ecx: &ExtCtxt, name: &str, err_map: &ErrorMap)
+/// Write metadata for the errors in `err_map` to disk, to a file corresponding to `prefix/name`.
+///
+/// For our current purposes the prefix is the target architecture and the name is a crate name.
+/// If an error occurs steps will be taken to ensure that no file is created.
+pub fn output_metadata(ecx: &ExtCtxt, prefix: &str, name: &str, err_map: &ErrorMap)
-> Result<(), Box<Error>>
{
- let metadata_path = get_metadata_path(name);
+ // Create the directory to place the file in.
+ let metadata_dir = get_metadata_dir(prefix);
+ try!(create_dir_all(&metadata_dir));
- // Open the dump file.
- let mut dump_file = try!(OpenOptions::new()
- .write(true)
- .create(true)
- .open(&metadata_path)
- );
+ // Open the metadata file.
+ let metadata_path = get_metadata_path(metadata_dir, name);
+ let mut metadata_file = try!(File::create(&metadata_path));
// Construct a serializable map.
let json_map = err_map.iter().map(|(k, &ErrorInfo { description, use_site })| {
(key, value)
}).collect::<ErrorMetadataMap>();
- try!(write!(&mut dump_file, "{}", as_json(&json_map)));
- Ok(())
+ // Write the data to the file, deleting it if the write fails.
+ let result = write!(&mut metadata_file, "{}", as_json(&json_map));
+ if result.is_err() {
+ try!(remove_file(&metadata_path));
+ }
+ Ok(try!(result))
}
use std::cell::RefCell;
use std::collections::BTreeMap;
+use std::env;
use ast;
use ast::{Ident, Name, TokenTree};
use codemap::Span;
-use diagnostics::metadata::{check_uniqueness, output_metadata, Duplicate};
use ext::base::{ExtCtxt, MacEager, MacResult};
use ext::build::AstBuilder;
use parse::token;
use ptr::P;
use util::small_vector::SmallVector;
+use diagnostics::metadata::output_metadata;
+
// Maximum width of any line in an extended error description (inclusive).
const MAX_DESCRIPTION_WIDTH: usize = 80;
}
_ => unreachable!()
};
+
// Check that the description starts and ends with a newline and doesn't
// overflow the maximum line width.
description.map(|raw_msg| {
token::get_ident(*code)
));
}
- if msg.lines().any(|line| line.len() > MAX_DESCRIPTION_WIDTH) {
+
+ // URLs can be unavoidably longer than the line limit, so we allow them.
+ // Allowed format is: `[name]: http://rust-lang.org/`
+ let is_url = |l: &str| l.starts_with('[') && l.contains("]:") && l.contains("http");
+
+ if msg.lines().any(|line| line.len() > MAX_DESCRIPTION_WIDTH && !is_url(line)) {
ecx.span_err(span, &format!(
- "description for error code {} contains a line longer than {} characters",
+ "description for error code {} contains a line longer than {} characters.\n\
+ if you're inserting a long URL use the footnote style to bypass this check.",
token::get_ident(*code), MAX_DESCRIPTION_WIDTH
));
}
_ => unreachable!()
};
- // Check uniqueness of errors and output metadata.
+ // Output error metadata to `tmp/extended-errors/<target arch>/<crate name>.json`
+ let target_triple = env::var("CFG_COMPILER_HOST_TRIPLE")
+ .ok().expect("unable to determine target arch from $CFG_COMPILER_HOST_TRIPLE");
+
with_registered_diagnostics(|diagnostics| {
- match check_uniqueness(crate_name, &*diagnostics) {
- Ok(Duplicate(err, location)) => {
- ecx.span_err(span, &format!(
- "error {} from `{}' also found in `{}'",
- err, crate_name, location
- ));
- },
- Ok(_) => (),
- Err(e) => panic!("{}", e.description())
+ if let Err(e) = output_metadata(ecx, &target_triple, crate_name, &diagnostics) {
+ ecx.span_bug(span, &format!(
+ "error writing metadata for triple `{}` and crate `{}`, error: {}, cause: {:?}",
+ target_triple, crate_name, e.description(), e.cause()
+ ));
}
-
- output_metadata(&*ecx, crate_name, &*diagnostics).ok().expect("metadata output error");
});
// Construct the output expression.
ident: name.clone(),
attrs: Vec::new(),
id: ast::DUMMY_NODE_ID,
- node: ast::ItemStatic(
+ node: ast::ItemConst(
ty,
- ast::MutImmutable,
expr,
),
vis: ast::Public,
ecx: &mut ExtCtxt,
sp: Span,
meta_item: &ast::MetaItem,
- item: Annotatable,
+ item: &Annotatable,
push: &mut FnMut(Annotatable));
}
impl<F> MultiItemDecorator for F
- where F : Fn(&mut ExtCtxt, Span, &ast::MetaItem, Annotatable, &mut FnMut(Annotatable))
+ where F : Fn(&mut ExtCtxt, Span, &ast::MetaItem, &Annotatable, &mut FnMut(Annotatable))
{
fn expand(&self,
ecx: &mut ExtCtxt,
sp: Span,
meta_item: &ast::MetaItem,
- item: Annotatable,
+ item: &Annotatable,
push: &mut FnMut(Annotatable)) {
(*self)(ecx, sp, meta_item, item, push)
}
parse::tts_to_parser(self.parse_sess, tts.to_vec(), self.cfg())
}
- pub fn codemap(&self) -> &'a CodeMap { &self.parse_sess.span_diagnostic.cm }
+ pub fn codemap(&self) -> &'a CodeMap { self.parse_sess.codemap() }
pub fn parse_sess(&self) -> &'a parse::ParseSess { self.parse_sess }
pub fn cfg(&self) -> ast::CrateConfig { self.cfg.clone() }
pub fn call_site(&self) -> Span {
Vec::new(),
ast::ItemFn(self.fn_decl(inputs, output),
ast::Unsafety::Normal,
+ ast::Constness::NotConst,
abi::Rust,
generics,
body))
pub fn expand_deriving_unsafe_bound(cx: &mut ExtCtxt,
span: Span,
_: &MetaItem,
- _: Annotatable,
+ _: &Annotatable,
_: &mut FnMut(Annotatable))
{
cx.span_err(span, "this unsafe trait should be implemented explicitly");
pub fn expand_deriving_copy(cx: &mut ExtCtxt,
span: Span,
mitem: &MetaItem,
- item: Annotatable,
+ item: &Annotatable,
push: &mut FnMut(Annotatable))
{
let path = Path::new(vec![
associated_types: Vec::new(),
};
- trait_def.expand(cx, mitem, &item, push);
+ trait_def.expand(cx, mitem, item, push);
}
pub fn expand_deriving_clone(cx: &mut ExtCtxt,
span: Span,
mitem: &MetaItem,
- item: Annotatable,
+ item: &Annotatable,
push: &mut FnMut(Annotatable))
{
let inline = cx.meta_word(span, InternedString::new("inline"));
args: Vec::new(),
ret_ty: Self_,
attributes: attrs,
+ is_unsafe: false,
combine_substructure: combine_substructure(Box::new(|c, s, sub| {
cs_clone("Clone", c, s, sub)
})),
associated_types: Vec::new(),
};
- trait_def.expand(cx, mitem, &item, push)
+ trait_def.expand(cx, mitem, item, push)
}
fn cs_clone(
pub fn expand_deriving_eq(cx: &mut ExtCtxt,
span: Span,
mitem: &MetaItem,
- item: Annotatable,
+ item: &Annotatable,
push: &mut FnMut(Annotatable))
{
fn cs_total_eq_assert(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<Expr> {
args: vec!(),
ret_ty: nil_ty(),
attributes: attrs,
+ is_unsafe: false,
combine_substructure: combine_substructure(Box::new(|a, b, c| {
cs_total_eq_assert(a, b, c)
}))
),
associated_types: Vec::new(),
};
- trait_def.expand(cx, mitem, &item, push)
+ trait_def.expand(cx, mitem, item, push)
}
pub fn expand_deriving_ord(cx: &mut ExtCtxt,
span: Span,
mitem: &MetaItem,
- item: Annotatable,
+ item: &Annotatable,
push: &mut FnMut(Annotatable))
{
let inline = cx.meta_word(span, InternedString::new("inline"));
args: vec!(borrowed_self()),
ret_ty: Literal(path_std!(cx, core::cmp::Ordering)),
attributes: attrs,
+ is_unsafe: false,
combine_substructure: combine_substructure(Box::new(|a, b, c| {
cs_cmp(a, b, c)
})),
associated_types: Vec::new(),
};
- trait_def.expand(cx, mitem, &item, push)
+ trait_def.expand(cx, mitem, item, push)
}
pub fn expand_deriving_partial_eq(cx: &mut ExtCtxt,
span: Span,
mitem: &MetaItem,
- item: Annotatable,
+ item: &Annotatable,
push: &mut FnMut(Annotatable))
{
// structures are equal if all fields are equal, and non equal, if
args: vec!(borrowed_self()),
ret_ty: Literal(path_local!(bool)),
attributes: attrs,
+ is_unsafe: false,
combine_substructure: combine_substructure(Box::new(|a, b, c| {
$f(a, b, c)
}))
),
associated_types: Vec::new(),
};
- trait_def.expand(cx, mitem, &item, push)
+ trait_def.expand(cx, mitem, item, push)
}
pub fn expand_deriving_partial_ord(cx: &mut ExtCtxt,
span: Span,
mitem: &MetaItem,
- item: Annotatable,
+ item: &Annotatable,
push: &mut FnMut(Annotatable))
{
macro_rules! md {
args: vec!(borrowed_self()),
ret_ty: Literal(path_local!(bool)),
attributes: attrs,
+ is_unsafe: false,
combine_substructure: combine_substructure(Box::new(|cx, span, substr| {
cs_op($op, $equal, cx, span, substr)
}))
args: vec![borrowed_self()],
ret_ty: ret_ty,
attributes: attrs,
+ is_unsafe: false,
combine_substructure: combine_substructure(Box::new(|cx, span, substr| {
cs_partial_cmp(cx, span, substr)
}))
],
associated_types: Vec::new(),
};
- trait_def.expand(cx, mitem, &item, push)
+ trait_def.expand(cx, mitem, item, push)
}
#[derive(Copy, Clone)]
pub fn expand_deriving_rustc_decodable(cx: &mut ExtCtxt,
span: Span,
mitem: &MetaItem,
- item: Annotatable,
+ item: &Annotatable,
push: &mut FnMut(Annotatable))
{
expand_deriving_decodable_imp(cx, span, mitem, item, push, "rustc_serialize")
pub fn expand_deriving_decodable(cx: &mut ExtCtxt,
span: Span,
mitem: &MetaItem,
- item: Annotatable,
+ item: &Annotatable,
push: &mut FnMut(Annotatable))
{
expand_deriving_decodable_imp(cx, span, mitem, item, push, "serialize")
fn expand_deriving_decodable_imp(cx: &mut ExtCtxt,
span: Span,
mitem: &MetaItem,
- item: Annotatable,
+ item: &Annotatable,
push: &mut FnMut(Annotatable),
krate: &'static str)
{
true
)),
attributes: Vec::new(),
+ is_unsafe: false,
combine_substructure: combine_substructure(Box::new(|a, b, c| {
decodable_substructure(a, b, c, krate)
})),
associated_types: Vec::new(),
};
- trait_def.expand(cx, mitem, &item, push)
+ trait_def.expand(cx, mitem, item, push)
}
fn decodable_substructure(cx: &mut ExtCtxt, trait_span: Span,
pub fn expand_deriving_default(cx: &mut ExtCtxt,
span: Span,
mitem: &MetaItem,
- item: Annotatable,
+ item: &Annotatable,
push: &mut FnMut(Annotatable))
{
let inline = cx.meta_word(span, InternedString::new("inline"));
args: Vec::new(),
ret_ty: Self_,
attributes: attrs,
+ is_unsafe: false,
combine_substructure: combine_substructure(Box::new(|a, b, c| {
default_substructure(a, b, c)
}))
),
associated_types: Vec::new(),
};
- trait_def.expand(cx, mitem, &item, push)
+ trait_def.expand(cx, mitem, item, push)
}
fn default_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P<Expr> {
pub fn expand_deriving_rustc_encodable(cx: &mut ExtCtxt,
span: Span,
mitem: &MetaItem,
- item: Annotatable,
+ item: &Annotatable,
push: &mut FnMut(Annotatable))
{
expand_deriving_encodable_imp(cx, span, mitem, item, push, "rustc_serialize")
pub fn expand_deriving_encodable(cx: &mut ExtCtxt,
span: Span,
mitem: &MetaItem,
- item: Annotatable,
+ item: &Annotatable,
push: &mut FnMut(Annotatable))
{
expand_deriving_encodable_imp(cx, span, mitem, item, push, "serialize")
fn expand_deriving_encodable_imp(cx: &mut ExtCtxt,
span: Span,
mitem: &MetaItem,
- item: Annotatable,
+ item: &Annotatable,
push: &mut FnMut(Annotatable),
krate: &'static str)
{
true
)),
attributes: Vec::new(),
+ is_unsafe: false,
combine_substructure: combine_substructure(Box::new(|a, b, c| {
encodable_substructure(a, b, c)
})),
associated_types: Vec::new(),
};
- trait_def.expand(cx, mitem, &item, push)
+ trait_def.expand(cx, mitem, item, push)
}
fn encodable_substructure(cx: &mut ExtCtxt, trait_span: Span,
pub attributes: Vec<ast::Attribute>,
+ // Is it an `unsafe fn`?
+ pub is_unsafe: bool,
+
pub combine_substructure: RefCell<CombineSubstructureFunc<'a>>,
}
bounds.push(cx.typarambound(trait_path.clone()));
// also add in any bounds from the declaration
- for declared_bound in &*ty_param.bounds {
+ for declared_bound in ty_param.bounds.iter() {
bounds.push((*declared_bound).clone());
}
.map(|ty_param| ty_param.ident.name)
.collect();
- for field_ty in field_tys.into_iter() {
+ for field_ty in field_tys {
let tys = find_type_parameters(&*field_ty, &ty_param_names);
- for ty in tys.into_iter() {
+ for ty in tys {
let mut bounds: Vec<_> = self.additional_bounds.iter().map(|p| {
cx.typarambound(p.to_path(cx, self.span, type_ident, generics))
}).collect();
generics: &Generics) -> P<ast::Item> {
let mut field_tys = Vec::new();
- for variant in enum_def.variants.iter() {
+ for variant in &enum_def.variants {
match variant.node.kind {
ast::VariantKind::TupleVariantKind(ref args) => {
field_tys.extend(args.iter()
let fn_decl = cx.fn_decl(args, ret_type);
let body_block = cx.block_expr(body);
+ let unsafety = if self.is_unsafe {
+ ast::Unsafety::Unsafe
+ } else {
+ ast::Unsafety::Normal
+ };
+
// Create the method.
P(ast::ImplItem {
id: ast::DUMMY_NODE_ID,
generics: fn_generics,
abi: abi,
explicit_self: explicit_self,
- unsafety: ast::Unsafety::Normal,
+ unsafety: unsafety,
+ constness: ast::Constness::NotConst,
decl: fn_decl
}, body_block)
})
// make a series of nested matches, to destructure the
// structs. This is actually right-to-left, but it shouldn't
// matter.
- for (arg_expr, pat) in self_args.iter().zip(patterns.iter()) {
+ for (arg_expr, pat) in self_args.iter().zip(patterns) {
body = cx.expr_match(trait_.span, arg_expr.clone(),
vec!( cx.arm(trait_.span, vec!(pat.clone()), body) ))
}
/// variants where all of the variants match, and one catch-all for
/// when one does not match.
+ /// As an optimization we generate code which checks whether all variants
+ /// match first which makes llvm see that C-like enums can be compiled into
+ /// a simple equality check (for PartialEq).
+
/// The catch-all handler is provided access the variant index values
- /// for each of the self-args, carried in precomputed variables. (Nota
- /// bene: the variant index values are not necessarily the
- /// discriminant values. See issue #15523.)
+ /// for each of the self-args, carried in precomputed variables.
/// ```{.text}
- /// match (this, that, ...) {
- /// (Variant1, Variant1, Variant1) => ... // delegate Matching on Variant1
- /// (Variant2, Variant2, Variant2) => ... // delegate Matching on Variant2
- /// ...
- /// _ => {
- /// let __this_vi = match this { Variant1 => 0, Variant2 => 1, ... };
- /// let __that_vi = match that { Variant1 => 0, Variant2 => 1, ... };
+ /// let __self0_vi = unsafe {
+ /// std::intrinsics::discriminant_value(&self) } as i32;
+ /// let __self1_vi = unsafe {
+ /// std::intrinsics::discriminant_value(&__arg1) } as i32;
+ /// let __self2_vi = unsafe {
+ /// std::intrinsics::discriminant_value(&__arg2) } as i32;
+ ///
+ /// if __self0_vi == __self1_vi && __self0_vi == __self2_vi && ... {
+ /// match (...) {
+ /// (Variant1, Variant1, ...) => Body1
+ /// (Variant2, Variant2, ...) => Body2,
+ /// ...
+ /// _ => ::core::intrinsics::unreachable()
+ /// }
+ /// }
+ /// else {
/// ... // catch-all remainder can inspect above variant index values.
- /// }
/// }
/// ```
fn build_enum_match_tuple<'b>(
cx.arm(sp, vec![single_pat], arm_expr)
}).collect();
-
// We will usually need the catch-all after matching the
// tuples `(VariantK, VariantK, ...)` for each VariantK of the
// enum. But:
// ```
let mut index_let_stmts: Vec<P<ast::Stmt>> = Vec::new();
+ //We also build an expression which checks whether all discriminants are equal
+ // discriminant_test = __self0_vi == __self1_vi && __self0_vi == __self2_vi && ...
+ let mut discriminant_test = cx.expr_bool(sp, true);
+
let target_type_name =
find_repr_type_name(&cx.parse_sess.span_diagnostic, type_attrs);
- for (&ident, self_arg) in vi_idents.iter().zip(self_args.iter()) {
+ let mut first_ident = None;
+ for (&ident, self_arg) in vi_idents.iter().zip(&self_args) {
let path = vec![cx.ident_of_std("core"),
cx.ident_of("intrinsics"),
cx.ident_of("discriminant_value")];
let variant_disr = cx.expr_cast(sp, variant_value, target_ty);
let let_stmt = cx.stmt_let(sp, false, ident, variant_disr);
index_let_stmts.push(let_stmt);
+
+ match first_ident {
+ Some(first) => {
+ let first_expr = cx.expr_ident(sp, first);
+ let id = cx.expr_ident(sp, ident);
+ let test = cx.expr_binary(sp, ast::BiEq, first_expr, id);
+ discriminant_test = cx.expr_binary(sp, ast::BiAnd, discriminant_test, test)
+ }
+ None => {
+ first_ident = Some(ident);
+ }
+ }
}
let arm_expr = self.call_substructure_method(
cx, trait_, type_ident, &self_args[..], nonself_args,
&catch_all_substructure);
- // Builds the expression:
- // {
- // let __self0_vi = ...;
- // let __self1_vi = ...;
- // ...
- // <delegated expression referring to __self0_vi, et al.>
- // }
- let arm_expr = cx.expr_block(
- cx.block_all(sp, index_let_stmts, Some(arm_expr)));
-
- // Builds arm:
- // _ => { let __self0_vi = ...;
- // let __self1_vi = ...;
- // ...
- // <delegated expression as above> }
- let catch_all_match_arm =
- cx.arm(sp, vec![cx.pat_wild(sp)], arm_expr);
-
- match_arms.push(catch_all_match_arm);
-
+ //Since we know that all the arguments will match if we reach the match expression we
+ //add the unreachable intrinsics as the result of the catch all which should help llvm
+ //in optimizing it
+ let path = vec![cx.ident_of_std("core"),
+ cx.ident_of("intrinsics"),
+ cx.ident_of("unreachable")];
+ let call = cx.expr_call_global(
+ sp, path, vec![]);
+ let unreachable = cx.expr_block(P(ast::Block {
+ stmts: vec![],
+ expr: Some(call),
+ id: ast::DUMMY_NODE_ID,
+ rules: ast::UnsafeBlock(ast::CompilerGenerated),
+ span: sp }));
+ match_arms.push(cx.arm(sp, vec![cx.pat_wild(sp)], unreachable));
+
+ // Final wrinkle: the self_args are expressions that deref
+ // down to desired l-values, but we cannot actually deref
+ // them when they are fed as r-values into a tuple
+ // expression; here add a layer of borrowing, turning
+ // `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`.
+ let borrowed_self_args = self_args.move_map(|self_arg| cx.expr_addr_of(sp, self_arg));
+ let match_arg = cx.expr(sp, ast::ExprTup(borrowed_self_args));
+
+ //Lastly we create an expression which branches on all discriminants being equal
+ // if discriminant_test {
+ // match (...) {
+ // (Variant1, Variant1, ...) => Body1
+ // (Variant2, Variant2, ...) => Body2,
+ // ...
+ // _ => ::core::intrinsics::unreachable()
+ // }
+ // }
+ // else {
+ // <delegated expression referring to __self0_vi, et al.>
+ // }
+ let all_match = cx.expr_match(sp, match_arg, match_arms);
+ let arm_expr = cx.expr_if(sp, discriminant_test, all_match, Some(arm_expr));
+ cx.expr_block(
+ cx.block_all(sp, index_let_stmts, Some(arm_expr)))
} else if variants.is_empty() {
// As an additional wrinkle, For a zero-variant enum A,
// currently the compiler
// derive Debug on such a type could here generate code
// that needs the feature gate enabled.)
- return cx.expr_unreachable(sp);
+ cx.expr_unreachable(sp)
+ }
+ else {
+
+ // Final wrinkle: the self_args are expressions that deref
+ // down to desired l-values, but we cannot actually deref
+ // them when they are fed as r-values into a tuple
+ // expression; here add a layer of borrowing, turning
+ // `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`.
+ let borrowed_self_args = self_args.move_map(|self_arg| cx.expr_addr_of(sp, self_arg));
+ let match_arg = cx.expr(sp, ast::ExprTup(borrowed_self_args));
+ cx.expr_match(sp, match_arg, match_arms)
}
-
- // Final wrinkle: the self_args are expressions that deref
- // down to desired l-values, but we cannot actually deref
- // them when they are fed as r-values into a tuple
- // expression; here add a layer of borrowing, turning
- // `(*self, *__arg_0, ...)` into `(&*self, &*__arg_0, ...)`.
- let borrowed_self_args = self_args.move_map(|self_arg| cx.expr_addr_of(sp, self_arg));
- let match_arg = cx.expr(sp, ast::ExprTup(borrowed_self_args));
- cx.expr_match(sp, match_arg, match_arms)
}
fn expand_static_enum_method_body(&self,
// struct_type is definitely not Unknown, since struct_def.fields
// must be nonempty to reach here
let pattern = if struct_type == Record {
- let field_pats = subpats.into_iter().zip(ident_expr.iter())
+ let field_pats = subpats.into_iter().zip(&ident_expr)
.map(|(pat, &(_, id, _, _))| {
// id is guaranteed to be Some
codemap::Spanned {
pub fn expand_deriving_hash(cx: &mut ExtCtxt,
span: Span,
mitem: &MetaItem,
- item: Annotatable,
+ item: &Annotatable,
push: &mut FnMut(Annotatable))
{
args: vec!(Ptr(Box::new(Literal(arg)), Borrowed(None, MutMutable))),
ret_ty: nil_ty(),
attributes: vec![],
+ is_unsafe: false,
combine_substructure: combine_substructure(Box::new(|a, b, c| {
hash_substructure(a, b, c)
}))
associated_types: Vec::new(),
};
- hash_trait_def.expand(cx, mitem, &item, push);
+ hash_trait_def.expand(cx, mitem, item, push);
}
fn hash_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P<Expr> {
ecx: &mut ExtCtxt,
sp: Span,
mitem: &MetaItem,
- annotatable: Annotatable,
+ annotatable: &Annotatable,
push: &mut FnMut(Annotatable)) {
warn_if_deprecated(ecx, sp, $name);
$func(ecx, sp, mitem, annotatable, push);
pub fn expand_deriving_from_primitive(cx: &mut ExtCtxt,
span: Span,
mitem: &MetaItem,
- item: Annotatable,
+ item: &Annotatable,
push: &mut FnMut(Annotatable))
{
let inline = cx.meta_word(span, InternedString::new("inline"));
true)),
// #[inline] liable to cause code-bloat
attributes: attrs.clone(),
+ is_unsafe: false,
combine_substructure: combine_substructure(Box::new(|c, s, sub| {
cs_from("i64", c, s, sub)
})),
true)),
// #[inline] liable to cause code-bloat
attributes: attrs,
+ is_unsafe: false,
combine_substructure: combine_substructure(Box::new(|c, s, sub| {
cs_from("u64", c, s, sub)
})),
associated_types: Vec::new(),
};
- trait_def.expand(cx, mitem, &item, push)
+ trait_def.expand(cx, mitem, item, push)
}
fn cs_from(name: &str, cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P<Expr> {
pub fn expand_deriving_show(cx: &mut ExtCtxt,
span: Span,
mitem: &MetaItem,
- item: Annotatable,
+ item: &Annotatable,
push: &mut FnMut(Annotatable))
{
// &mut ::std::fmt::Formatter
args: vec!(fmtr),
ret_ty: Literal(path_std!(cx, core::fmt::Result)),
attributes: Vec::new(),
+ is_unsafe: false,
combine_substructure: combine_substructure(Box::new(|a, b, c| {
show_substructure(a, b, c)
}))
],
associated_types: Vec::new(),
};
- trait_def.expand(cx, mitem, &item, push)
+ trait_def.expand(cx, mitem, item, push)
}
/// We use the debug builders to do the heavy lifting here
match *substr.fields {
Struct(ref fields) | EnumMatching(_, _, ref fields) => {
+
if fields.is_empty() || fields[0].name.is_none() {
// tuple struct/"normal" variant
expr = cx.expr_method_call(span,
vec![name]);
for field in fields {
+ // Use double indirection to make sure this works for unsized types
+ let field = cx.expr_addr_of(field.span, field.self_.clone());
+ let field = cx.expr_addr_of(field.span, field);
+
expr = cx.expr_method_call(span,
expr,
token::str_to_ident("field"),
- vec![cx.expr_addr_of(field.span,
- field.self_.clone())]);
+ vec![field]);
}
} else {
// normal struct/struct variant
let name = cx.expr_lit(field.span, ast::Lit_::LitStr(
token::get_ident(field.name.clone().unwrap()),
ast::StrStyle::CookedStr));
+
+ // Use double indirection to make sure this works for unsized types
+ let field = cx.expr_addr_of(field.span, field.self_.clone());
+ let field = cx.expr_addr_of(field.span, field);
expr = cx.expr_method_call(span,
expr,
token::str_to_ident("field"),
- vec![name,
- cx.expr_addr_of(field.span,
- field.self_.clone())]);
+ vec![name, field]);
}
}
}
let mut arms = Vec::with_capacity(else_if_arms.len() + 2);
arms.push(pat_arm);
- arms.extend(else_if_arms.into_iter());
+ arms.extend(else_if_arms);
arms.push(else_arm);
let match_expr = fld.cx.expr(span,
/// Expand item_underscore
fn expand_item_underscore(item: ast::Item_, fld: &mut MacroExpander) -> ast::Item_ {
match item {
- ast::ItemFn(decl, fn_style, abi, generics, body) => {
+ ast::ItemFn(decl, unsafety, constness, abi, generics, body) => {
let (rewritten_fn_decl, rewritten_body)
= expand_and_rename_fn_decl_and_block(decl, body, fld);
let expanded_generics = fold::noop_fold_generics(generics,fld);
- ast::ItemFn(rewritten_fn_decl, fn_style, abi, expanded_generics, rewritten_body)
+ ast::ItemFn(rewritten_fn_decl, unsafety, constness, abi,
+ expanded_generics, rewritten_body)
}
_ => noop_fold_item_underscore(item, fld)
}
};
// add them to the existing pending renames:
fld.cx.syntax_env.info().pending_renames
- .extend(new_pending_renames.into_iter());
+ .extend(new_pending_renames);
Local {
id: id,
ty: expanded_ty,
dec.expand(fld.cx,
attr.span,
&attr.node.value,
- a.clone(),
+ &a,
&mut |ann| items.push(ann));
decorator_items.extend(items.into_iter()
.flat_map(|ann| expand_annotatable(ann, fld).into_iter()));
abi: sig.abi,
explicit_self: fld.fold_explicit_self(sig.explicit_self),
unsafety: sig.unsafety,
+ constness: sig.constness,
decl: rewritten_fn_decl
}, rewritten_body)
}
#[test] fn macros_cant_escape_fns_test () {
let src = "fn bogus() {macro_rules! z (() => (3+4));}\
fn inty() -> i32 { z!() }".to_string();
- let sess = parse::new_parse_sess();
+ let sess = parse::ParseSess::new();
let crate_ast = parse::parse_crate_from_source_str(
"<test>".to_string(),
src,
#[test] fn macros_cant_escape_mods_test () {
let src = "mod foo {macro_rules! z (() => (3+4));}\
fn inty() -> i32 { z!() }".to_string();
- let sess = parse::new_parse_sess();
+ let sess = parse::ParseSess::new();
let crate_ast = parse::parse_crate_from_source_str(
"<test>".to_string(),
src,
#[test] fn macros_can_escape_flattened_mods_test () {
let src = "#[macro_use] mod foo {macro_rules! z (() => (3+4));}\
fn inty() -> i32 { z!() }".to_string();
- let sess = parse::new_parse_sess();
+ let sess = parse::ParseSess::new();
let crate_ast = parse::parse_crate_from_source_str(
"<test>".to_string(),
src,
}
fn expand_crate_str(crate_str: String) -> ast::Crate {
- let ps = parse::new_parse_sess();
+ let ps = parse::ParseSess::new();
let crate_ast = panictry!(string_to_parser(&ps, crate_str).parse_crate_mod());
// the cfg argument actually does matter, here...
expand_crate(&ps,test_ecfg(),vec!(),vec!(),crate_ast)
Some(ecx.lifetime(sp, special_idents::static_lifetime.name)),
ast::MutImmutable);
let slice = ecx.expr_vec_slice(sp, pieces);
+ // static instead of const to speed up codegen by not requiring this to be inlined
let st = ast::ItemStatic(ty, ast::MutImmutable, slice);
let name = ecx.ident_of(name);
impl<T: ToTokens> ToTokens for Vec<T> {
fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
- self.iter().flat_map(|t| t.to_tokens(cx).into_iter()).collect()
+ self.iter().flat_map(|t| t.to_tokens(cx)).collect()
}
}
-> Box<base::MacResult+'static> {
let (cx_expr, tts) = parse_arguments_to_quote(cx, tts);
let mut vector = mk_stmts_let(cx, sp);
- vector.extend(statements_mk_tts(cx, &tts[..], true).into_iter());
+ vector.extend(statements_mk_tts(cx, &tts[..], true));
let block = cx.expr_block(
cx.block_all(sp,
vector,
fn statements_mk_tt(cx: &ExtCtxt, tt: &ast::TokenTree, matcher: bool) -> Vec<P<ast::Stmt>> {
match *tt {
ast::TtToken(sp, SubstNt(ident, _)) => {
- // tt.extend($ident.to_tokens(ext_cx).into_iter())
+ // tt.extend($ident.to_tokens(ext_cx))
let e_to_toks =
cx.expr_method_call(sp,
ast::TtDelimited(_, ref delimed) => {
statements_mk_tt(cx, &delimed.open_tt(), matcher).into_iter()
.chain(delimed.tts.iter()
- .flat_map(|tt| statements_mk_tt(cx, tt, matcher).into_iter()))
- .chain(statements_mk_tt(cx, &delimed.close_tt(), matcher).into_iter())
+ .flat_map(|tt| statements_mk_tt(cx, tt, matcher)))
+ .chain(statements_mk_tt(cx, &delimed.close_tt(), matcher))
.collect()
},
ast::TtSequence(sp, ref seq) => {
let stmt_let_tt = cx.stmt_let(sp, true, id_ext("tt"), cx.expr_vec_ng(sp));
let mut tts_stmts = vec![stmt_let_tt];
- tts_stmts.extend(statements_mk_tts(cx, &seq.tts[..], matcher).into_iter());
+ tts_stmts.extend(statements_mk_tts(cx, &seq.tts[..], matcher));
let e_tts = cx.expr_block(cx.block(sp, tts_stmts,
Some(cx.expr_ident(sp, id_ext("tt")))));
let e_separator = match seq.separator {
fn statements_mk_tts(cx: &ExtCtxt, tts: &[ast::TokenTree], matcher: bool) -> Vec<P<ast::Stmt>> {
let mut ss = Vec::new();
for tt in tts {
- ss.extend(statements_mk_tt(cx, tt, matcher).into_iter());
+ ss.extend(statements_mk_tt(cx, tt, matcher));
}
ss
}
let (cx_expr, tts) = parse_arguments_to_quote(cx, tts);
let mut vector = mk_stmts_let(cx, sp);
- vector.extend(statements_mk_tts(cx, &tts[..], false).into_iter());
+ vector.extend(statements_mk_tts(cx, &tts[..], false));
let block = cx.expr_block(
cx.block_all(sp,
vector,
// make item: `use ...;`
let path = path.iter().map(|s| s.to_string()).collect();
cx.stmt_item(sp, cx.item_use_glob(sp, ast::Inherited, ids_ext(path)))
- }).chain(Some(stmt_let_ext_cx).into_iter()).collect();
+ }).chain(Some(stmt_let_ext_cx)).collect();
cx.expr_block(cx.block_all(sp, stmts, Some(expr)))
}
last = match *token {
TtToken(sp, MatchNt(ref name, ref frag_spec, _, _)) => {
// ii. If T is a simple NT, look ahead to the next token T' in
- // M.
- let next_token = match tokens.peek() {
- // If T' closes a complex NT, replace T' with F
- Some(&&TtToken(_, CloseDelim(_))) => follow.clone(),
- Some(&&TtToken(_, ref tok)) => tok.clone(),
- Some(&&TtSequence(sp, _)) => {
- cx.span_err(sp,
- &format!("`${0}:{1}` is followed by a \
- sequence repetition, which is not \
- allowed for `{1}` fragments",
- name.as_str(), frag_spec.as_str())
+ // M. If T' is in the set FOLLOW(NT), continue. Else; reject.
+ if can_be_followed_by_any(frag_spec.as_str()) {
+ continue
+ } else {
+ let next_token = match tokens.peek() {
+ // If T' closes a complex NT, replace T' with F
+ Some(&&TtToken(_, CloseDelim(_))) => follow.clone(),
+ Some(&&TtToken(_, ref tok)) => tok.clone(),
+ Some(&&TtSequence(sp, _)) => {
+ // Be conservative around sequences: to be
+ // more specific, we would need to
+ // consider FIRST sets, but also the
+ // possibility that the sequence occurred
+ // zero times (in which case we need to
+ // look at the token that follows the
+ // sequence, which may itself a sequence,
+ // and so on).
+ cx.span_err(sp,
+ &format!("`${0}:{1}` is followed by a \
+ sequence repetition, which is not \
+ allowed for `{1}` fragments",
+ name.as_str(), frag_spec.as_str())
);
- Eof
- },
- // die next iteration
- Some(&&TtDelimited(_, ref delim)) => delim.close_token(),
- // else, we're at the end of the macro or sequence
- None => follow.clone()
- };
-
- let tok = if let TtToken(_, ref tok) = *token { tok } else { unreachable!() };
- // If T' is in the set FOLLOW(NT), continue. Else, reject.
- match (&next_token, is_in_follow(cx, &next_token, frag_spec.as_str())) {
- (_, Err(msg)) => {
- cx.span_err(sp, &msg);
- continue
+ Eof
+ },
+ // die next iteration
+ Some(&&TtDelimited(_, ref delim)) => delim.close_token(),
+ // else, we're at the end of the macro or sequence
+ None => follow.clone()
+ };
+
+ let tok = if let TtToken(_, ref tok) = *token { tok } else { unreachable!() };
+
+ // If T' is in the set FOLLOW(NT), continue. Else, reject.
+ match (&next_token, is_in_follow(cx, &next_token, frag_spec.as_str())) {
+ (_, Err(msg)) => {
+ cx.span_err(sp, &msg);
+ continue
+ }
+ (&Eof, _) => return Some((sp, tok.clone())),
+ (_, Ok(true)) => continue,
+ (next, Ok(false)) => {
+ cx.span_err(sp, &format!("`${0}:{1}` is followed by `{2}`, which \
+ is not allowed for `{1}` fragments",
+ name.as_str(), frag_spec.as_str(),
+ token_to_string(next)));
+ continue
+ },
}
- (&Eof, _) => return Some((sp, tok.clone())),
- (_, Ok(true)) => continue,
- (next, Ok(false)) => {
- cx.span_err(sp, &format!("`${0}:{1}` is followed by `{2}`, which \
- is not allowed for `{1}` fragments",
- name.as_str(), frag_spec.as_str(),
- token_to_string(next)));
- continue
- },
}
},
TtSequence(sp, ref seq) => {
last
}
+/// True if a fragment of type `frag` can be followed by any sort of
+/// token. We use this (among other things) as a useful approximation
+/// for when `frag` can be followed by a repetition like `$(...)*` or
+/// `$(...)+`. In general, these can be a bit tricky to reason about,
+/// so we adopt a conservative position that says that any fragment
+/// specifier which consumes at most one token tree can be followed by
+/// a fragment specifier (indeed, these fragments can be followed by
+/// ANYTHING without fear of future compatibility hazards).
+fn can_be_followed_by_any(frag: &str) -> bool {
+ match frag {
+ "item" | // always terminated by `}` or `;`
+ "block" | // exactly one token tree
+ "ident" | // exactly one token tree
+ "meta" | // exactly one token tree
+ "tt" => // exactly one token tree
+ true,
+
+ _ =>
+ false,
+ }
+}
+
+/// True if `frag` can legally be followed by the token `tok`. For
+/// fragments that can consume an unbounded numbe of tokens, `tok`
+/// must be within a well-defined follow set. This is intended to
+/// guarantee future compatibility: for example, without this rule, if
+/// we expanded `expr` to include a new binary operator, we might
+/// break macros that were relying on that binary operator as a
+/// separator.
fn is_in_follow(_: &ExtCtxt, tok: &Token, frag: &str) -> Result<bool, String> {
if let &CloseDelim(_) = tok {
+ // closing a token tree can never be matched by any fragment;
+ // iow, we always require that `(` and `)` match, etc.
Ok(true)
} else {
match frag {
"pat" => {
match *tok {
FatArrow | Comma | Eq => Ok(true),
+ Ident(i, _) if i.as_str() == "if" || i.as_str() == "in" => Ok(true),
_ => Ok(false)
}
},
// Allows the use of rustc_* attributes; RFC 572
("rustc_attrs", "1.0.0", Active),
- // Allows the use of `static_assert`
- ("static_assert", "1.0.0", Active),
-
// Allows the use of #[allow_internal_unstable]. This is an
// attribute on macro_rules! and can't use the attribute handling
// below (it has to be checked before expansion possibly makes
// Allows the definition of associated constants in `trait` or `impl`
// blocks.
("associated_consts", "1.0.0", Active),
+
+ // Allows the definition of `const fn` functions.
+ ("const_fn", "1.2.0", Active),
+
+ // Allows associated type defaults
+ ("associated_type_defaults", "1.2.0", Active),
];
// (changing above list without updating src/doc/reference.md makes @cmr sad)
("no_builtins", Whitelisted),
("no_mangle", Whitelisted),
("no_stack_check", Whitelisted),
- ("packed", Whitelisted),
- ("static_assert", Gated("static_assert",
- "`#[static_assert]` is an experimental feature, and has a poor API")),
("no_debug", Whitelisted),
("omit_gdb_pretty_printer_section", Whitelisted),
("unsafe_no_drop_flag", Gated("unsafe_no_drop_flag",
/// spans of #![feature] attrs for stable language features. for error reporting
pub declared_stable_lang_features: Vec<Span>,
/// #![feature] attrs for non-language (library) features
- pub declared_lib_features: Vec<(InternedString, Span)>
+ pub declared_lib_features: Vec<(InternedString, Span)>,
+ pub const_fn: bool,
}
impl Features {
unmarked_api: false,
negate_unsigned: false,
declared_stable_lang_features: Vec::new(),
- declared_lib_features: Vec::new()
+ declared_lib_features: Vec::new(),
+ const_fn: false,
}
}
}
features: Vec<&'static str>,
span_handler: &'a SpanHandler,
cm: &'a CodeMap,
+ plugin_attributes: &'a [(String, AttributeType)],
}
impl<'a> Context<'a> {
self.features.iter().any(|&n| n == feature)
}
- fn check_attribute(&self, attr: &ast::Attribute) {
+ fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) {
debug!("check_attribute(attr = {:?})", attr);
let name = &*attr.name();
for &(n, ty) in KNOWN_ATTRIBUTES {
return;
}
}
+ for &(ref n, ref ty) in self.plugin_attributes {
+ if &*n == name {
+ // Plugins can't gate attributes, so we don't check for it
+ // unlike the code above; we only use this loop to
+ // short-circuit to avoid the checks below
+ debug!("check_attribute: {:?} is registered by a plugin, {:?}", name, ty);
+ return;
+ }
+ }
if name.starts_with("rustc_") {
self.gate_feature("rustc_attrs", attr.span,
"unless otherwise specified, attributes \
"attributes of the form `#[derive_*]` are reserved \
for the compiler");
} else {
- self.gate_feature("custom_attribute", attr.span,
- &format!("The attribute `{}` is currently \
- unknown to the compiler and \
- may have meaning \
- added to it in the future",
- name));
+ // Only run the custom attribute lint during regular
+ // feature gate checking. Macro gating runs
+ // before the plugin attributes are registered
+ // so we skip this then
+ if !is_macro {
+ self.gate_feature("custom_attribute", attr.span,
+ &format!("The attribute `{}` is currently \
+ unknown to the compiler and \
+ may have meaning \
+ added to it in the future",
+ name));
+ }
}
}
}
feature));
}
-pub fn emit_feature_warn(diag: &SpanHandler, feature: &str, span: Span, explain: &str) {
- diag.span_warn(span, explain);
-
- // #23973: do not suggest `#![feature(...)]` if we are in beta/stable
- if option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some() { return; }
- if diag.handler.can_emit_warnings {
- diag.fileline_help(span, &format!("add #![feature({})] to the \
- crate attributes to silence this warning",
- feature));
- }
-}
-
pub const EXPLAIN_ASM: &'static str =
"inline assembly is not stable enough for use and is subject to change";
}
fn visit_attribute(&mut self, attr: &'v ast::Attribute) {
- self.context.check_attribute(attr);
+ self.context.check_attribute(attr, true);
}
}
impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> {
fn visit_attribute(&mut self, attr: &ast::Attribute) {
if !self.context.cm.span_allows_unstable(attr.span) {
- self.context.check_attribute(attr);
+ self.context.check_attribute(attr, false);
}
}
block: &'v ast::Block,
span: Span,
_node_id: NodeId) {
+ // check for const fn declarations
+ match fn_kind {
+ visit::FkItemFn(_, _, _, ast::Constness::Const, _, _) => {
+ self.gate_feature("const_fn", span, "const fn is unstable");
+ }
+ _ => {
+ // stability of const fn methods are covered in
+ // visit_trait_item and visit_impl_item below; this is
+ // because default methods don't pass through this
+ // point.
+ }
+ }
+
match fn_kind {
- visit::FkItemFn(_, _, _, abi, _) if abi == Abi::RustIntrinsic => {
+ visit::FkItemFn(_, _, _, _, abi, _) if abi == Abi::RustIntrinsic => {
self.gate_feature("intrinsics",
span,
"intrinsics are subject to change")
}
- visit::FkItemFn(_, _, _, abi, _) |
+ visit::FkItemFn(_, _, _, _, abi, _) |
visit::FkMethod(_, &ast::MethodSig { abi, .. }, _) if abi == Abi::RustCall => {
self.gate_feature("unboxed_closures",
span,
ti.span,
"associated constants are experimental")
}
+ ast::MethodTraitItem(ref sig, _) => {
+ if sig.constness == ast::Constness::Const {
+ self.gate_feature("const_fn", ti.span, "const fn is unstable");
+ }
+ }
+ ast::TypeTraitItem(_, Some(_)) => {
+ self.gate_feature("associated_type_defaults", ti.span,
+ "associated type defaults are unstable");
+ }
_ => {}
}
visit::walk_trait_item(self, ti);
ii.span,
"associated constants are experimental")
}
+ ast::MethodImplItem(ref sig, _) => {
+ if sig.constness == ast::Constness::Const {
+ self.gate_feature("const_fn", ii.span, "const fn is unstable");
+ }
+ }
_ => {}
}
visit::walk_impl_item(self, ii);
fn check_crate_inner<F>(cm: &CodeMap, span_handler: &SpanHandler,
krate: &ast::Crate,
+ plugin_attributes: &[(String, AttributeType)],
check: F)
-> Features
where F: FnOnce(&mut Context, &ast::Crate)
features: Vec::new(),
span_handler: span_handler,
cm: cm,
+ plugin_attributes: plugin_attributes,
};
let mut accepted_features = Vec::new();
unmarked_api: cx.has_feature("unmarked_api"),
negate_unsigned: cx.has_feature("negate_unsigned"),
declared_stable_lang_features: accepted_features,
- declared_lib_features: unknown_features
+ declared_lib_features: unknown_features,
+ const_fn: cx.has_feature("const_fn"),
}
}
pub fn check_crate_macros(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::Crate)
-> Features {
- check_crate_inner(cm, span_handler, krate,
+ check_crate_inner(cm, span_handler, krate, &[] as &'static [_],
|ctx, krate| visit::walk_crate(&mut MacroVisitor { context: ctx }, krate))
}
-pub fn check_crate(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::Crate)
- -> Features
+pub fn check_crate(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::Crate,
+ plugin_attributes: &[(String, AttributeType)],
+ unstable: UnstableFeatures) -> Features
{
- check_crate_inner(cm, span_handler, krate,
+ maybe_stage_features(span_handler, krate, unstable);
+
+ check_crate_inner(cm, span_handler, krate, plugin_attributes,
|ctx, krate| visit::walk_crate(&mut PostExpansionVisitor { context: ctx },
krate))
}
+
+#[derive(Clone, Copy)]
+pub enum UnstableFeatures {
+ /// Hard errors for unstable features are active, as on
+ /// beta/stable channels.
+ Disallow,
+ /// Allow features to me activated, as on nightly.
+ Allow,
+ /// Errors are bypassed for bootstrapping. This is required any time
+ /// during the build that feature-related lints are set to warn or above
+ /// because the build turns on warnings-as-errors and uses lots of unstable
+ /// features. As a result, this this is always required for building Rust
+ /// itself.
+ Cheat
+}
+
+fn maybe_stage_features(span_handler: &SpanHandler, krate: &ast::Crate,
+ unstable: UnstableFeatures) {
+ let allow_features = match unstable {
+ UnstableFeatures::Allow => true,
+ UnstableFeatures::Disallow => false,
+ UnstableFeatures::Cheat => true
+ };
+ if !allow_features {
+ for attr in &krate.attrs {
+ if attr.check_name("feature") {
+ let release_channel = option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)");
+ let ref msg = format!("#[feature] may not be used on the {} release channel",
+ release_channel);
+ span_handler.span_err(attr.span, msg);
+ }
+ }
+ }
+}
}
pub fn fold_attrs<T: Folder>(attrs: Vec<Attribute>, fld: &mut T) -> Vec<Attribute> {
- attrs.into_iter().flat_map(|x| fld.fold_attribute(x).into_iter()).collect()
+ attrs.into_iter().flat_map(|x| fld.fold_attribute(x)).collect()
}
pub fn noop_fold_arm<T: Folder>(Arm {attrs, pats, guard, body}: Arm, fld: &mut T) -> Arm {
ItemConst(t, e) => {
ItemConst(folder.fold_ty(t), folder.fold_expr(e))
}
- ItemFn(decl, unsafety, abi, generics, body) => {
+ ItemFn(decl, unsafety, constness, abi, generics, body) => {
ItemFn(
folder.fold_fn_decl(decl),
unsafety,
+ constness,
abi,
folder.fold_generics(generics),
folder.fold_block(body)
abi: sig.abi,
explicit_self: folder.fold_explicit_self(sig.explicit_self),
unsafety: sig.unsafety,
+ constness: sig.constness,
decl: folder.fold_fn_decl(sig.decl)
}
}
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
- html_favicon_url = "http://www.rust-lang.org/favicon.ico",
+ html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/")]
#![feature(associated_consts)]
-#![feature(collections)]
-#![feature(collections_drain)]
-#![feature(core)]
+#![feature(bitset)]
+#![feature(drain)]
+#![feature(filling_drop)]
#![feature(libc)]
+#![feature(ref_slice)]
#![feature(rustc_private)]
#![feature(staged_api)]
#![feature(str_char)]
+#![feature(str_escape)]
#![feature(unicode)]
+#![feature(vec_push_all)]
-extern crate arena;
extern crate fmt_macros;
extern crate serialize;
extern crate term;
pub mod abi;
pub mod ast;
-pub mod ast_map;
pub mod ast_util;
pub mod attr;
pub mod codemap;
Some('/') => {
self.bump();
self.bump();
+
// line comments starting with "///" or "//!" are doc-comments
- if self.curr_is('/') || self.curr_is('!') {
- let start_bpos = self.pos - BytePos(3);
- while !self.is_eof() {
- match self.curr.unwrap() {
- '\n' => break,
- '\r' => {
- if self.nextch_is('\n') {
- // CRLF
- break
- } else {
- self.err_span_(self.last_pos, self.pos,
- "bare CR not allowed in doc-comment");
- }
+ let doc_comment = self.curr_is('/') || self.curr_is('!');
+ let start_bpos = if doc_comment {
+ self.pos - BytePos(3)
+ } else {
+ self.last_pos - BytePos(2)
+ };
+
+ while !self.is_eof() {
+ match self.curr.unwrap() {
+ '\n' => break,
+ '\r' => {
+ if self.nextch_is('\n') {
+ // CRLF
+ break
+ } else if doc_comment {
+ self.err_span_(self.last_pos, self.pos,
+ "bare CR not allowed in doc-comment");
}
- _ => ()
}
- self.bump();
+ _ => ()
}
- return self.with_str_from(start_bpos, |string| {
- // but comments with only more "/"s are not
+ self.bump();
+ }
+
+ return if doc_comment {
+ self.with_str_from(start_bpos, |string| {
+ // comments with only more "/"s are not doc comments
let tok = if is_doc_comment(string) {
token::DocComment(token::intern(string))
} else {
token::Comment
};
- return Some(TokenAndSpan{
+ Some(TokenAndSpan {
tok: tok,
sp: codemap::mk_sp(start_bpos, self.last_pos)
- });
- });
+ })
+ })
} else {
- let start_bpos = self.last_pos - BytePos(2);
- while !self.curr_is('\n') && !self.is_eof() { self.bump(); }
- return Some(TokenAndSpan {
+ Some(TokenAndSpan {
tok: token::Comment,
sp: codemap::mk_sp(start_bpos, self.last_pos)
- });
+ })
}
}
Some('*') => {
'n' | 'r' | 't' | '\\' | '\'' | '"' | '0' => true,
'x' => self.scan_byte_escape(delim, !ascii_only),
'u' if self.curr_is('{') => {
- let valid = self.scan_unicode_escape(delim);
- if valid && ascii_only {
- self.err_span_(
- escaped_pos,
- self.last_pos,
- "unicode escape sequences cannot be used as a byte or in \
- a byte string"
- );
- false
- } else {
- valid
- }
+ let valid = self.scan_unicode_escape(delim);
+ if valid && ascii_only {
+ self.err_span_(
+ escaped_pos,
+ self.last_pos,
+ "unicode escape sequences cannot be used as a byte or in \
+ a byte string"
+ );
+ false
+ } else {
+ valid
+ }
}
'\n' if delim == '"' => {
self.consume_whitespace();
if valid && (char::from_u32(accum_int).is_none() || count == 0) {
self.err_span_(start_bpos, self.last_pos, "illegal unicode character escape");
- valid= false;
+ valid = false;
}
fn mk_sh() -> diagnostic::SpanHandler {
// FIXME (#22405): Replace `Box::new` with `box` here when/if possible.
let emitter = diagnostic::EmitterWriter::new(Box::new(io::sink()), None);
- let handler = diagnostic::mk_handler(true, Box::new(emitter));
- diagnostic::mk_span_handler(handler, CodeMap::new())
+ let handler = diagnostic::Handler::with_emitter(true, Box::new(emitter));
+ diagnostic::SpanHandler::new(handler, CodeMap::new())
}
// open a string reader for the given string
assert_eq!(lexer.next_token().tok, token::Literal(token::Char(token::intern("a")), None));
}
+ #[test] fn crlf_comments() {
+ let sh = mk_sh();
+ let mut lexer = setup(&sh, "// test\r\n/// test\r\n".to_string());
+ let comment = lexer.next_token();
+ assert_eq!(comment.tok, token::Comment);
+ assert_eq!(comment.sp, ::codemap::mk_sp(BytePos(0), BytePos(7)));
+ assert_eq!(lexer.next_token().tok, token::Whitespace);
+ assert_eq!(lexer.next_token().tok, token::DocComment(token::intern("/// test")));
+ }
}
use ast;
use codemap::{Span, CodeMap, FileMap};
-use diagnostic::{SpanHandler, mk_span_handler, default_handler, Auto, FatalError};
+use diagnostic::{SpanHandler, Handler, Auto, FatalError};
use parse::attr::ParserAttr;
use parse::parser::Parser;
use ptr::P;
use str::char_at;
-use std::cell::{Cell, RefCell};
-use std::fs::File;
+use std::cell::RefCell;
use std::io::Read;
use std::iter;
use std::path::{Path, PathBuf};
pub span_diagnostic: SpanHandler, // better be the same as the one in the reader!
/// Used to determine and report recursive mod inclusions
included_mod_stack: RefCell<Vec<PathBuf>>,
- pub node_id: Cell<ast::NodeId>,
-}
-
-pub fn new_parse_sess() -> ParseSess {
- ParseSess {
- span_diagnostic: mk_span_handler(default_handler(Auto, None, true), CodeMap::new()),
- included_mod_stack: RefCell::new(Vec::new()),
- node_id: Cell::new(1),
- }
-}
-
-pub fn new_parse_sess_special_handler(sh: SpanHandler) -> ParseSess {
- ParseSess {
- span_diagnostic: sh,
- included_mod_stack: RefCell::new(Vec::new()),
- node_id: Cell::new(1),
- }
}
impl ParseSess {
- pub fn next_node_id(&self) -> ast::NodeId {
- self.reserve_node_ids(1)
+ pub fn new() -> ParseSess {
+ let handler = SpanHandler::new(Handler::new(Auto, None, true), CodeMap::new());
+ ParseSess::with_span_handler(handler)
}
- pub fn reserve_node_ids(&self, count: ast::NodeId) -> ast::NodeId {
- let v = self.node_id.get();
- match v.checked_add(count) {
- Some(next) => { self.node_id.set(next); }
- None => panic!("Input too large, ran out of node ids!")
+ pub fn with_span_handler(sh: SpanHandler) -> ParseSess {
+ ParseSess {
+ span_diagnostic: sh,
+ included_mod_stack: RefCell::new(vec![])
}
+ }
- v
+ pub fn codemap(&self) -> &CodeMap {
+ &self.span_diagnostic.cm
}
}
name: String,
source: String)
-> Parser<'a> {
- filemap_to_parser(sess, string_to_filemap(sess, source, name), cfg)
+ filemap_to_parser(sess, sess.codemap().new_filemap(name, source), cfg)
}
/// Create a new parser, handling errors as appropriate
/// Given a session and a path and an optional span (for error reporting),
/// add the path to the session's codemap and return the new filemap.
-pub fn file_to_filemap(sess: &ParseSess, path: &Path, spanopt: Option<Span>)
- -> Rc<FileMap> {
- let err = |msg: &str| {
- match spanopt {
- Some(sp) => panic!(sess.span_diagnostic.span_fatal(sp, msg)),
- None => sess.span_diagnostic.handler().fatal(msg),
- }
- };
- let mut bytes = Vec::new();
- match File::open(path).and_then(|mut f| f.read_to_end(&mut bytes)) {
- Ok(..) => {}
+fn file_to_filemap(sess: &ParseSess, path: &Path, spanopt: Option<Span>)
+ -> Rc<FileMap> {
+ match sess.codemap().load_file(path) {
+ Ok(filemap) => filemap,
Err(e) => {
- err(&format!("couldn't read {:?}: {}", path.display(), e));
- unreachable!();
- }
- };
- match str::from_utf8(&bytes[..]).ok() {
- Some(s) => {
- string_to_filemap(sess, s.to_string(),
- path.to_str().unwrap().to_string())
- }
- None => {
- err(&format!("{:?} is not UTF-8 encoded", path.display()));
- unreachable!();
+ let msg = format!("couldn't read {:?}: {}", path.display(), e);
+ match spanopt {
+ Some(sp) => panic!(sess.span_diagnostic.span_fatal(sp, &msg)),
+ None => sess.span_diagnostic.handler().fatal(&msg)
+ }
}
}
}
-/// Given a session and a string, add the string to
-/// the session's codemap and return the new filemap
-pub fn string_to_filemap(sess: &ParseSess, source: String, path: String)
- -> Rc<FileMap> {
- sess.span_diagnostic.cm.new_filemap(path, source)
-}
-
/// Given a filemap, produce a sequence of token-trees
pub fn filemap_to_tts(sess: &ParseSess, filemap: Rc<FileMap>)
-> Vec<ast::TokenTree> {
}
#[test] fn parse_ident_pat () {
- let sess = new_parse_sess();
+ let sess = ParseSess::new();
let mut parser = string_to_parser(&sess, "b".to_string());
assert!(panictry!(parser.parse_pat_nopanic())
== P(ast::Pat{
variadic: false
}),
ast::Unsafety::Normal,
+ ast::Constness::NotConst,
abi::Rust,
ast::Generics{ // no idea on either of these:
lifetimes: Vec::new(),
}
#[test] fn crlf_doc_comments() {
- let sess = new_parse_sess();
+ let sess = ParseSess::new();
let name = "<source>".to_string();
let source = "/// doc comment\r\nfn foo() {}".to_string();
#[test]
fn ttdelim_span() {
- let sess = parse::new_parse_sess();
+ let sess = ParseSess::new();
let expr = parse::parse_expr_from_source_str("foo".to_string(),
"foo!( fn main() { body } )".to_string(), vec![], &sess);
let span = tts.iter().rev().next().unwrap().get_span();
- match sess.span_diagnostic.cm.span_to_snippet(span) {
+ match sess.codemap().span_to_snippet(span) {
Ok(s) => assert_eq!(&s[..], "{ body }"),
Err(_) => panic!("could not get snippet"),
}
use ast::{Mod, BiAdd, Arg, Arm, Attribute, BindByRef, BindByValue};
use ast::{BiBitAnd, BiBitOr, BiBitXor, BiRem, BiLt, BiGt, Block};
use ast::{BlockCheckMode, CaptureByRef, CaptureByValue, CaptureClause};
-use ast::{ConstImplItem, ConstTraitItem, Crate, CrateConfig};
+use ast::{Constness, ConstImplItem, ConstTraitItem, Crate, CrateConfig};
use ast::{Decl, DeclItem, DeclLocal, DefaultBlock, DefaultReturn};
use ast::{UnDeref, BiDiv, EMPTY_CTXT, EnumDef, ExplicitSelf};
use ast::{Expr, Expr_, ExprAddrOf, ExprMatch, ExprAgain};
use diagnostic::FatalError;
use std::collections::HashSet;
-use std::fs;
use std::io::prelude::*;
use std::mem;
use std::path::{Path, PathBuf};
};
let all_bounds =
Some(TraitTyParamBound(poly_trait_ref, TraitBoundModifier::None)).into_iter()
- .chain(other_bounds.into_vec().into_iter())
+ .chain(other_bounds.into_vec())
.collect();
Ok(ast::TyPolyTraitRef(all_bounds))
}
let TyParam {ident, bounds, default, ..} = try!(p.parse_ty_param());
try!(p.expect(&token::Semi));
(ident, TypeTraitItem(bounds, default))
- } else if try!(p.eat_keyword(keywords::Const)) {
+ } else if p.is_const_item() {
+ try!(p.expect_keyword(keywords::Const));
let ident = try!(p.parse_ident());
try!(p.expect(&token::Colon));
let ty = try!(p.parse_ty_sum());
};
(ident, ConstTraitItem(ty, default))
} else {
- let style = try!(p.parse_unsafety());
- let abi = if try!(p.eat_keyword(keywords::Extern)) {
- try!(p.parse_opt_abi()).unwrap_or(abi::C)
- } else {
- abi::Rust
- };
- try!(p.expect_keyword(keywords::Fn));
+ let (constness, unsafety, abi) = try!(p.parse_fn_front_matter());
let ident = try!(p.parse_ident());
let mut generics = try!(p.parse_generics());
generics.where_clause = try!(p.parse_where_clause());
let sig = ast::MethodSig {
- unsafety: style,
+ unsafety: unsafety,
+ constness: constness,
decl: d,
generics: generics,
abi: abi,
return self.parse_block_expr(lo, DefaultBlock);
},
token::BinOp(token::Or) | token::OrOr => {
- return self.parse_lambda_expr(CaptureByRef);
+ let lo = self.span.lo;
+ return self.parse_lambda_expr(lo, CaptureByRef);
},
token::Ident(id @ ast::Ident {
name: token::SELF_KEYWORD_NAME,
|p| Ok(try!(p.parse_expr_nopanic()))
));
let mut exprs = vec!(first_expr);
- exprs.extend(remaining_exprs.into_iter());
+ exprs.extend(remaining_exprs);
ex = ExprVec(exprs);
} else {
// Vector with one element.
}
_ => {
if try!(self.eat_lt()){
-
let (qself, path) =
try!(self.parse_qualified_path(LifetimeAndTypesWithColons));
-
+ hi = path.span.hi;
return Ok(self.mk_expr(lo, hi, ExprPath(Some(qself), path)));
}
if try!(self.eat_keyword(keywords::Move) ){
- return self.parse_lambda_expr(CaptureByValue);
+ let lo = self.last_span.lo;
+ return self.parse_lambda_expr(lo, CaptureByValue);
}
if try!(self.eat_keyword(keywords::If)) {
return self.parse_if_expr();
}
// `|args| expr`
- pub fn parse_lambda_expr(&mut self, capture_clause: CaptureClause)
+ pub fn parse_lambda_expr(&mut self, lo: BytePos, capture_clause: CaptureClause)
-> PResult<P<Expr>>
{
- let lo = self.span.lo;
let decl = try!(self.parse_fn_block_decl());
let body = match decl.output {
DefaultReturn(_) => {
/// Parse a structure field
fn parse_name_and_ty(&mut self, pr: Visibility,
attrs: Vec<Attribute> ) -> PResult<StructField> {
- let lo = self.span.lo;
+ let lo = match pr {
+ Inherited => self.span.lo,
+ Public => self.last_span.lo,
+ };
if !self.token.is_plain_ident() {
return Err(self.fatal("expected ident"));
}
};
if self.is_self_ident() {
let span = self.span;
- self.span_err(span, "cannot pass self by unsafe pointer");
+ self.span_err(span, "cannot pass self by raw pointer");
try!(self.bump());
}
// error case, making bogus self ident:
}
/// Parse an item-position function declaration.
- fn parse_item_fn(&mut self, unsafety: Unsafety, abi: abi::Abi) -> PResult<ItemInfo> {
+ fn parse_item_fn(&mut self,
+ unsafety: Unsafety,
+ constness: Constness,
+ abi: abi::Abi)
+ -> PResult<ItemInfo> {
let (ident, mut generics) = try!(self.parse_fn_header());
let decl = try!(self.parse_fn_decl(false));
generics.where_clause = try!(self.parse_where_clause());
let (inner_attrs, body) = try!(self.parse_inner_attrs_and_block());
- Ok((ident, ItemFn(decl, unsafety, abi, generics, body), Some(inner_attrs)))
+ Ok((ident, ItemFn(decl, unsafety, constness, abi, generics, body), Some(inner_attrs)))
+ }
+
+ /// true if we are looking at `const ID`, false for things like `const fn` etc
+ pub fn is_const_item(&mut self) -> bool {
+ self.token.is_keyword(keywords::Const) &&
+ !self.look_ahead(1, |t| t.is_keyword(keywords::Fn))
+ }
+
+ /// parses all the "front matter" for a `fn` declaration, up to
+ /// and including the `fn` keyword:
+ ///
+ /// - `const fn`
+ /// - `unsafe fn`
+ /// - `extern fn`
+ /// - etc
+ pub fn parse_fn_front_matter(&mut self) -> PResult<(ast::Constness, ast::Unsafety, abi::Abi)> {
+ let is_const_fn = try!(self.eat_keyword(keywords::Const));
+ let (constness, unsafety, abi) = if is_const_fn {
+ (Constness::Const, Unsafety::Normal, abi::Rust)
+ } else {
+ let unsafety = try!(self.parse_unsafety());
+ let abi = if try!(self.eat_keyword(keywords::Extern)) {
+ try!(self.parse_opt_abi()).unwrap_or(abi::C)
+ } else {
+ abi::Rust
+ };
+ (Constness::NotConst, unsafety, abi)
+ };
+ try!(self.expect_keyword(keywords::Fn));
+ Ok((constness, unsafety, abi))
}
/// Parse an impl item.
let typ = try!(self.parse_ty_sum());
try!(self.expect(&token::Semi));
(name, TypeImplItem(typ))
- } else if try!(self.eat_keyword(keywords::Const)) {
+ } else if self.is_const_item() {
+ try!(self.expect_keyword(keywords::Const));
let name = try!(self.parse_ident());
try!(self.expect(&token::Colon));
let typ = try!(self.parse_ty_sum());
(name, ConstImplItem(typ, expr))
} else {
let (name, inner_attrs, node) = try!(self.parse_impl_method(vis));
- attrs.extend(inner_attrs.into_iter());
+ attrs.extend(inner_attrs);
(name, node)
};
}
Ok((token::special_idents::invalid, vec![], ast::MacImplItem(m)))
} else {
- let unsafety = try!(self.parse_unsafety());
- let abi = if try!(self.eat_keyword(keywords::Extern)) {
- try!(self.parse_opt_abi()).unwrap_or(abi::C)
- } else {
- abi::Rust
- };
- try!(self.expect_keyword(keywords::Fn));
+ let (constness, unsafety, abi) = try!(self.parse_fn_front_matter());
let ident = try!(self.parse_ident());
let mut generics = try!(self.parse_generics());
let (explicit_self, decl) = try!(self.parse_fn_decl_with_self(|p| {
abi: abi,
explicit_self: explicit_self,
unsafety: unsafety,
+ constness: constness,
decl: decl
}, body)))
}
if try!(self.eat(&token::DotDot) ){
if generics.is_parameterized() {
self.span_err(impl_span, "default trait implementations are not \
- allowed to have genercis");
+ allowed to have generics");
}
try!(self.expect(&token::OpenDelim(token::Brace)));
outer_attrs: &[ast::Attribute],
id_sp: Span)
-> PResult<(ast::Item_, Vec<ast::Attribute> )> {
- let mut prefix = PathBuf::from(&self.sess.span_diagnostic.cm
- .span_to_filename(self.span));
+ let mut prefix = PathBuf::from(&self.sess.codemap().span_to_filename(self.span));
prefix.pop();
let mut dir_path = prefix;
for part in &self.mod_path_stack {
let secondary_path_str = format!("{}/mod.rs", mod_name);
let default_path = dir_path.join(&default_path_str[..]);
let secondary_path = dir_path.join(&secondary_path_str[..]);
- let default_exists = fs::metadata(&default_path).is_ok();
- let secondary_exists = fs::metadata(&secondary_path).is_ok();
+ let default_exists = self.sess.codemap().file_exists(&default_path);
+ let secondary_exists = self.sess.codemap().file_exists(&secondary_path);
if !self.owns_directory {
self.span_err(id_sp,
let abi = opt_abi.unwrap_or(abi::C);
- attrs.extend(self.parse_inner_attributes().into_iter());
+ attrs.extend(self.parse_inner_attributes());
let mut foreign_items = vec![];
while let Some(item) = try!(self.parse_foreign_item()) {
try!(self.bump());
let mut attrs = attrs;
mem::swap(&mut item.attrs, &mut attrs);
- item.attrs.extend(attrs.into_iter());
+ item.attrs.extend(attrs);
return Ok(Some(P(item)));
}
None => {}
// EXTERN FUNCTION ITEM
let abi = opt_abi.unwrap_or(abi::C);
let (ident, item_, extra_attrs) =
- try!(self.parse_item_fn(Unsafety::Normal, abi));
+ try!(self.parse_item_fn(Unsafety::Normal, Constness::NotConst, abi));
let last_span = self.last_span;
let item = self.mk_item(lo,
last_span.hi,
return Ok(Some(try!(self.parse_item_foreign_mod(lo, opt_abi, visibility, attrs))));
}
- let span = self.span;
- let token_str = self.this_token_to_string();
- return Err(self.span_fatal(span,
- &format!("expected `{}` or `fn`, found `{}`", "{",
- token_str)))
+ try!(self.expect_one_of(&[], &[]));
}
if try!(self.eat_keyword_noexpect(keywords::Virtual) ){
return Ok(Some(item));
}
if try!(self.eat_keyword(keywords::Const) ){
+ if self.check_keyword(keywords::Fn) {
+ // CONST FUNCTION ITEM
+ try!(self.bump());
+ let (ident, item_, extra_attrs) =
+ try!(self.parse_item_fn(Unsafety::Normal, Constness::Const, abi::Rust));
+ let last_span = self.last_span;
+ let item = self.mk_item(lo,
+ last_span.hi,
+ ident,
+ item_,
+ visibility,
+ maybe_append(attrs, extra_attrs));
+ return Ok(Some(item));
+ }
+
// CONST ITEM
if try!(self.eat_keyword(keywords::Mut) ){
let last_span = self.last_span;
// FUNCTION ITEM
try!(self.bump());
let (ident, item_, extra_attrs) =
- try!(self.parse_item_fn(Unsafety::Normal, abi::Rust));
+ try!(self.parse_item_fn(Unsafety::Normal, Constness::NotConst, abi::Rust));
let last_span = self.last_span;
let item = self.mk_item(lo,
last_span.hi,
};
try!(self.expect_keyword(keywords::Fn));
let (ident, item_, extra_attrs) =
- try!(self.parse_item_fn(Unsafety::Unsafe, abi));
+ try!(self.parse_item_fn(Unsafety::Unsafe, Constness::NotConst, abi));
let last_span = self.last_span;
let item = self.mk_item(lo,
last_span.hi,
to_string(|s| s.print_ident(*id))
}
-pub fn fun_to_string(decl: &ast::FnDecl, unsafety: ast::Unsafety, name: ast::Ident,
- opt_explicit_self: Option<&ast::ExplicitSelf_>,
- generics: &ast::Generics) -> String {
+pub fn fun_to_string(decl: &ast::FnDecl,
+ unsafety: ast::Unsafety,
+ constness: ast::Constness,
+ name: ast::Ident,
+ opt_explicit_self: Option<&ast::ExplicitSelf_>,
+ generics: &ast::Generics)
+ -> String {
to_string(|s| {
try!(s.head(""));
- try!(s.print_fn(decl, unsafety, abi::Rust, Some(name),
+ try!(s.print_fn(decl, unsafety, constness, abi::Rust, Some(name),
generics, opt_explicit_self, ast::Inherited));
try!(s.end()); // Close the head box
s.end() // Close the outer box
match item.node {
ast::ForeignItemFn(ref decl, ref generics) => {
try!(self.head(""));
- try!(self.print_fn(&**decl, ast::Unsafety::Normal,
+ try!(self.print_fn(decl, ast::Unsafety::Normal,
+ ast::Constness::NotConst,
abi::Rust, Some(item.ident),
generics, None, item.vis));
try!(self.end()); // end head-ibox
try!(word(&mut self.s, ";"));
try!(self.end()); // end the outer cbox
}
- ast::ItemFn(ref decl, unsafety, abi, ref typarams, ref body) => {
+ ast::ItemFn(ref decl, unsafety, constness, abi, ref typarams, ref body) => {
try!(self.head(""));
try!(self.print_fn(
decl,
unsafety,
+ constness,
abi,
Some(item.ident),
typarams,
-> io::Result<()> {
self.print_fn(&m.decl,
m.unsafety,
+ m.constness,
m.abi,
Some(ident),
&m.generics,
comma = true;
}
- for binding in &*data.bindings {
+ for binding in data.bindings.iter() {
if comma {
try!(self.word_space(","))
}
pub fn print_fn(&mut self,
decl: &ast::FnDecl,
unsafety: ast::Unsafety,
+ constness: ast::Constness,
abi: abi::Abi,
name: Option<ast::Ident>,
generics: &ast::Generics,
opt_explicit_self: Option<&ast::ExplicitSelf_>,
vis: ast::Visibility) -> io::Result<()> {
- try!(self.print_fn_header_info(unsafety, abi, vis));
+ try!(self.print_fn_header_info(unsafety, constness, abi, vis));
if let Some(name) = name {
try!(self.nbsp());
predicates: Vec::new(),
},
};
- try!(self.print_fn(decl, unsafety, abi, name,
- &generics, opt_explicit_self,
+ try!(self.print_fn(decl,
+ unsafety,
+ ast::Constness::NotConst,
+ abi,
+ name,
+ &generics,
+ opt_explicit_self,
ast::Inherited));
self.end()
}
}
ast::LitBinary(ref v) => {
let mut escaped: String = String::new();
- for &ch in &**v {
+ for &ch in v.iter() {
escaped.extend(ascii::escape_default(ch)
.map(|c| c as char));
}
pub fn print_fn_header_info(&mut self,
unsafety: ast::Unsafety,
+ constness: ast::Constness,
abi: abi::Abi,
vis: ast::Visibility) -> io::Result<()> {
try!(word(&mut self.s, &visibility_qualified(vis, "")));
try!(self.print_unsafety(unsafety));
+ match constness {
+ ast::Constness::NotConst => {}
+ ast::Constness::Const => try!(self.word_nbsp("const"))
+ }
+
if abi != abi::Rust {
try!(self.word_nbsp("extern"));
try!(self.word_nbsp(&abi.to_string()));
variadic: false
};
let generics = ast_util::empty_generics();
- assert_eq!(fun_to_string(&decl, ast::Unsafety::Normal, abba_ident,
- None, &generics),
+ assert_eq!(fun_to_string(&decl, ast::Unsafety::Normal,
+ ast::Constness::NotConst,
+ abba_ident,
+ None, &generics),
"fn abba()");
}
let i = if is_test_fn(&self.cx, &*i) || is_bench_fn(&self.cx, &*i) {
match i.node {
- ast::ItemFn(_, ast::Unsafety::Unsafe, _, _, _) => {
+ ast::ItemFn(_, ast::Unsafety::Unsafe, _, _, _, _) => {
let diag = self.cx.span_diagnostic;
panic!(diag.span_fatal(i.span, "unsafe functions cannot be used for tests"));
}
allow_internal_unstable: true,
}
};
- let expn_id = cx.sess.span_diagnostic.cm.record_expansion(info);
+ let expn_id = cx.sess.codemap().record_expansion(info);
let mut sp = sp;
sp.expn_id = expn_id;
return sp;
fn has_test_signature(i: &ast::Item) -> HasTestSignature {
match &i.node {
- &ast::ItemFn(ref decl, _, _, ref generics, _) => {
+ &ast::ItemFn(ref decl, _, _, _, ref generics, _) => {
let no_output = match decl.output {
ast::DefaultReturn(..) => true,
ast::Return(ref t) if t.node == ast::TyTup(vec![]) => true,
fn has_test_signature(i: &ast::Item) -> bool {
match i.node {
- ast::ItemFn(ref decl, _, _, ref generics, _) => {
+ ast::ItemFn(ref decl, _, _, _, ref generics, _) => {
let input_cnt = decl.inputs.len();
let no_output = match decl.output {
ast::DefaultReturn(..) => true,
let main_ret_ty = ecx.ty(sp, ast::TyTup(vec![]));
let main_body = ecx.block_all(sp, vec![call_test_main], None);
let main = ast::ItemFn(ecx.fn_decl(vec![], main_ret_ty),
- ast::Unsafety::Normal, ::abi::Rust, empty_generics(), main_body);
+ ast::Unsafety::Normal,
+ ast::Constness::NotConst,
+ ::abi::Rust, empty_generics(), main_body);
let main = P(ast::Item {
ident: token::str_to_ident("main"),
attrs: vec![main_attr],
diag.handler.bug("expected to find top-level re-export name, but found None");
}
};
- visible_path.extend(path.into_iter());
+ visible_path.extend(path);
let fn_expr = ecx.expr_path(ecx.path_global(span, visible_path));
// except according to those terms.
use ast;
-use parse::new_parse_sess;
-use parse::{ParseSess,string_to_filemap,filemap_to_tts};
+use parse::{ParseSess,filemap_to_tts};
use parse::new_parser_from_source_str;
use parse::parser::Parser;
use parse::token;
/// Map a string to tts, using a made-up filename:
pub fn string_to_tts(source_str: String) -> Vec<ast::TokenTree> {
- let ps = new_parse_sess();
- filemap_to_tts(&ps,
- string_to_filemap(&ps, source_str, "bogofile".to_string()))
+ let ps = ParseSess::new();
+ filemap_to_tts(&ps, ps.codemap().new_filemap("bogofile".to_string(), source_str))
}
/// Map string to parser (via tts)
fn with_error_checking_parse<T, F>(s: String, f: F) -> T where
F: FnOnce(&mut Parser) -> T,
{
- let ps = new_parse_sess();
+ let ps = ParseSess::new();
let mut p = string_to_parser(&ps, s);
let x = f(&mut p);
p.abort_if_errors();
pub fn string_to_pat(source_str: String) -> P<ast::Pat> {
// Binding `sess` and `parser` works around dropck-injected
// region-inference issues; see #25212, #22323, #22321.
- let sess = new_parse_sess();
+ let sess = ParseSess::new();
let mut parser = string_to_parser(&sess, source_str);
parser.parse_pat()
}
#[derive(Copy, Clone)]
pub enum FnKind<'a> {
/// fn foo() or extern "Abi" fn foo()
- FkItemFn(Ident, &'a Generics, Unsafety, Abi, Visibility),
+ FkItemFn(Ident, &'a Generics, Unsafety, Constness, Abi, Visibility),
/// fn foo(&self)
FkMethod(Ident, &'a MethodSig, Option<Visibility>),
visitor.visit_ty(&**typ);
visitor.visit_expr(&**expr);
}
- ItemFn(ref declaration, fn_style, abi, ref generics, ref body) => {
- visitor.visit_fn(FkItemFn(item.ident, generics, fn_style, abi, item.vis),
+ ItemFn(ref declaration, unsafety, constness, abi, ref generics, ref body) => {
+ visitor.visit_fn(FkItemFn(item.ident, generics, unsafety,
+ constness, abi, item.vis),
&**declaration,
&**body,
item.span,
path_parameters: &'v PathParameters) {
match *path_parameters {
ast::AngleBracketedParameters(ref data) => {
- for typ in &*data.types {
+ for typ in data.types.iter() {
visitor.visit_ty(&**typ);
}
for lifetime in &data.lifetimes {
visitor.visit_lifetime_ref(lifetime);
}
- for binding in &*data.bindings {
+ for binding in data.bindings.iter() {
visitor.visit_assoc_type_binding(&**binding);
}
}
pub fn walk_ty_param_bounds_helper<'v, V: Visitor<'v>>(visitor: &mut V,
bounds: &'v OwnedSlice<TyParamBound>) {
- for bound in &**bounds {
+ for bound in bounds.iter() {
visitor.visit_ty_param_bound(bound)
}
}
}
pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics) {
- for param in &*generics.ty_params {
+ for param in generics.ty_params.iter() {
visitor.visit_ident(param.span, param.ident);
walk_ty_param_bounds_helper(visitor, ¶m.bounds);
walk_ty_opt(visitor, ¶m.default);
walk_fn_decl(visitor, function_declaration);
match function_kind {
- FkItemFn(_, generics, _, _, _) => {
+ FkItemFn(_, generics, _, _, _, _) => {
visitor.visit_generics(generics);
}
FkMethod(_, sig, _) => {
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
- html_favicon_url = "http://www.rust-lang.org/favicon.ico",
+ html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/",
html_playground_url = "http://play.rust-lang.org/")]
#![deny(missing_docs)]
#![feature(box_syntax)]
-#![feature(collections)]
+#![feature(owned_ascii_ext)]
+#![feature(path_ext)]
#![feature(rustc_private)]
#![feature(staged_api)]
-#![feature(std_misc)]
#![feature(str_char)]
-#![feature(path_ext)]
+#![feature(vec_push_all)]
#![cfg_attr(windows, feature(libc))]
#[macro_use] extern crate log;
Number(0), Number(0), Number(0), Number(0), Number(0),
Number(0), Number(0), Number(0), Number(0),
];
- for (dst, src) in mparams.iter_mut().zip(params.iter()) {
+ for (dst, src) in mparams.iter_mut().zip(params) {
*dst = (*src).clone();
}
let mut s_ = Vec::with_capacity(flags.precision);
let n = flags.precision - s.len();
s_.extend(repeat(b'0').take(n));
- s_.extend(s.into_iter());
+ s_.extend(s);
s = s_;
}
assert!(!s.is_empty(), "string conversion produced empty result");
FormatHex => {
if flags.alternate {
let s_ = replace(&mut s, vec!(b'0', b'x'));
- s.extend(s_.into_iter());
+ s.extend(s_);
}
}
FormatHEX => {
s = s.into_ascii_uppercase();
if flags.alternate {
let s_ = replace(&mut s, vec!(b'0', b'X'));
- s.extend(s_.into_iter());
+ s.extend(s_);
}
}
FormatString => unreachable!()
} else {
let mut s_ = Vec::with_capacity(flags.width);
s_.extend(repeat(b' ').take(n));
- s_.extend(s.into_iter());
+ s_.extend(s);
s = s_;
}
}
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
- html_favicon_url = "http://www.rust-lang.org/favicon.ico",
+ html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/")]
#![feature(asm)]
#![feature(box_syntax)]
-#![feature(collections)]
-#![feature(core)]
-#![feature(rustc_private)]
-#![feature(staged_api)]
-#![feature(std_misc)]
-#![feature(libc)]
-#![feature(set_stdio)]
#![feature(duration)]
#![feature(duration_span)]
+#![feature(fnbox)]
+#![feature(iter_cmp)]
+#![feature(libc)]
+#![feature(rt)]
+#![feature(rustc_private)]
+#![feature(set_stdio)]
+#![feature(slice_extras)]
+#![feature(staged_api)]
extern crate getopts;
extern crate serialize;
use std::sync::mpsc::{channel, Sender};
use std::sync::{Arc, Mutex};
use std::thread;
-use std::thunk::Thunk;
use std::time::Duration;
// to be used by rustc to compile tests in libtest
impl TestDesc {
fn padded_name(&self, column_count: usize, align: NamePadding) -> String {
- let mut name = String::from_str(self.name.as_slice());
+ let mut name = String::from(self.name.as_slice());
let fill = column_count.saturating_sub(name.len());
let pad = repeat(" ").take(fill).collect::<String>();
match align {
StaticTestFn(fn()),
StaticBenchFn(fn(&mut Bencher)),
StaticMetricFn(fn(&mut MetricMap)),
- DynTestFn(Thunk<'static>),
+ DynTestFn(Box<FnBox() + Send>),
DynMetricFn(Box<FnBox(&mut MetricMap)+Send>),
DynBenchFn(Box<TDynBenchFn+'static>)
}
}
}
+// Format a number with thousands separators
+fn fmt_thousands_sep(mut n: usize, sep: char) -> String {
+ use std::fmt::Write;
+ let mut output = String::new();
+ let mut trailing = false;
+ for &pow in &[9, 6, 3, 0] {
+ let base = 10_usize.pow(pow);
+ if pow == 0 || trailing || n / base != 0 {
+ if !trailing {
+ output.write_fmt(format_args!("{}", n / base)).unwrap();
+ } else {
+ output.write_fmt(format_args!("{:03}", n / base)).unwrap();
+ }
+ if pow != 0 {
+ output.push(sep);
+ }
+ trailing = true;
+ }
+ n %= base;
+ }
+
+ output
+}
+
pub fn fmt_bench_samples(bs: &BenchSamples) -> String {
+ use std::fmt::Write;
+ let mut output = String::new();
+
+ let median = bs.ns_iter_summ.median as usize;
+ let deviation = (bs.ns_iter_summ.max - bs.ns_iter_summ.min) as usize;
+
+ output.write_fmt(format_args!("{:>11} ns/iter (+/- {})",
+ fmt_thousands_sep(median, ','),
+ fmt_thousands_sep(deviation, ','))).unwrap();
if bs.mb_s != 0 {
- format!("{:>9} ns/iter (+/- {}) = {} MB/s",
- bs.ns_iter_summ.median as usize,
- (bs.ns_iter_summ.max - bs.ns_iter_summ.min) as usize,
- bs.mb_s)
- } else {
- format!("{:>9} ns/iter (+/- {})",
- bs.ns_iter_summ.median as usize,
- (bs.ns_iter_summ.max - bs.ns_iter_summ.min) as usize)
+ output.write_fmt(format_args!(" = {} MB/s", bs.mb_s)).unwrap();
}
+ output
}
// A simple console test runner
fn use_color(opts: &TestOpts) -> bool {
match opts.color {
- AutoColor => get_concurrency() == 1 && stdout_isatty(),
+ AutoColor => !opts.nocapture && stdout_isatty(),
AlwaysColor => true,
NeverColor => false,
}
fn run_test_inner(desc: TestDesc,
monitor_ch: Sender<MonitorMsg>,
nocapture: bool,
- testfn: Thunk<'static>) {
+ testfn: Box<FnBox() + Send>) {
struct Sink(Arc<Mutex<Vec<u8>>>);
impl Write for Sink {
fn write(&mut self, data: &[u8]) -> io::Result<usize> {
TestDesc, TestDescAndFn, TestOpts, run_test,
MetricMap,
StaticTestName, DynTestName, DynTestFn, ShouldPanic};
- use std::thunk::Thunk;
use std::sync::mpsc::channel;
#[test]
"test::parse_ignored_flag".to_string(),
"test::sort_tests".to_string());
- for (a, b) in expected.iter().zip(filtered.iter()) {
+ for (a, b) in expected.iter().zip(filtered) {
assert!(*a == b.desc.name.to_string());
}
}
#else
#if defined(__linux__) || defined(__FreeBSD__)
#define MORESTACK __morestack
-#define EXHAUSTED rust_stack_exhausted
+#define EXHAUSTED rust_stack_exhausted@plt
#else
#define MORESTACK ___morestack
#define EXHAUSTED _rust_stack_exhausted
#endif
.globl MORESTACK
-.globl EXHAUSTED
// FIXME: What about __WIN32__?
#if defined(__linux__) || defined(__FreeBSD__)
// re-align the stack
subl $12,%esp
- calll EXHAUSTED
+ call EXHAUSTED
// the exhaustion function guarantees that it can't return
.cfi_endproc
#include <assert.h>
#include <stdlib.h>
-#if !defined(__WIN32__)
+
+#if !defined(_WIN32)
#include <dirent.h>
#include <pthread.h>
#include <signal.h>
/* Foreign builtins. */
//include valgrind.h after stdint.h so that uintptr_t is defined for msys2 w64
+#ifndef _WIN32
#include "valgrind/valgrind.h"
+#endif
+
+#if defined(_MSC_VER)
+# define RUST_BUILTIN_API __declspec(dllexport)
+#else
+# define RUST_BUILTIN_API
+#endif
#ifndef _WIN32
char*
int
rust_dir_get_mode(struct dirent* entry_ptr) {
-#if defined(_DIRENT_HAVE_D_TYPE)
+#if defined(_DIRENT_HAVE_D_TYPE) || defined(__APPLE__)
switch (entry_ptr->d_type) {
case DT_BLK: return S_IFBLK;
case DT_CHR: return S_IFCHR;
case DT_LNK: return S_IFLNK;
case DT_REG: return S_IFREG;
case DT_SOCK: return S_IFSOCK;
+ case DT_DIR: return S_IFDIR;
}
#endif
return -1;
}
#endif
-uintptr_t
-rust_running_on_valgrind() {
- return RUNNING_ON_VALGRIND;
-}
-
-#if defined(__WIN32__)
+#if defined(_WIN32)
int
get_num_cpus() {
SYSTEM_INFO sysinfo;
}
#endif
+RUST_BUILTIN_API
uintptr_t
rust_get_num_cpus() {
return get_num_cpus();
}
-unsigned int
-rust_valgrind_stack_register(void *start, void *end) {
- return VALGRIND_STACK_REGISTER(start, end);
-}
-
-void
-rust_valgrind_stack_deregister(unsigned int id) {
- VALGRIND_STACK_DEREGISTER(id);
+uintptr_t
+rust_running_on_valgrind() {
+#ifdef _WIN32
+ return 0;
+#else
+ return RUNNING_ON_VALGRIND;
+#endif
}
#if defined(__DragonFly__)
struct TwoU8s arg6;
};
+// MSVC doesn't allow empty structs or unions
+#ifndef _MSC_VER
struct Empty {
};
assert(v1.arg6.one == v2.arg6.one + 1);
assert(v1.arg6.two == v2.arg6.two + 1);
}
+#endif
intptr_t
rust_get_test_int() {
}
int
-rust_dbg_static_mut;
-
-int rust_dbg_static_mut = 3;
+rust_dbg_static_mut = 3;
void
rust_dbg_static_mut_check_four() {
_ostype=unknown-dragonfly
;;
- OpenBSD)
+ Bitrig)
+ _ostype=unknown-bitrig
+ ;;
+
+ OpenBSD)
_ostype=unknown-openbsd
- ;;
+ ;;
Darwin)
_ostype=apple-darwin
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
}
}
-fn write_toc(book: &Book, path_to_root: &Path, out: &mut Write) -> io::Result<()> {
+fn write_toc(book: &Book, current_page: &BookItem, out: &mut Write) -> io::Result<()> {
fn walk_items(items: &[BookItem],
section: &str,
- path_to_root: &Path,
+ current_page: &BookItem,
out: &mut Write) -> io::Result<()> {
for (i, item) in items.iter().enumerate() {
- try!(walk_item(item, &format!("{}{}.", section, i + 1)[..], path_to_root, out));
+ try!(walk_item(item, &format!("{}{}.", section, i + 1)[..], current_page, out));
}
Ok(())
}
fn walk_item(item: &BookItem,
section: &str,
- path_to_root: &Path,
+ current_page: &BookItem,
out: &mut Write) -> io::Result<()> {
- try!(writeln!(out, "<li><a href='{}'><b>{}</b> {}</a>",
- path_to_root.join(&item.path.with_extension("html")).display(),
+ let class_string = if item.path == current_page.path {
+ "class='active'"
+ } else {
+ ""
+ };
+
+ try!(writeln!(out, "<li><a {} href='{}'><b>{}</b> {}</a>",
+ class_string,
+ current_page.path_to_root.join(&item.path).with_extension("html").display(),
section,
item.title));
if !item.children.is_empty() {
try!(writeln!(out, "<ul class='section'>"));
- let _ = walk_items(&item.children[..], section, path_to_root, out);
+ let _ = walk_items(&item.children[..], section, current_page, out);
try!(writeln!(out, "</ul>"));
}
try!(writeln!(out, "</li>"));
try!(writeln!(out, "<div id='toc' class='mobile-hidden'>"));
try!(writeln!(out, "<ul class='chapter'>"));
- try!(walk_items(&book.chapters[..], "", path_to_root, out));
+ try!(walk_items(&book.chapters[..], "", ¤t_page, out));
try!(writeln!(out, "</ul>"));
try!(writeln!(out, "</div>"));
<span class="bar"></span>
</button>
</div>"#));
- let _ = write_toc(book, &item.path_to_root, &mut toc);
+ let _ = write_toc(book, &item, &mut toc);
try!(writeln!(&mut toc, "<div id='page-wrapper'>"));
try!(writeln!(&mut toc, "<div id='page'>"));
}
// create index.html from the root README
try!(fs::copy(&tgt.join("README.html"), &tgt.join("index.html")));
- // Copy some js for playpen
- let mut jquery = try!(File::create(tgt.join("jquery.js")));
- let js = include_bytes!("../librustdoc/html/static/jquery-2.1.0.min.js");
- try!(jquery.write_all(js));
+ // Copy js for playpen
let mut playpen = try!(File::create(tgt.join("playpen.js")));
let js = include_bytes!("../librustdoc/html/static/playpen.js");
try!(playpen.write_all(js));
color: #000000;
}
+.chapter li a.active {
+ text-decoration: underline;
+ font-weight: bold;
+}
+
#toggle-nav {
height: 20px;
width: 30px;
});
</script>
-<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="playpen.js"></script>
"#;
#![deny(warnings)]
-#![feature(core)]
-#![feature(exit_status)]
-#![feature(rustdoc)]
-#![feature(rustc_private)]
+#![feature(iter_arith)]
#![feature(path_relative_from)]
+#![feature(rustc_private)]
+#![feature(rustdoc)]
extern crate rustdoc;
extern crate rustc_back;
use std::env;
use std::error::Error;
+use std::process;
+use std::sync::atomic::{AtomicIsize, ATOMIC_ISIZE_INIT, Ordering};
use subcommand::Subcommand;
use term::Term;
mod css;
mod javascript;
+static EXIT_STATUS: AtomicIsize = ATOMIC_ISIZE_INIT;
+
#[cfg(not(test))] // thanks #12327
fn main() {
let mut term = Term::new();
}
}
}
+ process::exit(EXIT_STATUS.load(Ordering::SeqCst) as i32);
}
build::parse_cmd,
serve::parse_cmd,
test::parse_cmd];
- for parser in cmds.iter() {
+ for parser in &cmds {
let parsed = (*parser)(name);
if parsed.is_some() { return parsed }
}
//! An abstraction of the terminal. Eventually, provide color and
//! verbosity support. For now, just a wrapper around stdout/stderr.
-use std::env;
use std::io;
use std::io::prelude::*;
+use std::sync::atomic::Ordering;
pub struct Term {
err: Box<Write + 'static>
pub fn err(&mut self, msg: &str) {
// swallow any errors
let _ = writeln!(&mut self.err, "{}", msg);
- env::set_exit_status(101);
+ ::EXIT_STATUS.store(101, Ordering::SeqCst);
}
}
using namespace llvm::sys;
using namespace llvm::object;
+// libmorestack is not used on other platforms
+#if defined(__linux__) || defined(__APPLE__)
+extern "C" void __morestack(void);
+
+static void* morestack_addr() {
+ return reinterpret_cast<void*>(__morestack);
+}
+#endif
+
class RustJITMemoryManager : public SectionMemoryManager
{
typedef SectionMemoryManager Base;
- const void *morestack;
-
public:
- RustJITMemoryManager(const void *morestack_ptr)
- : morestack(morestack_ptr)
- {}
+ RustJITMemoryManager() {}
uint64_t getSymbolAddress(const std::string &Name) override
{
+#if defined(__linux__) || defined(__APPLE__)
if (Name == "__morestack" || Name == "___morestack")
- return reinterpret_cast<uint64_t>(morestack);
+ return reinterpret_cast<uint64_t>(__morestack);
+ if (Name == "__morestack_addr" || Name == "___morestack_addr")
+ return reinterpret_cast<uint64_t>(morestack_addr);
+#endif
return Base::getSymbolAddress(Name);
}
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(RustJITMemoryManager, LLVMRustJITMemoryManagerRef)
-extern "C" LLVMRustJITMemoryManagerRef LLVMRustCreateJITMemoryManager(void *morestack)
-{
- return wrap(new RustJITMemoryManager(morestack));
-}
-
extern "C" LLVMBool LLVMRustLoadDynamicLibrary(const char *path)
{
std::string err;
extern "C" void LLVMExecutionEngineAddModule(
LLVMExecutionEngineRef eeref, LLVMModuleRef mref)
{
+#ifdef _WIN32
+ // On Windows, MCJIT must generate ELF objects
+ std::string target = getProcessTriple();
+ target += "-elf";
+ target = Triple::normalize(target);
+ unwrap(mref)->setTargetTriple(target);
+#endif
LLVMAddModule(eeref, mref);
}
return ee->removeModule(m);
}
-extern "C" LLVMExecutionEngineRef LLVMBuildExecutionEngine(
- LLVMModuleRef mod, LLVMRustJITMemoryManagerRef mref)
+extern "C" LLVMExecutionEngineRef LLVMBuildExecutionEngine(LLVMModuleRef mod)
{
// These are necessary for code generation to work properly.
InitializeNativeTarget();
InitializeNativeTargetAsmPrinter();
InitializeNativeTargetAsmParser();
+#ifdef _WIN32
+ // On Windows, MCJIT must generate ELF objects
+ std::string target = getProcessTriple();
+ target += "-elf";
+ target = Triple::normalize(target);
+ unwrap(mod)->setTargetTriple(target);
+#endif
+
std::string error_str;
TargetOptions options;
- options.JITEmitDebugInfo = true;
- options.NoFramePointerElim = true;
+ RustJITMemoryManager *mm = new RustJITMemoryManager;
ExecutionEngine *ee =
#if LLVM_VERSION_MINOR >= 6
EngineBuilder(std::unique_ptr<Module>(unwrap(mod)))
- .setMCJITMemoryManager(std::unique_ptr<RustJITMemoryManager>(unwrap(mref)))
+ .setMCJITMemoryManager(std::unique_ptr<RustJITMemoryManager>(mm))
#else
EngineBuilder(unwrap(mod))
- .setMCJITMemoryManager(unwrap(mref))
+ .setMCJITMemoryManager(mm)
#endif
.setEngineKind(EngineKind::JIT)
.setErrorStr(&error_str)
#include "llvm/Support/CBindingWrapping.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Host.h"
+#if LLVM_VERSION_MINOR >= 7
+#include "llvm/Analysis/TargetLibraryInfo.h"
+#include "llvm/Analysis/TargetTransformInfo.h"
+#else
#include "llvm/Target/TargetLibraryInfo.h"
+#endif
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
+
#include "llvm-c/Transforms/PassManagerBuilder.h"
using namespace llvm;
+using namespace llvm::legacy;
extern cl::opt<bool> EnableARMEHABI;
CodeGenOpt::Level OptLevel,
bool EnableSegmentedStacks,
bool UseSoftFloat,
- bool NoFramePointerElim,
bool PositionIndependentExecutable,
bool FunctionSections,
bool DataSections) {
TargetOptions Options;
Options.PositionIndependentExecutable = PositionIndependentExecutable;
- Options.NoFramePointerElim = NoFramePointerElim;
Options.FloatABIType = FloatABI::Default;
- Options.UseSoftFloat = UseSoftFloat;
if (UseSoftFloat) {
Options.FloatABIType = FloatABI::Soft;
}
+ Options.DataSections = DataSections;
+ Options.FunctionSections = FunctionSections;
TargetMachine *TM = TheTarget->createTargetMachine(Trip.getTriple(),
real_cpu,
RM,
CM,
OptLevel);
- TM->setDataSections(DataSections);
- TM->setFunctionSections(FunctionSections);
return wrap(TM);
}
LLVMPassManagerRef PMR,
LLVMModuleRef M) {
PassManagerBase *PM = unwrap(PMR);
-#if LLVM_VERSION_MINOR >= 6
+#if LLVM_VERSION_MINOR >= 7
+ PM->add(createTargetTransformInfoWrapperPass(
+ unwrap(TM)->getTargetIRAnalysis()));
+#else
+#if LLVM_VERSION_MINOR == 6
PM->add(new DataLayoutPass());
#else
PM->add(new DataLayoutPass(unwrap(M)));
#endif
unwrap(TM)->addAnalysisPasses(*PM);
+#endif
+}
+
+extern "C" void
+LLVMRustConfigurePassManagerBuilder(LLVMPassManagerBuilderRef PMB,
+ CodeGenOpt::Level OptLevel,
+ bool MergeFunctions,
+ bool SLPVectorize,
+ bool LoopVectorize) {
+#if LLVM_VERSION_MINOR >= 6
+ // Ignore mergefunc for now as enabling it causes crashes.
+ //unwrap(PMB)->MergeFunctions = MergeFunctions;
+#endif
+ unwrap(PMB)->SLPVectorize = SLPVectorize;
+ unwrap(PMB)->OptLevel = OptLevel;
+ unwrap(PMB)->LoopVectorize = LoopVectorize;
}
// Unfortunately, the LLVM C API doesn't provide a way to set the `LibraryInfo`
LLVMModuleRef M,
bool DisableSimplifyLibCalls) {
Triple TargetTriple(unwrap(M)->getTargetTriple());
+#if LLVM_VERSION_MINOR >= 7
+ TargetLibraryInfoImpl *TLI = new TargetLibraryInfoImpl(TargetTriple);
+#else
TargetLibraryInfo *TLI = new TargetLibraryInfo(TargetTriple);
+#endif
if (DisableSimplifyLibCalls)
TLI->disableAllFunctions();
unwrap(PMB)->LibraryInfo = TLI;
LLVMModuleRef M,
bool DisableSimplifyLibCalls) {
Triple TargetTriple(unwrap(M)->getTargetTriple());
+#if LLVM_VERSION_MINOR >= 7
+ TargetLibraryInfoImpl TLII(TargetTriple);
+ if (DisableSimplifyLibCalls)
+ TLII.disableAllFunctions();
+ unwrap(PMB)->add(new TargetLibraryInfoWrapperPass(TLII));
+#else
TargetLibraryInfo *TLI = new TargetLibraryInfo(TargetTriple);
if (DisableSimplifyLibCalls)
TLI->disableAllFunctions();
unwrap(PMB)->add(TLI);
+#endif
}
// Unfortunately, the LLVM C API doesn't provide an easy way of iterating over
LLVMRustSetLastError(ErrorInfo.c_str());
return false;
}
- formatted_raw_ostream FOS(OS);
+#if LLVM_VERSION_MINOR >= 7
+ unwrap(Target)->addPassesToEmitFile(*PM, OS, FileType, false);
+#else
+ formatted_raw_ostream FOS(OS);
unwrap(Target)->addPassesToEmitFile(*PM, FOS, FileType, false);
+#endif
PM->run(*unwrap(M));
+
+ // Apparently `addPassesToEmitFile` adds an pointer to our on-the-stack output
+ // stream (OS), so the only real safe place to delete this is here? Don't we
+ // wish this was written in Rust?
+ delete PM;
return true;
}
F->addAttributes(index, AttributeSet::get(F->getContext(), index, B));
}
+extern "C" void LLVMAddFunctionAttrStringValue(LLVMValueRef Fn, unsigned index,
+ const char *Name,
+ const char *Value) {
+ Function *F = unwrap<Function>(Fn);
+ AttrBuilder B;
+ B.addAttribute(Name, Value);
+ F->addAttributes(index, AttributeSet::get(F->getContext(), index, B));
+}
+
extern "C" void LLVMRemoveFunctionAttrString(LLVMValueRef fn, unsigned index, const char *Name) {
Function *f = unwrap<Function>(fn);
LLVMContext &C = f->getContext();
typedef LLVMValueRef LLVMMetadataRef;
#endif
+template<typename DIT>
+DIT* unwrapDIptr(LLVMMetadataRef ref) {
+ return (DIT*) (ref ? unwrap<MDNode>(ref) : NULL);
+}
+
+#if LLVM_VERSION_MINOR <= 6
template<typename DIT>
DIT unwrapDI(LLVMMetadataRef ref) {
return DIT(ref ? unwrap<MDNode>(ref) : NULL);
}
+#else
+#define DIDescriptor DIScope
+#define DIArray DINodeArray
+#define unwrapDI unwrapDIptr
+#endif
-extern "C" const uint32_t LLVMRustDebugMetadataVersion = DEBUG_METADATA_VERSION;
+#if LLVM_VERSION_MINOR <= 5
+#define DISubroutineType DICompositeType
+#endif
+
+extern "C" uint32_t LLVMRustDebugMetadataVersion() {
+ return DEBUG_METADATA_VERSION;
+}
+
+extern "C" uint32_t LLVMVersionMinor() {
+ return LLVM_VERSION_MINOR;
+}
+
+extern "C" uint32_t LLVMVersionMajor() {
+ return LLVM_VERSION_MAJOR;
+}
extern "C" void LLVMRustAddModuleFlag(LLVMModuleRef M,
const char *name,
LLVMMetadataRef ParameterTypes) {
return wrap(Builder->createSubroutineType(
unwrapDI<DIFile>(File),
-#if LLVM_VERSION_MINOR >= 6
+#if LLVM_VERSION_MINOR >= 7
+ DITypeRefArray(unwrap<MDTuple>(ParameterTypes))));
+#elif LLVM_VERSION_MINOR >= 6
unwrapDI<DITypeArray>(ParameterTypes)));
#else
unwrapDI<DIArray>(ParameterTypes)));
return wrap(Builder->createFunction(
unwrapDI<DIScope>(Scope), Name, LinkageName,
unwrapDI<DIFile>(File), LineNo,
- unwrapDI<DICompositeType>(Ty), isLocalToUnit, isDefinition, ScopeLine,
+ unwrapDI<DISubroutineType>(Ty), isLocalToUnit, isDefinition, ScopeLine,
Flags, isOptimized,
unwrap<Function>(Fn),
- unwrapDI<MDNode*>(TParam),
- unwrapDI<MDNode*>(Decl)));
+ unwrapDIptr<MDNode>(TParam),
+ unwrapDIptr<MDNode>(Decl)));
}
extern "C" LLVMMetadataRef LLVMDIBuilderCreateBasicType(
AlignInBits,
Flags,
unwrapDI<DIType>(DerivedFrom),
+#if LLVM_VERSION_MINOR >= 7
+ DINodeArray(unwrapDI<MDTuple>(Elements)),
+#else
unwrapDI<DIArray>(Elements),
+#endif
RunTimeLang,
unwrapDI<DIType>(VTableHolder),
UniqueId
unwrapDI<DIType>(Ty),
isLocalToUnit,
cast<Constant>(unwrap(Val)),
- unwrapDI<MDNode*>(Decl)));
+ unwrapDIptr<MDNode>(Decl)));
}
extern "C" LLVMMetadataRef LLVMDIBuilderCreateVariable(
LLVMMetadataRef Subscripts) {
return wrap(Builder->createArrayType(Size, AlignInBits,
unwrapDI<DIType>(Ty),
- unwrapDI<DIArray>(Subscripts)));
+#if LLVM_VERSION_MINOR >= 7
+ DINodeArray(unwrapDI<MDTuple>(Subscripts))
+#else
+ unwrapDI<DIArray>(Subscripts)
+#endif
+ ));
}
extern "C" LLVMMetadataRef LLVMDIBuilderCreateVectorType(
LLVMMetadataRef Subscripts) {
return wrap(Builder->createVectorType(Size, AlignInBits,
unwrapDI<DIType>(Ty),
- unwrapDI<DIArray>(Subscripts)));
+#if LLVM_VERSION_MINOR >= 7
+ DINodeArray(unwrapDI<MDTuple>(Subscripts))
+#else
+ unwrapDI<DIArray>(Subscripts)
+#endif
+ ));
}
extern "C" LLVMMetadataRef LLVMDIBuilderGetOrCreateSubrange(
DIBuilderRef Builder,
LLVMMetadataRef* Ptr,
unsigned Count) {
+#if LLVM_VERSION_MINOR >= 7
+ Metadata **DataValue = unwrap(Ptr);
+ return wrap(Builder->getOrCreateArray(
+ ArrayRef<Metadata*>(DataValue, Count)).get());
+#else
return wrap(Builder->getOrCreateArray(
#if LLVM_VERSION_MINOR >= 6
ArrayRef<Metadata*>(unwrap(Ptr), Count)));
#else
ArrayRef<Value*>(reinterpret_cast<Value**>(Ptr), Count)));
#endif
+#endif
}
extern "C" LLVMValueRef LLVMDIBuilderInsertDeclareAtEnd(
LLVMMetadataRef VarInfo,
int64_t* AddrOps,
unsigned AddrOpsCount,
+ LLVMValueRef DL,
LLVMBasicBlockRef InsertAtEnd) {
-#if LLVM_VERSION_MINOR >= 6
- DIExpression Expr;
- if (AddrOpsCount == 0) {
- Expr = Builder->createExpression();
- } else {
- llvm::ArrayRef<int64_t> addr_ops(AddrOps, AddrOpsCount);
- Expr = Builder->createExpression(addr_ops);
- }
-#endif
return wrap(Builder->insertDeclare(
unwrap(Val),
+#if LLVM_VERSION_MINOR >= 7
+ unwrap<DILocalVariable>(VarInfo),
+#else
unwrapDI<DIVariable>(VarInfo),
+#endif
#if LLVM_VERSION_MINOR >= 6
- Expr,
+ Builder->createExpression(
+ llvm::ArrayRef<int64_t>(AddrOps, AddrOpsCount)),
+#endif
+#if LLVM_VERSION_MINOR >= 7
+ DebugLoc(cast<MDNode>(unwrap<MetadataAsValue>(DL)->getMetadata())),
#endif
unwrap(InsertAtEnd)));
}
LLVMMetadataRef VarInfo,
int64_t* AddrOps,
unsigned AddrOpsCount,
+ LLVMValueRef DL,
LLVMValueRef InsertBefore) {
#if LLVM_VERSION_MINOR >= 6
- DIExpression Expr;
- if (AddrOpsCount == 0) {
- Expr = Builder->createExpression();
- } else {
- llvm::ArrayRef<int64_t> addr_ops(AddrOps, AddrOpsCount);
- Expr = Builder->createExpression(addr_ops);
- }
#endif
return wrap(Builder->insertDeclare(
unwrap(Val),
+#if LLVM_VERSION_MINOR >= 7
+ unwrap<DILocalVariable>(VarInfo),
+#else
unwrapDI<DIVariable>(VarInfo),
+#endif
#if LLVM_VERSION_MINOR >= 6
- Expr,
+ Builder->createExpression(
+ llvm::ArrayRef<int64_t>(AddrOps, AddrOpsCount)),
+#endif
+#if LLVM_VERSION_MINOR >= 7
+ DebugLoc(cast<MDNode>(unwrap<MetadataAsValue>(DL)->getMetadata())),
#endif
unwrap<Instruction>(InsertBefore)));
}
LineNumber,
SizeInBits,
AlignInBits,
+#if LLVM_VERSION_MINOR >= 7
+ DINodeArray(unwrapDI<MDTuple>(Elements)),
+#else
unwrapDI<DIArray>(Elements),
+#endif
unwrapDI<DIType>(ClassType)));
}
SizeInBits,
AlignInBits,
Flags,
+#if LLVM_VERSION_MINOR >= 7
+ DINodeArray(unwrapDI<MDTuple>(Elements)),
+#else
unwrapDI<DIArray>(Elements),
+#endif
RunTimeLang,
UniqueId
));
return wrap(Builder->createTemplateTypeParameter(
unwrapDI<DIDescriptor>(Scope),
Name,
- unwrapDI<DIType>(Ty),
+ unwrapDI<DIType>(Ty)
+#if LLVM_VERSION_MINOR <= 6
+ ,
unwrapDI<MDNode*>(File),
LineNo,
- ColumnNo));
+ ColumnNo
+#endif
+ ));
}
extern "C" int64_t LLVMDIBuilderCreateOpDeref()
LLVMMetadataRef CompositeType,
LLVMMetadataRef TypeArray)
{
-#if LLVM_VERSION_MINOR >= 6
+#if LLVM_VERSION_MINOR >= 7
+ DICompositeType *tmp = unwrapDI<DICompositeType>(CompositeType);
+ Builder->replaceArrays(tmp, DINodeArray(unwrap<MDTuple>(TypeArray)));
+#elif LLVM_VERSION_MINOR >= 6
DICompositeType tmp = unwrapDI<DICompositeType>(CompositeType);
Builder->replaceArrays(tmp, unwrapDI<DIArray>(TypeArray));
#else
DebugLoc debug_loc = DebugLoc::get(Line,
Column,
- unwrapDI<MDNode*>(Scope),
- unwrapDI<MDNode*>(InlinedAt));
+ unwrapDIptr<MDNode>(Scope),
+ unwrapDIptr<MDNode>(InlinedAt));
#if LLVM_VERSION_MINOR >= 6
- return wrap(MetadataAsValue::get(context, debug_loc.getAsMDNode(context)));
+ return wrap(MetadataAsValue::get(context, debug_loc.getAsMDNode(
+#if LLVM_VERSION_MINOR <= 6
+ context
+#endif
+ )));
#else
return wrap(debug_loc.getAsMDNode(context));
#endif
Module *Dst = unwrap(dst);
#if LLVM_VERSION_MINOR >= 6
std::unique_ptr<MemoryBuffer> buf = MemoryBuffer::getMemBufferCopy(StringRef(bc, len));
+#if LLVM_VERSION_MINOR >= 7
+ ErrorOr<std::unique_ptr<Module>> Src =
+ llvm::getLazyBitcodeModule(std::move(buf), Dst->getContext());
+#else
ErrorOr<Module *> Src = llvm::getLazyBitcodeModule(std::move(buf), Dst->getContext());
+#endif
#else
MemoryBuffer* buf = MemoryBuffer::getMemBufferCopy(StringRef(bc, len));
ErrorOr<Module *> Src = llvm::getLazyBitcodeModule(buf, Dst->getContext());
#if LLVM_VERSION_MINOR >= 6
raw_string_ostream Stream(Err);
DiagnosticPrinterRawOStream DP(Stream);
+#if LLVM_VERSION_MINOR >= 7
+ if (Linker::LinkModules(Dst, Src->get(), [&](const DiagnosticInfo &DI) { DI.print(DP); })) {
+#else
if (Linker::LinkModules(Dst, *Src, [&](const DiagnosticInfo &DI) { DI.print(DP); })) {
+#endif
#else
if (Linker::LinkModules(Dst, *Src, Linker::DestroySource, &Err)) {
#endif
LLVMRustArchiveIteratorCurrent(RustArchiveIterator *rai) {
if (rai->cur == rai->end)
return NULL;
+#if LLVM_VERSION_MINOR >= 6
const Archive::Child &ret = *rai->cur;
return &ret;
+#else
+ return rai->cur.operator->();
+#endif
}
extern "C" void
}
extern "C" void
-LLVMRustSetDLLExportStorageClass(LLVMValueRef Value) {
+LLVMRustSetDLLStorageClass(LLVMValueRef Value,
+ GlobalValue::DLLStorageClassTypes Class) {
GlobalValue *V = unwrap<GlobalValue>(Value);
- V->setDLLStorageClass(GlobalValue::DLLExportStorageClass);
+ V->setDLLStorageClass(Class);
}
// Note that the two following functions look quite similar to the
RustStringRef str)
{
raw_rust_string_ostream os(str);
+#if LLVM_VERSION_MINOR >= 7
+ unwrap(dl)->print(os);
+#else
unwrap(dl)->print(*unwrap(C), os);
+#endif
}
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(SMDiagnostic, LLVMSMDiagnosticRef)
# If this file is modified, then llvm will be forcibly cleaned and then rebuilt.
# The actual contents of this file do not matter, but to trigger a change on the
# build bots then the contents should be changed so git updates the mtime.
-2015-03-04
+2015-06-16
#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
-#include "llvm/PassManager.h"
#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Analysis/Passes.h"
#include "llvm-c/ExecutionEngine.h"
#include "llvm-c/Object.h"
+#if LLVM_VERSION_MINOR >= 7
+#include "llvm/IR/LegacyPassManager.h"
+#else
+#include "llvm/PassManager.h"
+#endif
+
#include "llvm/IR/IRPrintingPasses.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/DIBuilder.h"
#include "llvm/Linker/Linker.h"
-// Used by RustMCJITMemoryManager::getPointerToNamedFunction()
-// to get around glibc issues. See the function for more information.
-#ifdef __linux__
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#endif
-
void LLVMRustSetLastError(const char*);
typedef struct OpaqueRustString *RustStringRef;
+S 2015-05-24 ba0e1cd
+ bitrig-x86_64 2a710e16e3e3ef3760df1f724d66b3af34c1ef3f
+ freebsd-x86_64 370db40613f5c08563ed7e38357826dd42d4e0f8
+ linux-i386 a6f22e481eabf098cc65bda97bf7e434a1fcc20b
+ linux-x86_64 5fd8698fdfe953e6c4d86cf4fa1d5f3a0053248c
+ macos-i386 9a273324a6b63a40f67a553029c0a9fb692ffd1f
+ macos-x86_64 e5b12cb7c179fc98fa905a3c84803645d946a6ae
+ winnt-i386 18d8d76c5380ee2247dd534bfb2c4ed1b3d83461
+ winnt-x86_64 ef27ce42af4941be24a2f6097d969ffc845a31ee
+
S 2015-04-27 857ef6e
bitrig-x86_64 d28e2a5f8b478e69720703e751774f5e728a8edd
freebsd-x86_64 18925db56f6298cc190d1f41615ab5871de1dda0
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// force-host
+
+#![feature(plugin_registrar)]
+#![feature(rustc_private)]
+
+extern crate syntax;
+
+extern crate rustc;
+
+use syntax::feature_gate::AttributeType;
+use rustc::plugin::Registry;
+
+
+
+#[plugin_registrar]
+pub fn plugin_registrar(reg: &mut Registry) {
+ reg.register_attribute("foo".to_owned(), AttributeType::Normal);
+ reg.register_attribute("bar".to_owned(), AttributeType::CrateLevel);
+ reg.register_attribute("baz".to_owned(), AttributeType::Whitelisted);
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Crate that exports a const fn. Used for testing cross-crate.
+
+#![crate_type="rlib"]
+#![feature(const_fn)]
+
+pub const fn foo() -> usize { 22 } //~ ERROR const fn is unstable
fn expand(cx: &mut ExtCtxt,
span: Span,
mitem: &ast::MetaItem,
- item: Annotatable,
+ item: &Annotatable,
push: &mut FnMut(Annotatable)) {
let trait_def = TraitDef {
span: span,
args: vec![],
ret_ty: Literal(Path::new_local("isize")),
attributes: vec![],
+ is_unsafe: false,
combine_substructure: combine_substructure(box |cx, span, substr| {
let zero = cx.expr_isize(span, 0);
cs_fold(false,
],
};
- trait_def.expand(cx, mitem, &item, push)
+ trait_def.expand(cx, mitem, item, push)
}
fn expand(cx: &mut ExtCtxt,
span: Span,
mitem: &ast::MetaItem,
- item: Annotatable,
+ item: &Annotatable,
push: &mut FnMut(Annotatable)) {
let trait_def = TraitDef {
span: span,
args: vec![],
ret_ty: Literal(Path::new_local("isize")),
attributes: vec![],
+ is_unsafe: false,
combine_substructure: combine_substructure(Box::new(totalsum_substructure)),
},
],
};
- trait_def.expand(cx, mitem, &item, push)
+ trait_def.expand(cx, mitem, item, push)
}
// Mostly copied from syntax::ext::deriving::hash
#[inline(never)]
#[cfg(target_arch = "x86_64")]
pub extern "win64" fn foo(a: isize, b: isize, c: isize, d: isize) {
- assert!(a == 1);
- assert!(b == 2);
- assert!(c == 3);
- assert!(d == 4);
+ assert_eq!(a, 1);
+ assert_eq!(b, 2);
+ assert_eq!(c, 3);
+ assert_eq!(d, 4);
println!("a: {}, b: {}, c: {}, d: {}",
a, b, c, d)
#[inline(never)]
#[cfg(any(target_arch = "x86", target_arch = "arm", target_arch = "aarch64"))]
pub extern fn foo(a: isize, b: isize, c: isize, d: isize) {
- assert!(a == 1);
- assert!(b == 2);
- assert!(c == 3);
- assert!(d == 4);
+ assert_eq!(a, 1);
+ assert_eq!(b, 2);
+ assert_eq!(c, 3);
+ assert_eq!(d, 4);
println!("a: {}, b: {}, c: {}, d: {}",
a, b, c, d)
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(const_fn)]
+
use std::sync::atomic;
pub const C1: usize = 1;
-pub const C2: atomic::AtomicUsize = atomic::ATOMIC_USIZE_INIT;
+pub const C2: atomic::AtomicUsize = atomic::AtomicUsize::new(0);
pub const C3: fn() = foo;
pub const C4: usize = C1 * C1 + C1 / C1;
pub const C5: &'static usize = &C4;
pub static S1: usize = 3;
-pub static S2: atomic::AtomicUsize = atomic::ATOMIC_USIZE_INIT;
+pub static S2: atomic::AtomicUsize = atomic::AtomicUsize::new(0);
fn foo() {}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// no-prefer-dynamic
+
+#![crate_type = "rlib"]
+#![crate_name = "foo"]
+
+pub fn foo() -> i32 { 0 }
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// no-prefer-dynamic
+
+#![crate_type = "rlib"]
+#![crate_name = "foo"]
+
+pub fn foo() -> i32 { 1 }
impl Baz {
pub fn baz(&self) {}
+ pub fn static_baz() {}
}
impl Deref for Bar {
// Skipping ty_bot
- // Tests ty_bool
+ // Tests TyBool
pub type FooBool = bool;
- // Tests ty_char
+ // Tests TyChar
pub type FooChar = char;
- // Tests ty_int (does not test all variants of IntTy)
+ // Tests TyInt (does not test all variants of IntTy)
pub type FooInt = isize;
- // Tests ty_uint (does not test all variants of UintTy)
+ // Tests TyUint (does not test all variants of UintTy)
pub type FooUint = usize;
- // Tests ty_float (does not test all variants of FloatTy)
+ // Tests TyFloat (does not test all variants of FloatTy)
pub type FooFloat = f64;
- // For ty_str, what kind of string should I use? &'static str? String? Raw str?
+ // For TyStr, what kind of string should I use? &'static str? String? Raw str?
- // Tests ty_enum
+ // Tests TyEnum
pub enum FooEnum {
VarA(usize),
VarB(usize, usize)
}
- // Tests ty_uniq (of u8)
+ // Tests TyBox (of u8)
pub type FooUniq = Box<u8>;
- // As with ty_str, what type should be used for ty_vec?
+ // As with TyStr, what type should be used for TyArray?
- // Tests ty_ptr
+ // Tests TyRawPtr
pub type FooPtr = *const u8;
- // Skipping ty_rptr
+ // Skipping TyRef
- // Skipping ty_bare_fn (how do you get a bare function type, rather than proc or closure?)
+ // Skipping TyBareFn (how do you get a bare function type, rather than proc or closure?)
- // Tests ty_trait
+ // Tests TyTrait
pub trait FooTrait {
fn foo_method(&self) -> usize;
fn foo_static_method() -> usize;
}
- // Tests ty_struct
+ // Tests TyStruct
pub struct FooStruct {
pub pub_foo_field: usize,
foo_field: usize
}
- // Tests ty_tup
+ // Tests TyTuple
pub type FooTuple = (u8, i8, bool);
// Skipping ty_param
// Skipping ty_self
- // Skipping ty_infer
+ // Skipping TyInfer
- // Skipping ty_err
+ // Skipping TyError
}
#![feature(no_std)]
#![no_std]
#![feature(lang_items)]
+#![feature(associated_type_defaults)]
#[lang="sized"]
pub trait Sized { }
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_type = "rlib"]
+
+// Helper for testing that we get suitable warnings when lifetime
+// bound change will cause breakage.
+
+pub fn just_ref(x: &Fn()) {
+}
+
+pub fn ref_obj(x: &Box<Fn()>) {
+ // this will change to &Box<Fn()+'static>...
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(std_misc)]
+#![feature(dynamic_lib)]
// We're testing linkage visibility; the compiler warns us, but we want to
// do the runtime check that these functions aren't exported.
// Normally, we would name a pass that was registered through
// C++ static object constructors in the same .so file as the
// plugin registrar.
- reg.register_llvm_pass("inline");
+ reg.register_llvm_pass("gvn");
}
fn expand_duplicate(cx: &mut ExtCtxt,
sp: Span,
mi: &MetaItem,
- it: Annotatable,
+ it: &Annotatable,
push: &mut FnMut(Annotatable))
{
let copy_name = match mi.node {
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(associated_type_defaults)]
+
+pub trait Foo {
+ type Input = usize;
+ fn bar(&self, _: Self::Input) {}
+}
+
+impl Foo for () {}
// ignore-pretty very bad with line comments
#![feature(unboxed_closures, rand, std_misc, collections, duration, duration_span)]
+#![feature(bitset)]
extern crate collections;
extern crate rand;
// Microbenchmarks for various functions in std and extra
-#![feature(rand, collections, std_misc, duration, duration_span)]
+#![feature(rand, vec_push_all, duration, duration_span)]
use std::iter::repeat;
use std::mem::swap;
while i < 1500 {
let rv = repeat(i).take(r.gen_range(0, i + 1)).collect::<Vec<_>>();
if r.gen() {
- v.extend(rv.into_iter());
+ v.extend(rv);
} else {
let mut rv = rv.clone();
rv.push_all(&v);
// no-pretty-expanded FIXME #15189
-#![feature(duration, duration_span, std_misc)]
+#![feature(duration, duration_span, future)]
use std::env;
use std::sync::{Arc, Future, Mutex, Condvar};
let d = idx / self.fact[i] as i32;
self.cnt[i] = d;
idx %= self.fact[i] as i32;
- for (place, val) in pp.iter_mut().zip(self.perm.p[..i+1].iter()) {
+ for (place, val) in pp.iter_mut().zip(&self.perm.p[..i+1]) {
*place = (*val) as u8
}
let mut buf = repeat(0).take(alu_len + LINE_LEN).collect::<Vec<_>>();
let alu: &[u8] = self.alu.as_bytes();
- for (slot, val) in buf.iter_mut().zip(alu.iter()) {
+ for (slot, val) in buf.iter_mut().zip(alu) {
*slot = *val;
}
let buf_len = buf.len();
- for (slot, val) in buf[alu_len..buf_len].iter_mut().zip(alu[..LINE_LEN].iter()) {
+ for (slot, val) in buf[alu_len..buf_len].iter_mut().zip(&alu[..LINE_LEN]) {
*slot = *val;
}
Some(channel::<String>())
}).collect::<Vec<_>>();
let mut from_child = Vec::new();
- let to_child = sizes.iter().zip(streams.iter_mut()).map(|(sz, stream_ref)| {
+ let to_child = sizes.iter().zip(&mut streams).map(|(sz, stream_ref)| {
let sz = *sz;
let stream = replace(stream_ref, None);
let (to_parent_, from_child_) = stream.unwrap();
// ignore-android: FIXME(#10393) hangs without output
-#![feature(box_syntax, std_misc, collections)]
+#![feature(box_syntax, owned_ascii_ext, vec_push_all)]
use std::ascii::OwnedAsciiExt;
use std::env;
for (i, freq) in nb_freqs {
print_frequencies(&freq.join().unwrap(), i);
}
- for (&occ, freq) in OCCURRENCES.iter().zip(occ_freqs.into_iter()) {
+ for (&occ, freq) in OCCURRENCES.iter().zip(occ_freqs) {
print_occurrences(&mut freq.join().unwrap(), occ);
}
}
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
-#![feature(simd, core)]
+#![feature(core_simd, core)]
// ignore-pretty very bad with line comments
const WORKERS: usize = 16;
fn mandelbrot<W: Write>(w: usize, mut out: W) -> io::Result<()> {
- assert!(WORKERS % 2 == 0);
+ assert_eq!(WORKERS % 2, 0);
// Ensure w and h are multiples of 8.
let w = (w + 7) / 8 * 8;
let v_consts = f64x2(1.5, 1.0);
// A lot of this code assumes this (so do other lang benchmarks)
- assert!(w == h);
+ assert_eq!(w, h);
let mut precalc_r = Vec::with_capacity(w);
let mut precalc_i = Vec::with_capacity(h);
for res in precalc_futures {
let (rs, is) = res.join().unwrap();
- precalc_r.extend(rs.into_iter());
- precalc_i.extend(is.into_iter());
+ precalc_r.extend(rs);
+ precalc_i.extend(is);
}
assert_eq!(precalc_r.len(), w);
// no-pretty-expanded FIXME #15189
-#![feature(core)]
+#![feature(iter_cmp)]
use std::iter::repeat;
use std::sync::Arc;
// launching the search in parallel on every masks at minimum
// coordinate (0,0)
- for m in (*masks)[0].iter().flat_map(|masks_pos| masks_pos.iter()) {
+ for m in (*masks)[0].iter().flat_map(|masks_pos| masks_pos) {
let masks = masks.clone();
let tx = tx.clone();
let m = *m;
let mut px = 0.0;
let mut py = 0.0;
let mut pz = 0.0;
- for bi in &*bodies {
+ for bi in bodies.iter() {
px += bi.vx * bi.mass;
py += bi.vy * bi.mass;
pz += bi.vz * bi.mass;
// no-pretty-expanded FIXME #15189
#![allow(non_snake_case)]
-#![feature(unboxed_closures, core, os, scoped)]
+#![feature(unboxed_closures, iter_arith, core_simd, scoped)]
use std::iter::repeat;
use std::thread;
-use std::mem;
-use std::os;
use std::env;
-use std::raw::Repr;
use std::simd::f64x2;
fn main() {
}
fn dot(v: &[f64], u: &[f64]) -> f64 {
- v.iter().zip(u.iter()).map(|(a, b)| *a * *b).sum()
+ v.iter().zip(u).map(|(a, b)| *a * *b).sum()
}
// Microbenchmark for the smallintmap library
-#![feature(collections, duration, duration_span)]
+#![feature(vecmap, duration, duration_span)]
use std::collections::VecMap;
use std::env;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(box_syntax, duration, duration_span, collections)]
+#![feature(box_syntax, duration, duration_span, vec_push_all)]
use std::env;
use std::thread;
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -C no-prepopulate-passes
+
+static X: i32 = 5;
+
+// CHECK-LABEL: @raw_ptr_to_raw_ptr_noop
+// CHECK-NOT: alloca
+#[no_mangle]
+pub fn raw_ptr_to_raw_ptr_noop() -> *const i32{
+ &X as *const i32
+}
+
+// CHECK-LABEL: @reference_to_raw_ptr_noop
+// CHECK-NOT: alloca
+#[no_mangle]
+pub fn reference_to_raw_ptr_noop() -> *const i32 {
+ &X
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -C no-prepopulate-passes
+
+#![feature(allocator)]
+
+pub struct S {
+ _field: [i64; 4],
+}
+
+pub struct UnsafeInner {
+ _field: std::cell::UnsafeCell<i16>,
+}
+
+// CHECK: zeroext i1 @boolean(i1 zeroext)
+#[no_mangle]
+pub fn boolean(x: bool) -> bool {
+ x
+}
+
+// CHECK: @readonly_borrow(i32* noalias readonly dereferenceable(4))
+// FIXME #25759 This should also have `nocapture`
+#[no_mangle]
+pub fn readonly_borrow(_: &i32) {
+}
+
+// CHECK: @static_borrow(i32* noalias readonly dereferenceable(4))
+// static borrow may be captured
+#[no_mangle]
+pub fn static_borrow(_: &'static i32) {
+}
+
+// CHECK: @named_borrow(i32* noalias readonly dereferenceable(4))
+// borrow with named lifetime may be captured
+#[no_mangle]
+pub fn named_borrow<'r>(_: &'r i32) {
+}
+
+// CHECK: @unsafe_borrow(%UnsafeInner* dereferenceable(2))
+// unsafe interior means this isn't actually readonly and there may be aliases ...
+#[no_mangle]
+pub fn unsafe_borrow(_: &UnsafeInner) {
+}
+
+// CHECK: @mutable_unsafe_borrow(%UnsafeInner* noalias dereferenceable(2))
+// ... unless this is a mutable borrow, those never alias
+#[no_mangle]
+pub fn mutable_unsafe_borrow(_: &mut UnsafeInner) {
+}
+
+// CHECK: @mutable_borrow(i32* noalias dereferenceable(4))
+// FIXME #25759 This should also have `nocapture`
+#[no_mangle]
+pub fn mutable_borrow(_: &mut i32) {
+}
+
+// CHECK: @indirect_struct(%S* noalias nocapture dereferenceable(32))
+#[no_mangle]
+pub fn indirect_struct(_: S) {
+}
+
+// CHECK: @borrowed_struct(%S* noalias readonly dereferenceable(32))
+// FIXME #25759 This should also have `nocapture`
+#[no_mangle]
+pub fn borrowed_struct(_: &S) {
+}
+
+// CHECK: noalias dereferenceable(4) i32* @_box(i32* noalias dereferenceable(4))
+#[no_mangle]
+pub fn _box(x: Box<i32>) -> Box<i32> {
+ x
+}
+
+// CHECK: @struct_return(%S* noalias nocapture sret dereferenceable(32))
+#[no_mangle]
+pub fn struct_return() -> S {
+ S {
+ _field: [0, 0, 0, 0]
+ }
+}
+
+// Hack to get the correct size for the length part in slices
+// CHECK: @helper([[USIZE:i[0-9]+]])
+#[no_mangle]
+fn helper(_: usize) {
+}
+
+// CHECK: @slice(i8* noalias nonnull readonly, [[USIZE]])
+// FIXME #25759 This should also have `nocapture`
+#[no_mangle]
+fn slice(_: &[u8]) {
+}
+
+// CHECK: @mutable_slice(i8* noalias nonnull, [[USIZE]])
+// FIXME #25759 This should also have `nocapture`
+#[no_mangle]
+fn mutable_slice(_: &mut [u8]) {
+}
+
+// CHECK: @unsafe_slice(%UnsafeInner* nonnull, [[USIZE]])
+// unsafe interior means this isn't actually readonly and there may be aliases ...
+#[no_mangle]
+pub fn unsafe_slice(_: &[UnsafeInner]) {
+}
+
+// CHECK: @str(i8* noalias nonnull readonly, [[USIZE]])
+// FIXME #25759 This should also have `nocapture`
+#[no_mangle]
+fn str(_: &[u8]) {
+}
+
+// CHECK: @trait_borrow(i8* nonnull, void (i8*)** nonnull)
+// FIXME #25759 This should also have `nocapture`
+#[no_mangle]
+fn trait_borrow(_: &Drop) {
+}
+
+// CHECK: @trait_box(i8* noalias nonnull, void (i8*)** nonnull)
+#[no_mangle]
+fn trait_box(_: Box<Drop>) {
+}
+
+// CHECK: { i16*, [[USIZE]] } @return_slice(i16* noalias nonnull readonly, [[USIZE]])
+#[no_mangle]
+fn return_slice(x: &[u16]) -> &[u16] {
+ x
+}
+
+// CHECK: noalias i8* @allocator()
+#[no_mangle]
+#[allocator]
+pub fn allocator() -> *const i8 {
+ std::ptr::null()
+}
+++ /dev/null
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#include <stdlib.h>
-#include <assert.h>
-
-struct slice {
- int const *p;
- size_t len;
-};
-
-extern "C"
-size_t test(slice s) {
- size_t y = 0;
- for (int i = 0; i < s.len; ++i) {
- assert(i < s.len);
- y += s.p[i];
- }
- return y;
-}
+++ /dev/null
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#[no_mangle]
-pub fn test(x: &[isize]) -> isize {
- let mut y = 0;
- let mut i = 0;
- while (i < x.len()) {
- y += x[i];
- i += 1;
- }
- y
-}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -C no-prepopulate-passes
+
+pub struct Bytes {
+ a: u8,
+ b: u8,
+ c: u8,
+ d: u8,
+}
+
+// CHECK-LABEL: @borrow
+#[no_mangle]
+pub fn borrow(x: &i32) -> &i32 {
+// CHECK: load i32*, i32** %x{{.*}}, !nonnull
+ x
+}
+
+// CHECK-LABEL: @_box
+#[no_mangle]
+pub fn _box(x: Box<i32>) -> i32 {
+// CHECK: load i32*, i32** %x{{.*}}, !nonnull
+ *x
+}
+
+// CHECK-LABEL: small_array_alignment
+// The array is loaded as i32, but its alignment is lower, go with 1 byte to avoid target
+// dependent alignment
+#[no_mangle]
+pub fn small_array_alignment(x: [i8; 4]) -> [i8; 4] {
+// CHECK: [[VAR:%[0-9]+]] = load i32, i32* %{{.*}}, align 1
+// CHECK: ret i32 [[VAR]]
+ x
+}
+
+// CHECK-LABEL: small_struct_alignment
+// The struct is loaded as i32, but its alignment is lower, go with 1 byte to avoid target
+// dependent alignment
+#[no_mangle]
+pub fn small_struct_alignment(x: Bytes) -> Bytes {
+// CHECK: [[VAR:%[0-9]+]] = load i32, i32* %{{.*}}, align 1
+// CHECK: ret i32 [[VAR]]
+ x
+}
+++ /dev/null
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#include <stdlib.h>
-
-size_t foo(size_t x) {
- return x * x;
-}
-
-extern "C"
-void test() {
- size_t x = foo(10);
-}
+++ /dev/null
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-fn foo(x: isize) -> isize {
- x * x
-}
-
-#[no_mangle]
-pub fn test() {
- let _x = foo(10);
-}
+++ /dev/null
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-extern "C"
-int test() {
- return 5;
-}
+++ /dev/null
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#[no_mangle]
-pub fn test() -> isize {
- 5
-}
+++ /dev/null
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#include <stdlib.h>
-
-extern "C"
-size_t test(size_t x, size_t y) {
- switch (x) {
- case 1: return y;
- case 2: return y*2;
- case 4: return y*3;
- default: return 11;
- }
-}
+++ /dev/null
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#[no_mangle]
-pub fn test(x: isize, y: isize) -> isize {
- match x {
- 1 => y,
- 2 => y*2,
- 4 => y*3,
- _ => 11
- }
-}
+++ /dev/null
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#include <stddef.h>
-
-struct slice {
- char const *p;
- size_t len;
-};
-
-extern "C"
-void test() {
- struct slice s = { .p = "hello",
- .len = 5 };
-}
+++ /dev/null
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#[no_mangle]
-pub fn test() {
- let _x = "hello";
-}
+++ /dev/null
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#include <stdlib.h>
-
-struct Struct {
- size_t field;
- size_t method(size_t x) {
- return this->field + x;
- }
-};
-
-extern "C"
-size_t test(Struct &a,
- Struct &b,
- Struct &c,
- Struct &d,
- Struct &e) {
- return a.method(b.method(c.method(d.method(e.method(1)))));
-}
+++ /dev/null
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-pub struct Struct {
- field: isize
-}
-
-impl Struct {
- fn method(&self, x: isize) -> isize {
- self.field + x
- }
-}
-
-#[no_mangle]
-pub fn test(a: &Struct,
- b: &Struct,
- c: &Struct,
- d: &Struct,
- e: &Struct) -> isize {
- a.method(b.method(c.method(d.method(e.method(1)))))
-}
+++ /dev/null
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#include <stdlib.h>
-
-struct Struct {
- size_t field;
- size_t method() {
- return this->field;
- }
-};
-
-extern "C"
-size_t test(Struct &s) {
- return s.method();
-}
+++ /dev/null
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-pub struct Struct {
- field: isize
-}
-
-impl Struct {
- fn method(&self) -> isize {
- self.field
- }
-}
-
-#[no_mangle]
-pub fn test(s: &Struct) -> isize {
- s.method()
-}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -C no-prepopulate-passes
+
+pub struct Bytes {
+ a: u8,
+ b: u8,
+ c: u8,
+ d: u8,
+}
+
+// CHECK-LABEL: small_array_alignment
+// The array is stored as i32, but its alignment is lower, go with 1 byte to avoid target
+// dependent alignment
+#[no_mangle]
+pub fn small_array_alignment(x: &mut [i8; 4]) {
+// CHECK: [[VAR:%[0-9]+]] = load [4 x i8]*, [4 x i8]** %x
+// CHECK: [[VAR2:%[0-9]+]] = bitcast [4 x i8]* [[VAR]] to i32*
+// CHECK: store i32 %{{.*}}, i32* [[VAR2]], align 1
+ *x = [0; 4];
+}
+
+// CHECK-LABEL: small_struct_alignment
+// The struct is stored as i32, but its alignment is lower, go with 1 byte to avoid target
+// dependent alignment
+#[no_mangle]
+pub fn small_struct_alignment(x: &mut Bytes) {
+// CHECK: [[VAR:%[0-9]+]] = load %Bytes*, %Bytes** %x
+// CHECK: [[VAR2:%[0-9]+]] = bitcast %Bytes* [[VAR]] to i32*
+// CHECK: store i32 %{{.*}}, i32* [[VAR2]], align 1
+ *x = Bytes {
+ a: 0,
+ b: 0,
+ c: 0,
+ d: 0,
+ };
+}
+++ /dev/null
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#include <stdlib.h>
-
-struct Stuff {
- size_t a;
- double b;
-};
-
-struct Struct {
- virtual Stuff method() = 0;
-};
-
-extern "C"
-size_t test(Struct &s) {
- return s.method().a;
-}
+++ /dev/null
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-pub struct Stuff {
- a: isize,
- b: f64
-}
-
-pub trait Trait {
- fn method(&self) -> Stuff;
-}
-
-#[no_mangle]
-pub fn test(t: &Trait) -> isize {
- t.method().a
-}
+++ /dev/null
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#include <stdlib.h>
-
-struct Struct {
- virtual size_t method() = 0;
-};
-
-extern "C"
-size_t test(Struct &s) {
- return s.method();
-}
+++ /dev/null
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-pub trait Trait {
- fn method(&self) -> isize;
-}
-
-#[no_mangle]
-pub fn test(t: &Trait) -> isize {
- t.method()
-}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:attr_plugin_test.rs
+// ignore-stage1
+
+#![feature(plugin)]
+#![plugin(attr_plugin_test)]
+#![deny(unused_attributes)]
+
+#[baz]
+fn baz() { } // no error
+
+#[foo]
+pub fn main() {
+ //~^^ ERROR unused
+ #[bar]
+ fn inner() {}
+ //~^^ ERROR crate
+ //~^^^ ERROR unused
+ baz();
+ inner();
+}
use syntax::print::pprust;
fn main() {
- let ps = syntax::parse::new_parse_sess();
+ let ps = syntax::parse::ParseSess::new();
let mut cx = syntax::ext::base::ExtCtxt::new(
&ps, vec![],
syntax::ext::expand::ExpansionConfig::default("qquote".to_string()));
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//
-// ignore-stage1 (#20184)
+// WONTFIX(#20184) Needs landing pads (not present in stage1) or the compiler hangs.
+// ignore-stage1
// compile-flags: -C codegen-units=2
// error-pattern: build without -C codegen-units for more exact errors
struct Foo;
impl Foo {
- type Bar = isize; //~ERROR associated items are not allowed in inherent impls
+ type Bar = isize; //~ERROR associated types are not allowed in inherent impls
}
fn main() {}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(associated_consts)]
+
+pub trait Foo {
+ const MIN: i32;
+
+ fn get_min() -> i32 {
+ Self::MIN //~ ERROR E0329
+ }
+}
+
+fn get_min<T: Foo>() -> i32 {
+ T::MIN; //~ ERROR E0329
+ <T as Foo>::MIN //~ ERROR E0329
+}
+
+fn main() {}
}
pub fn main() {
- let a = &42 as &Foo<A=usize, B=char>;
+ let a = &42isize as &Foo<A=usize, B=char>;
- let b = &42 as &Foo<A=usize>;
+ let b = &42isize as &Foo<A=usize>;
//~^ ERROR the value of the associated type `B` (from the trait `Foo`) must be specified
- let c = &42 as &Foo<B=char>;
+ let c = &42isize as &Foo<B=char>;
//~^ ERROR the value of the associated type `A` (from the trait `Foo`) must be specified
- let d = &42 as &Foo;
+ let d = &42isize as &Foo;
//~^ ERROR the value of the associated type `A` (from the trait `Foo`) must be specified
//~| ERROR the value of the associated type `B` (from the trait `Foo`) must be specified
}
pub fn f1_uint_int() {
f1(2u32, 4i32);
//~^ ERROR the trait `Foo` is not implemented
- //~| ERROR the trait `Foo` is not implemented
}
pub fn f2_int() {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// error-pattern: unresolved name `m1::a`. Did you mean `args`?
+// error-pattern: unresolved name `m1::arguments`. Did you mean `arguments`?
mod m1 {}
-fn main(args: Vec<String>) { log(debug, m1::a); }
+fn main(arguments: Vec<String>) { log(debug, m1::arguments); }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// error-pattern: unresolved name `m1::a`. Did you mean `args`?
+// error-pattern: unresolved name `m1::arguments`. Did you mean `arguments`?
mod m1 {
- pub mod a {}
+ pub mod arguments {}
}
-fn main(args: Vec<String>) {
- log(debug, m1::a);
+fn main(arguments: Vec<String>) {
+ log(debug, m1::arguments);
}
fn foo(x: *const Box<isize>) -> Box<isize> {
- let y = *x; //~ ERROR dereference of unsafe pointer requires unsafe function or block
+ let y = *x; //~ ERROR dereference of raw pointer requires unsafe function or block
return y;
}
fn main() {
let (tx, rx) = channel();
1193182.foo(tx);
- assert!(rx.recv() == 1193182);
+ assert_eq!(rx.recv(), 1193182);
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ const X: u32 = main as u32; //~ ERROR E0018
+ const Y: u32 = 0;
+ const Z: u32 = &Y as *const u32 as u32; //~ ERROR E0018
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn illegal_cast<U:?Sized,V:?Sized>(u: *const U) -> *const V
+{
+ u as *const V //~ ERROR vtable kinds
+}
+
+fn illegal_cast_2<U:?Sized>(u: *const U) -> *const str
+{
+ u as *const str //~ ERROR vtable kinds
+}
+
+trait Foo { fn foo(&self) {} }
+impl<T> Foo for T {}
+
+trait Bar { fn foo(&self) {} }
+impl<T> Bar for T {}
+
+enum E {
+ A, B
+}
+
+fn main()
+{
+ let f: f32 = 1.2;
+ let v = 0 as *const u8;
+ let fat_v : *const [u8] = unsafe { &*(0 as *const [u8; 1])};
+ let foo: &Foo = &f;
+
+ let _ = v as &u8; //~ ERROR non-scalar
+ let _ = v as E; //~ ERROR non-scalar
+ let _ = v as fn(); //~ ERROR non-scalar
+ let _ = v as (u32,); //~ ERROR non-scalar
+ let _ = Some(&v) as *const u8; //~ ERROR non-scalar
+
+ let _ = v as f32; //~ ERROR through a usize first
+ let _ = main as f64; //~ ERROR through a usize first
+ let _ = &v as usize; //~ ERROR through a raw pointer first
+ let _ = f as *const u8; //~ ERROR through a usize first
+ let _ = 3 as bool; //~ ERROR compare with zero
+ let _ = E::A as bool; //~ ERROR compare with zero
+ let _ = 0x61u32 as char; //~ ERROR only `u8` can be cast
+
+ let _ = false as f32; //~ ERROR through an integer first
+ let _ = E::A as f32; //~ ERROR through an integer first
+ let _ = 'a' as f32; //~ ERROR through an integer first
+
+ let _ = false as *const u8; //~ ERROR through a usize first
+ let _ = E::A as *const u8; //~ ERROR through a usize first
+ let _ = 'a' as *const u8; //~ ERROR through a usize first
+
+ let _ = 42usize as *const [u8]; //~ ERROR illegal cast
+ let _ = v as *const [u8]; //~ ERROR illegal cast
+ let _ = fat_v as *const Foo;
+ //~^ ERROR `core::marker::Sized` is not implemented for the type `[u8]`
+ let _ = foo as *const str; //~ ERROR illegal cast
+ let _ = foo as *mut str; //~ ERROR illegal cast
+ let _ = main as *mut str; //~ ERROR illegal cast
+ let _ = &f as *mut f32; //~ ERROR illegal cast
+ let _ = &f as *const f64; //~ ERROR illegal cast
+ let _ = fat_v as usize; //~ ERROR through a raw pointer first
+
+ let a : *const str = "hello";
+ let _ = a as *const Foo;
+ //~^ ERROR `core::marker::Sized` is not implemented for the type `str`
+
+ // check no error cascade
+ let _ = main.f as *const u32; //~ ERROR attempted access of field
+
+ let cf: *const Foo = &0;
+ let _ = cf as *const [u8]; //~ ERROR vtable kinds
+ let _ = cf as *const Bar; //~ ERROR vtable kinds
+}
fn main() {
let v: u64 = 5;
let x = foo as extern "C" fn() -> isize;
- //~^ ERROR mismatched types
+ //~^ ERROR non-scalar cast
let y = v as extern "Rust" fn(isize) -> (isize, isize);
//~^ ERROR non-scalar cast
y(x());
//~^ ERROR mutable statics are not allowed to have destructors
field1: SafeEnum::Variant1,
field2: SafeEnum::Variant4("str".to_string())
-//~^ ERROR static contains unimplemented expression type
+//~^ ERROR method calls in statics are limited to constant inherent methods
};
static STATIC15: &'static [Box<MyOwned>] = &[
trait Bar: Foo { }
trait Baz: Bar { }
-// Subtraits of Baz are not legal:
+// Supertraits of Baz are not legal:
impl Foo for Baz { } //~ ERROR E0371
impl Bar for Baz { } //~ ERROR E0371
impl Baz for Baz { } //~ ERROR E0371
// But other random traits are:
trait Other { }
-impl Other for Baz { } // OK, Bar not a subtrait of Baz
+impl Other for Baz { } // OK, Other not a supertrait of Baz
// If the trait is not object-safe, we give a more tailored message
// because we're such schnuckels:
// except according to those terms.
static a: &'static str = "foo";
-static b: *const u8 = a as *const u8;
-//~^ ERROR mismatched types
-//~| expected *const u8
-//~| found &'static str
-//~| expected u8
-//~| found str
-static c: *const u8 = &a as *const u8;
-//~^ ERROR mismatched types
-//~| expected *const u8
-//~| found &&'static str
-//~| expected u8
-//~| found &-ptr
+static b: *const u8 = a as *const u8; //~ ERROR illegal cast
+static c: *const u8 = &a as *const u8; //~ ERROR illegal cast
fn main() {
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Check that you can't dereference raw pointers in constants.
+
+fn main() {
+ static C: u64 = unsafe {*(0xdeadbeef as *const u64)}; //~ ERROR E0396
+ println!("{}", C);
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we can't declare a const fn in an impl -- right now it's
+// just not allowed at all, though eventually it'd make sense to allow
+// it if the trait fn is const (but right now no trait fns can be
+// const).
+
+#![feature(const_fn)]
+
+trait Foo {
+ fn f() -> u32;
+}
+
+impl Foo for u32 {
+ const fn f() -> u32 { 22 } //~ ERROR E0379
+}
+
+fn main() { }
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that const fn is illegal in a trait declaration, whether or
+// not a default is provided.
+
+#![feature(const_fn)]
+
+trait Foo {
+ const fn f() -> u32; //~ ERROR trait fns cannot be declared const
+ const fn g() -> u32 { 0 } //~ ERROR trait fns cannot be declared const
+}
+
+fn main() { }
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we can't call random fns in a const fn or do other bad things.
+
+#![feature(const_fn)]
+
+use std::mem::transmute;
+
+fn random() -> u32 { 0 }
+
+const fn sub(x: &u32) -> usize {
+ unsafe { transmute(x) } //~ ERROR E0015
+}
+
+const fn sub1() -> u32 {
+ random() //~ ERROR E0015
+}
+
+static Y: u32 = 0;
+
+const fn get_Y() -> u32 {
+ Y
+ //~^ ERROR E0013
+ //~| ERROR cannot refer to other statics by value
+}
+
+const fn get_Y_addr() -> &'static u32 {
+ &Y
+ //~^ ERROR E0013
+}
+
+const fn get() -> u32 {
+ let x = 22; //~ ERROR E0016
+ let y = 44; //~ ERROR E0016
+ x + y
+}
+
+fn main() {
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test use of const fn from another crate without a feature gate.
+
+// aux-build:const_fn_lib.rs
+
+extern crate const_fn_lib;
+
+use const_fn_lib::foo;
+
+fn main() {
+ let x: [usize; foo()] = []; //~ ERROR unsupported constant expr
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test use of const fn from another crate without a feature gate.
+
+#![feature(rustc_attrs)]
+#![allow(unused_variables)]
+
+// aux-build:const_fn_lib.rs
+
+extern crate const_fn_lib;
+
+use const_fn_lib::foo;
+
+#[rustc_error]
+fn main() { //~ ERROR compilation successful
+ let x = foo(); // use outside a constant is ok
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test use of const fn from another crate without a feature gate.
+
+// aux-build:const_fn_lib.rs
+
+extern crate const_fn_lib;
+
+use const_fn_lib::foo;
+
+static FOO: usize = foo(); //~ ERROR const fns are an unstable feature
+const BAR: usize = foo(); //~ ERROR const fns are an unstable feature
+
+macro_rules! constant {
+ ($n:ident: $t:ty = $v:expr) => {
+ const $n: $t = $v;
+ }
+}
+
+constant! {
+ BAZ: usize = foo() //~ ERROR const fns are an unstable feature
+}
+
+fn main() {
+// let x: [usize; foo()] = [];
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test use of const fn without feature gate.
+
+const fn foo() -> usize { 0 } //~ ERROR const fn is unstable
+
+trait Foo {
+ const fn foo() -> u32; //~ ERROR const fn is unstable
+ const fn bar() -> u32 { 0 } //~ ERROR const fn is unstable
+}
+
+impl Foo {
+ const fn baz() -> u32 { 0 } //~ ERROR const fn is unstable
+}
+
+impl Foo for u32 {
+ const fn foo() -> u32 { 0 } //~ ERROR const fn is unstable
+}
+
+static FOO: usize = foo();
+const BAR: usize = foo();
+
+macro_rules! constant {
+ ($n:ident: $t:ty = $v:expr) => {
+ const $n: $t = $v;
+ }
+}
+
+constant! {
+ BAZ: usize = foo()
+}
+
+fn main() {
+ let x: [usize; foo()] = [];
+}
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Check that when there are vacuous predicates in the environment
+// (which make a fn uncallable) we don't erroneously cache those and
+// then consider them satisfied elsewhere. The current technique for
+// doing this is just to filter "global" predicates out of the
+// environment, which means that we wind up with an error in the
+// function `vacuous`, because even though `i32: Bar<u32>` is implied
+// by its where clause, that where clause never holds.
+
+trait Foo<X,Y>: Bar<X> {
+}
+
+trait Bar<X> { }
+
+fn vacuous<A>()
+ where i32: Foo<u32, A>
+{
+ // vacuous could never be called, because it requires that i32:
+ // Bar<u32>. But the code doesn't check that this could never be
+ // satisfied.
+ require::<i32, u32>();
+ //~^ ERROR the trait `Bar<u32>` is not implemented for the type `i32`
+}
+
+fn require<A,B>()
+ where A: Bar<B>
+{
+}
+
+fn main() {
+ require::<i32, u32>();
+}
fn main() {
let x = || panic!();
x();
- std::io::println("Foo bar"); //~ ERROR: unreachable statement
+ println!("Foo bar"); //~ ERROR: unreachable statement
}
// if n > m, it's a type mismatch error.
// n < m
- let &x = &(&1 as &T);
- let &x = &&(&1 as &T);
- let &&x = &&(&1 as &T);
+ let &x = &(&1isize as &T);
+ let &x = &&(&1isize as &T);
+ let &&x = &&(&1isize as &T);
// n == m
- let &x = &1 as &T; //~ ERROR type `&T` cannot be dereferenced
- let &&x = &(&1 as &T); //~ ERROR type `&T` cannot be dereferenced
- let box x = box 1 as Box<T>; //~ ERROR the trait `core::marker::Sized` is not implemented
+ let &x = &1isize as &T; //~ ERROR type `&T` cannot be dereferenced
+ let &&x = &(&1isize as &T); //~ ERROR type `&T` cannot be dereferenced
+ let box x = box 1isize as Box<T>; //~ ERROR the trait `core::marker::Sized` is not implemented
// n > m
- let &&x = &1 as &T;
+ let &&x = &1isize as &T;
//~^ ERROR mismatched types
//~| expected `T`
//~| found `&_`
//~| expected trait T
//~| found &-ptr
- let &&&x = &(&1 as &T);
+ let &&&x = &(&1isize as &T);
//~^ ERROR mismatched types
//~| expected `T`
//~| found `&_`
//~| expected trait T
//~| found &-ptr
- let box box x = box 1 as Box<T>;
+ let box box x = box 1isize as Box<T>;
//~^ ERROR mismatched types
//~| expected `T`
//~| found `Box<_>`
//
// (Compare against compile-fail/dropck_vec_cycle_checked.rs)
+#![feature(const_fn)]
+
use std::cell::Cell;
use id::Id;
mod s {
#![allow(unstable)]
- use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
+ use std::sync::atomic::{AtomicUsize, Ordering};
- static S_COUNT: AtomicUsize = ATOMIC_USIZE_INIT;
+ static S_COUNT: AtomicUsize = AtomicUsize::new(0);
pub fn next_count() -> usize {
S_COUNT.fetch_add(1, Ordering::SeqCst) + 1
// for the error message we see here.)
#![allow(unstable)]
+#![feature(const_fn)]
extern crate arena;
mod s {
#![allow(unstable)]
- use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
+ use std::sync::atomic::{AtomicUsize, Ordering};
- static S_COUNT: AtomicUsize = ATOMIC_USIZE_INIT;
+ static S_COUNT: AtomicUsize = AtomicUsize::new(0);
pub fn next_count() -> usize {
S_COUNT.fetch_add(1, Ordering::SeqCst) + 1
//
// (Compare against compile-fail/dropck_vec_cycle_checked.rs)
+#![feature(const_fn)]
+
use std::cell::Cell;
use id::Id;
mod s {
- use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
+ use std::sync::atomic::{AtomicUsize, Ordering};
- static S_COUNT: AtomicUsize = ATOMIC_USIZE_INIT;
+ static S_COUNT: AtomicUsize = AtomicUsize::new(0);
pub fn next_count() -> usize {
S_COUNT.fetch_add(1, Ordering::SeqCst) + 1
//
// (Compare against compile-fail/dropck_arr_cycle_checked.rs)
+#![feature(const_fn)]
+
use std::cell::Cell;
use id::Id;
mod s {
#![allow(unstable)]
- use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
+ use std::sync::atomic::{AtomicUsize, Ordering};
- static S_COUNT: AtomicUsize = ATOMIC_USIZE_INIT;
+ static S_COUNT: AtomicUsize = AtomicUsize::new(0);
pub fn next_count() -> usize {
S_COUNT.fetch_add(1, Ordering::SeqCst) + 1
trait Foo { fn foo(&self) {} }
impl Foo for str {}
+impl Foo for [u8] {}
fn test1<T: ?Sized + Foo>(t: &T) {
let u: &Foo = t;
//~^ ERROR `core::marker::Sized` is not implemented for the type `str`
}
-fn test4() {
- let _: &Foo = "hi" as &Foo;
- //~^ ERROR `core::marker::Sized` is not implemented for the type `str`
+fn test4(x: &[u8]) {
+ let _: &Foo = x as &Foo;
+ //~^ ERROR `core::marker::Sized` is not implemented for the type `[u8]`
}
fn main() { }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// Make sure casts between thin pointer <-> fat pointer are illegal.
-
-pub trait Trait {}
+trait Trait {}
+// Make sure casts between thin-pointer <-> fat pointer obey RFC401
fn main() {
let a: &[i32] = &[1, 2, 3];
let b: Box<[i32]> = Box::new([1, 2, 3]);
+ let p = a as *const [i32];
+ let q = a.as_ptr();
- a as usize; //~ ERROR non-scalar cast
+ a as usize; //~ ERROR illegal cast
b as usize; //~ ERROR non-scalar cast
+ p as usize; //~ ERROR illegal cast; cast through a raw pointer
- let a: usize = 42;
- a as *const [i32]; //~ ERROR cast to fat pointer: `usize` as `*const [i32]`
+ // #22955
+ q as *const [i32]; //~ ERROR illegal cast
- let a: *const u8 = &42;
- a as *const [u8]; //~ ERROR cast to fat pointer: `*const u8` as `*const [u8]`
+ // #21397
+ let t: *mut (Trait + 'static) = 0 as *mut _; //~ ERROR illegal cast
+ let mut fail: *const str = 0 as *const str; //~ ERROR illegal cast
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait Foo {
+ type Bar = u8; //~ ERROR associated type defaults are unstable
+}
+
+fn main() {}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(simd, core)]
+#![feature(simd, core_simd)]
#![allow(dead_code)]
use std::simd::f32x4;
+++ /dev/null
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#[static_assert] //~ ERROR `#[static_assert]` is an experimental feature
-static X: bool = true;
-
-fn main() {}
// RFC 736 (and Issue 21407): functional struct update should respect privacy.
+#![feature(const_fn)]
+
// The `foo` module attempts to maintains an invariant that each `S`
// has a unique `u64` id.
use self::foo::S;
mod foo {
use std::cell::{UnsafeCell};
- static mut count : UnsafeCell<u64> = UnsafeCell { value: 1 };
+ static mut count : UnsafeCell<u64> = UnsafeCell::new(1);
pub struct S { pub a: u8, pub b: String, secret_uid: u64 }
struct Foo;
impl Foo {
fn orange(&self){}
- fn orange(&self){} //~ ERROR error: duplicate method
+ fn orange(&self){} //~ ERROR duplicate method
}
fn main() {}
fn outer(self) {
fn inner(_: Self) {
//~^ ERROR can't use type parameters from outer function
- //~^^ ERROR use of undeclared type name `Self`
+ //~^^ ERROR use of `Self` outside of an impl or trait
}
}
}
fn main() {
let x = X { a: [0] };
- let _f = &x.a as *mut u8;
- //~^ ERROR mismatched types
- //~| expected `*mut u8`
- //~| found `&[u8; 1]`
- //~| expected u8
- //~| found array of 1 elements
+ let _f = &x.a as *mut u8; //~ ERROR illegal cast
let local: [u8; 1] = [0];
- let _v = &local as *mut u8;
- //~^ ERROR mismatched types
- //~| expected `*mut u8`
- //~| found `&[u8; 1]`
- //~| expected u8,
- //~| found array of 1 elements
+ let _v = &local as *mut u8; //~ ERROR illegal cast
}
// except according to those terms.
// macro f should not be able to inject a reference to 'n'.
-//
-// Ignored because `for` loops are not hygienic yet; they will require special
-// handling since they introduce a new pattern binding position.
-
-// ignore-test
macro_rules! f { () => (n) }
static foo: *const Y::X = Y::foo(Y::x as *const Y::X);
//~^ ERROR the trait `core::marker::Sync` is not implemented for the type
-//~| ERROR function calls in statics are limited to struct and enum constructors
+//~| ERROR cannot refer to other statics by value, use the address-of operator or a constant instead
+//~| ERROR E0015
fn main() {}
fn main() {
let _x = Test::Foo as *const isize;
- //~^ ERROR illegal cast; cast through an integer first: `Test` as `*const isize`
+ //~^ ERROR illegal cast; cast through a usize first: `Test` as `*const isize`
}
// except according to those terms.
static X: usize = 0 as *const usize as usize;
-//~^ ERROR: can not cast a pointer to an integer in statics
+//~^ ERROR: raw pointers cannot be cast to integers in statics
fn main() {
assert_eq!(X, 0);
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(const_fn)]
+
use std::cell::UnsafeCell;
-const A: UnsafeCell<usize> = UnsafeCell { value: 1 };
+const A: UnsafeCell<usize> = UnsafeCell::new(1);
const B: &'static UnsafeCell<usize> = &A;
//~^ ERROR: cannot borrow a constant which contains interior mutability
struct C { a: UnsafeCell<usize> }
-const D: C = C { a: UnsafeCell { value: 1 } };
+const D: C = C { a: UnsafeCell::new(1) };
const E: &'static UnsafeCell<usize> = &D.a;
//~^ ERROR: cannot borrow a constant which contains interior mutability
const F: &'static C = &D;
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+impl Undefined {}
+//~^ ERROR use of undeclared type name `Undefined`
+
+fn main() {}
fn main() {
let o = Obj { closure: || 42 };
o.closure(); //~ ERROR no method named `closure` found
- //~^ NOTE use `(s.closure)(...)` if you meant to call the function stored in the `closure` field
+ //~^ NOTE use `(o.closure)(...)` if you meant to call the function stored in the `closure` field
}
#[lang = "sized"]
trait Sized { }
+struct S;
+
#[start]
fn main(_: isize, _: *const *const u8) -> isize {
+ let _ = S;
0
}
//~^ ERROR cannot move out of borrowed content
let c = unsafe { *mut_ptr() };
- //~^ ERROR cannot move out of dereference of unsafe pointer
+ //~^ ERROR cannot move out of dereference of raw pointer
let d = unsafe { *const_ptr() };
- //~^ ERROR cannot move out of dereference of unsafe pointer
+ //~^ ERROR cannot move out of dereference of raw pointer
}
struct Inches(i32);
fn main() {
- Inches as f32; //~ ERROR illegal cast; cast through an integer first
+ Inches as f32; //~ ERROR illegal cast; cast through a usize first
}
// except according to those terms.
fn main() {
- 0 as &std::any::Any; //~ ERROR cast to fat pointer: `i32` as `&core::any::Any`
+ 0 as &std::any::Any; //~ ERROR non-scalar cast
}
trait Expr : PartialEq<Self::Item> {
//~^ ERROR: unsupported cyclic reference between types/traits detected
- type Item = Expr;
+ type Item;
}
fn main() {}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(associated_type_defaults)]
+
+trait Foo { type T; }
+trait Bar {
+ type Foo: Foo;
+ type FooT = <<Self as Bar>::Foo>::T; //~ ERROR ambiguous associated type
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+enum Token { LeftParen, RightParen, Plus, Minus, /* etc */ }
+
+fn use_token(token: &Token) { unimplemented!() }
+
+fn main() {
+ use_token(&Token::Homura); //~ ERROR no associated item named
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ let v: Vec(&str) = vec!['1', '2'];
+ //~^ ERROR parenthesized parameters may only be used with a trait
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(core)]
+use std::boxed::FnBox;
+
+struct Obj<F> where F: FnOnce() -> u32 {
+ closure: F,
+ not_closure: usize,
+}
+
+struct BoxedObj {
+ boxed_closure: Box<FnBox() -> u32>,
+}
+
+struct Wrapper<F> where F: FnMut() -> u32 {
+ wrap: Obj<F>,
+}
+
+fn func() -> u32 {
+ 0
+}
+
+fn check_expression() -> Obj<Box<FnBox() -> u32>> {
+ Obj { closure: Box::new(|| 42_u32) as Box<FnBox() -> u32>, not_closure: 42 }
+}
+
+fn main() {
+ // test variations of function
+
+ let o_closure = Obj { closure: || 42, not_closure: 42 };
+ o_closure.closure(); //~ ERROR no method named `closure` found
+ //~^ NOTE use `(o_closure.closure)(...)` if you meant to call the function stored
+
+ o_closure.not_closure(); //~ ERROR no method named `not_closure` found
+ //~^ NOTE did you mean to write `o_closure.not_closure`?
+
+ let o_func = Obj { closure: func, not_closure: 5 };
+ o_func.closure(); //~ ERROR no method named `closure` found
+ //~^ NOTE use `(o_func.closure)(...)` if you meant to call the function stored
+
+ let boxed_fn = BoxedObj { boxed_closure: Box::new(func) };
+ boxed_fn.boxed_closure();//~ ERROR no method named `boxed_closure` found
+ //~^ NOTE use `(boxed_fn.boxed_closure)(...)` if you meant to call the function stored
+
+ let boxed_closure = BoxedObj { boxed_closure: Box::new(|| 42_u32) as Box<FnBox() -> u32> };
+ boxed_closure.boxed_closure();//~ ERROR no method named `boxed_closure` found
+ //~^ NOTE use `(boxed_closure.boxed_closure)(...)` if you meant to call the function stored
+
+ // test expression writing in the notes
+
+ let w = Wrapper { wrap: o_func };
+ w.wrap.closure();//~ ERROR no method named `closure` found
+ //~^ NOTE use `(w.wrap.closure)(...)` if you meant to call the function stored
+
+ w.wrap.not_closure();//~ ERROR no method named `not_closure` found
+ //~^ NOTE did you mean to write `w.wrap.not_closure`?
+
+ check_expression().closure();//~ ERROR no method named `closure` found
+ //~^ NOTE use `(check_expression().closure)(...)` if you meant to call the function stored
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::ops::Add; //~ ERROR import `Add` conflicts with type in this module
+use std::ops::Sub; //~ ERROR import `Sub` conflicts with type in this module
+use std::ops::Mul; //~ ERROR import `Mul` conflicts with type in this module
+use std::ops::Div; //~ ERROR import `Div` conflicts with existing submodule
+use std::ops::Rem; //~ ERROR import `Rem` conflicts with trait in this module
+
+type Add = bool;
+struct Sub { x: f32 }
+enum Mul { A, B }
+mod Div { }
+trait Rem { }
+
+fn main() {}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct B;
+
+impl B {
+ fn func(&self) -> u32 { 42 }
+}
+
+fn main() {
+ let x: &fn(&B) -> u32 = &B::func; //~ ERROR mismatched types
+}
fn main() {
static foo: Fn() -> u32 = || -> u32 {
//~^ ERROR: mismatched types:
- //~| expected `core::ops::Fn() -> u32`,
+ //~| expected `core::ops::Fn() -> u32 + 'static`,
//~| found closure
//~| (expected trait core::ops::Fn,
//~| found closure)
+++ /dev/null
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// ignore-test
-
-fn foo<'a>() -> &'a isize { //~ ERROR unconstrained region
- return &x;
-}
-static x: isize = 5;
-fn main() {}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn foo(_: Self) {
+ //~^ ERROR use of `Self` outside of an impl or trait
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use foo::baz;
+use bar::baz; //~ ERROR a module named `baz` has already been imported
+
+use foo::Quux;
+use bar::Quux; //~ ERROR a trait named `Quux` has already been imported
+
+use foo::blah;
+use bar::blah; //~ ERROR a type named `blah` has already been imported
+
+use foo::WOMP;
+use bar::WOMP; //~ ERROR a value named `WOMP` has already been imported
+
+fn main() {}
+
+mod foo {
+ pub mod baz {}
+ pub trait Quux { }
+ pub type blah = (f64, u32);
+ pub const WOMP: u8 = 5;
+}
+
+mod bar {
+ pub mod baz {}
+ pub type Quux = i32;
+ struct blah { x: i8 }
+ pub const WOMP: i8 = -5;
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct S<T: 'static>(Option<&'static T>);
+
+trait Tr { type Out; }
+impl<T> Tr for T { type Out = T; }
+
+impl<T: 'static> Copy for S<T> where S<T>: Tr<Out=T> {}
+impl<T: 'static> Clone for S<T> where S<T>: Tr<Out=T> {
+ fn clone(&self) -> Self { *self }
+}
+fn main() {
+ let t = S::<()>(None);
+ drop(t);
+ drop(t); //~ ERROR use of moved value
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn id<T>(t: T) -> T { t }
+fn main() {
+ const A: bool = id::<u8> as *const () < id::<u16> as *const ();
+ //~^ ERROR raw pointers cannot be compared in constants [E0395]
+ println!("{}", A);
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct S(String);
+
+impl S {
+ fn f(self: *mut S) -> String { self.0 }
+ //~^ ERROR mismatched self type
+}
+
+fn main() { S("".to_owned()).f(); }
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Check that projections don't count as constraining type parameters.
+
+struct S<T>(T);
+
+trait Tr { type Assoc; fn test(); }
+
+impl<T: Tr> S<T::Assoc> {
+//~^ ERROR the type parameter `T` is not constrained
+ fn foo(self, _: T) {
+ T::test();
+ }
+}
+
+trait Trait1<T> { type Bar; }
+trait Trait2<'x> { type Foo; }
+
+impl<'a,T: Trait2<'a>> Trait1<<T as Trait2<'a>>::Foo> for T {
+//~^ ERROR the lifetime parameter `'a` is not constrained
+ type Bar = &'a ();
+}
+
+fn main() {}
Foo { baz: 0 }.bar();
}
- fn bar() { //~ ERROR duplicate method
+ fn bar() { //~ ERROR duplicate associated function
}
}
}
fn main() {
- (&5 as &Foo).foo();
+ (&5isize as &Foo).foo();
//~^ ERROR: no method named `foo` found for type `&Foo` in the current scope
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// Creating a stack closure which references an owned pointer and then
-// transferring ownership of the owned box before invoking the stack
+// Creating a stack closure which references an box and then
+// transferring ownership of the box before invoking the stack
// closure results in a crash.
#![feature(box_syntax)]
// except according to those terms.
#![feature(box_syntax)]
+#![feature(const_fn)]
use std::cell::RefCell;
//~^ ERROR allocations are not allowed in statics
//~| ERROR the trait `core::marker::Sync` is not implemented for the type
//~| ERROR the trait `core::marker::Sync` is not implemented for the type
-//~| ERROR function calls in statics are limited to struct and enum constructors
fn main() { }
assert_copy::<&'static mut isize>(); //~ ERROR `core::marker::Copy` is not implemented
assert_copy::<&'a mut isize>(); //~ ERROR `core::marker::Copy` is not implemented
- // owned pointers are not ok
+ // boxes are not ok
assert_copy::<Box<isize>>(); //~ ERROR `core::marker::Copy` is not implemented
assert_copy::<String>(); //~ ERROR `core::marker::Copy` is not implemented
assert_copy::<Vec<isize> >(); //~ ERROR `core::marker::Copy` is not implemented
let a = &t as &Gettable<T>;
//~^ ERROR the trait `core::marker::Send` is not implemented
//~^^ ERROR the trait `core::marker::Copy` is not implemented
- //~^^^ ERROR the parameter type `T` may not live long enough
}
fn g<T>(val: T) {
}
fn foo3<'a>() {
- let t: Box<S<String>> = box S(marker::PhantomData);
- let a: Box<Gettable<String>> = t;
+ struct Foo; // does not impl Copy
+
+ let t: Box<S<Foo>> = box S(marker::PhantomData);
+ let a: Box<Gettable<Foo>> = t;
//~^ ERROR the trait `core::marker::Copy` is not implemented
}
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:lifetime_bound_will_change_warning_lib.rs
+
+// Test that we get suitable warnings when lifetime bound change will
+// cause breakage.
+
+#![allow(dead_code)]
+#![allow(unused_variables)]
+#![feature(rustc_attrs)]
+
+extern crate lifetime_bound_will_change_warning_lib as lib;
+
+fn just_ref(x: &Fn()) {
+}
+
+fn ref_obj(x: &Box<Fn()>) {
+ // this will change to &Box<Fn()+'static>...
+
+ // Note: no warning is issued here, because the type of `x` will change to 'static
+ if false { ref_obj(x); }
+}
+
+fn test1<'a>(x: &'a Box<Fn()+'a>) {
+ // just_ref will stay the same.
+ just_ref(&**x)
+}
+
+fn test1cc<'a>(x: &'a Box<Fn()+'a>) {
+ // same as test1, but cross-crate
+ lib::just_ref(&**x)
+}
+
+fn test2<'a>(x: &'a Box<Fn()+'a>) {
+ // but ref_obj will not, so warn.
+ ref_obj(x) //~ WARNING this code may fail to compile in Rust 1.3
+}
+
+fn test2cc<'a>(x: &'a Box<Fn()+'a>) {
+ // same as test2, but cross crate
+ lib::ref_obj(x) //~ WARNING this code may fail to compile in Rust 1.3
+}
+
+fn test3<'a>(x: &'a Box<Fn()+'static>) {
+ // here, we have a 'static bound, so even when ref_obj changes, no error results
+ ref_obj(x)
+}
+
+fn test3cc<'a>(x: &'a Box<Fn()+'static>) {
+ // same as test3, but cross crate
+ lib::ref_obj(x)
+}
+
+#[rustc_error]
+fn main() { //~ ERROR compilation successful
+}
#![allow(unused_variables)]
#![allow(non_camel_case_types)]
#![deny(dead_code)]
-#![feature(libc)]
-#![feature(core)]
-
-extern crate libc;
struct Foo {
x: usize,
b: bool, //~ ERROR: struct field is never used
- marker: std::marker::NoCopy
}
fn field_read(f: Foo) -> usize {
X, //~ ERROR variant is never used
Y { //~ ERROR variant is never used
a: String,
- b: isize //~ ERROR: struct field is never used
+ b: i32, //~ ERROR: struct field is never used
+ c: i32, //~ ERROR: struct field is never used
},
Z
}
fn field_match_in_patterns(b: XYZ) -> String {
match b {
- XYZ::Y { a, .. } => a,
+ XYZ::Y { a, b: _, .. } => a,
_ => "".to_string()
}
}
struct Bar {
x: usize, //~ ERROR: struct field is never used
b: bool,
+ c: bool, //~ ERROR: struct field is never used
_guard: ()
}
#[repr(C)]
struct Baz {
- x: libc::c_uint
+ x: u32,
}
fn field_match_in_let(f: Bar) -> bool {
- let Bar { b, .. } = f;
+ let Bar { b, c: _, .. } = f;
b
}
fn main() {
- field_read(Foo { x: 1, b: false, marker: std::marker::NoCopy });
+ field_read(Foo { x: 1, b: false });
field_match_in_patterns(XYZ::Z);
- field_match_in_let(Bar { x: 42, b: true, _guard: () });
+ field_match_in_let(Bar { x: 42, b: true, c: false, _guard: () });
let _ = Baz { x: 0 };
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![deny(dead_code)]
+
+#[derive(Clone)]
+enum Enum {
+ Variant1, //~ ERROR: variant is never used
+ Variant2,
+}
+
+fn main() {
+ let e = Enum::Variant2;
+ e.clone();
+}
#![deny(exceeding_bitshifts)]
#![allow(unused_variables)]
#![allow(dead_code)]
-#![feature(core, negate_unsigned)]
+#![feature(num_bits_bytes, negate_unsigned)]
fn main() {
let n = 1u8 << 7;
// injected intrinsics by the compiler.
#![deny(missing_docs)]
#![allow(dead_code)]
+#![feature(associated_type_defaults)]
//! Some garbage docs for the crate here
#![doc="More garbage"]
let x = 9223372036854775808_i64; //~ error: literal out of range for i64
let x = -9223372036854775808_i64; // should be OK
let x = 18446744073709551615_i64; //~ error: literal out of range for i64
+ let x: i64 = -9223372036854775809; //~ error: literal out of range for i64
+ let x = -9223372036854775809_i64; //~ error: literal out of range for i64
let x = -3.40282348e+38_f32; //~ error: literal out of range for f32
let x = 3.40282348e+38_f32; //~ error: literal out of range for f32
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Regression test for issue #25436: check that things which can be
+// followed by any token also permit X* to come afterwards.
+
+macro_rules! foo {
+ ( $a:expr $($b:tt)* ) => { }; //~ ERROR not allowed for `expr` fragments
+ ( $a:ty $($b:tt)* ) => { }; //~ ERROR not allowed for `ty` fragments
+}
+
+fn main() { }
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Check that we cannot have two sequence repetitions in a row.
+
+macro_rules! foo {
+ ( $($a:expr)* $($b:tt)* ) => { }; //~ ERROR sequence repetition followed by another sequence
+ ( $($a:tt)* $($b:tt)* ) => { }; //~ ERROR sequence repetition followed by another sequence
+}
+
+fn main() { }
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-fn main() {
- match 1 {
- 1...2_usize => 1, //~ ERROR mismatched types in range
- _ => 2,
- };
-}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//error-pattern: lower range bound
-//error-pattern: only char and numeric types
-//error-pattern: mismatched types
-
fn main() {
match 5 {
- 6 ... 1 => { }
- _ => { }
+ 6 ... 1 => { }
+ _ => { }
+ };
+ //~^^^ ERROR lower range bound must be less than or equal to upper
+
+ match "wow" {
+ "bar" ... "foo" => { }
};
+ //~^^ ERROR only char and numeric types are allowed in range
+ //~| start type: &'static str
+ //~| end type: &'static str
match "wow" {
- "bar" ... "foo" => { }
+ 10 ... "what" => ()
};
+ //~^^ ERROR only char and numeric types are allowed in range
+ //~| start type: _
+ //~| end type: &'static str
match 5 {
- 'c' ... 100 => { }
- _ => { }
+ 'c' ... 100 => { }
+ _ => { }
};
+ //~^^^ ERROR mismatched types in range
+ //~| expected char
+ //~| found integral variable
}
//~^ ERROR constant in pattern `a` should have an upper case name such as `A`
(x, y) => 1 + x + y,
};
- assert!(r == 1);
+ assert_eq!(r, 1);
}
mod m {
//~^ ERROR constant in pattern `aha` should have an upper case name such as `AHA`
(x, y) => 1 + x + y,
};
- assert!(r == 1);
+ assert_eq!(r, 1);
}
mod n {
//~^ ERROR constant in pattern `not_okay` should have an upper case name such as `NOT_OKAY`
(x, y) => 1 + x + y,
};
- assert!(r == 1);
+ assert_eq!(r, 1);
}
fn main () {
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct Foo;
+
+fn main() {
+ let a: Result<(), Foo> = Ok(());
+ a.unwrap();
+ //~^ ERROR no method named `unwrap` found for type `core::result::Result<(), Foo>`
+ //~| NOTE the following trait bounds were not satisfied: `Foo : core::fmt::Debug`
+}
mod mod_file_aux;
fn main() {
- assert!(mod_file_aux::bar() == 10); //~ ERROR unresolved name
+ assert_eq!(mod_file_aux::bar(), 10); //~ ERROR unresolved name
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Make sure that the span of a closure marked `move` begins at the `move` keyword.
+
+fn main() {
+ let x: () =
+ move //~ ERROR mismatched types
+ || ();
+}
+++ /dev/null
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![feature(static_assert)]
-#![allow(dead_code)]
-
-#[static_assert]
-static E: i32 = 1; //~ ERROR can only have static_assert on a static with type `bool`
-
-fn main() {}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// error-pattern: is not UTF-8
+// error-pattern: did not contain valid UTF-8
fn foo() {
include!("not-utf8.bin")
//~| ERROR mismatched types
}
+fn load2<'a>(ss: &MyBox<SomeTrait+'a>) -> MyBox<SomeTrait+'a> {
+ load0(ss) //~ WARNING E0398
+}
+
fn main() {
}
#![feature(rustc_attrs)]
#[rustc_object_lifetime_default]
-struct A<T>(T); //~ ERROR None
+struct A<T>(T); //~ ERROR BaseDefault
#[rustc_object_lifetime_default]
-struct B<'a,T>(&'a (), T); //~ ERROR None
+struct B<'a,T>(&'a (), T); //~ ERROR BaseDefault
#[rustc_object_lifetime_default]
struct C<'a,T:'a>(&'a T); //~ ERROR 'a
fn main() {
let nyan : cat = cat(52, 99);
- assert!((nyan.meows == 52));
+ assert_eq!(nyan.meows, 52);
//~^ ERROR field `meows` of struct `cci_class::kitties::cat` is private
}
fn main() {
let nyan = cat::new_cat();
- assert!(nyan.meows == 52); //~ ERROR field `meows` of struct `cat::Cat` is private
+ assert_eq!(nyan.meows, 52); //~ ERROR field `meows` of struct `cat::Cat` is private
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Regression test for issue #26083
+// Test that span for public struct fields start at `pub` instead of the identifier
+
+struct Foo {
+ pub bar: u8,
+
+ pub
+ //~^ error: field `bar` is already declared [E0124]
+ bar: u8,
+
+ pub bar:
+ //~^ error: field `bar` is already declared [E0124]
+ u8,
+
+ bar:
+ //~^ error: field `bar` is already declared [E0124]
+ u8,
+}
+
+fn main() { }
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// ignore-test
-
-// error-pattern:library 'm' already added: can't specify link_args.
-
-/* I think it should undefined to have multiple modules that link in the same
- library, but provide different link arguments. Unfortunately we don't track
- link_args by module -- they are just appended as discovered into the crate
- store -- but for now, it should be an error to provide link_args on a module
- that's already been included (with or without link_args). */
-
-#[link_name= "m"]
-#[link_args="-foo"] // this could have been elided.
-extern {
-}
-
-#[link_name= "m"]
-#[link_args="-bar"] // this is the actual error trigger.
-extern {
-}
assert_send::<Box<&'a isize>>(); //~ ERROR does not fulfill the required lifetime
}
-// unsafe pointers are ok unless they point at unsendable things
+// raw pointers are ok unless they point at unsendable things
fn unsafe_ok1<'a>(_: &'a isize) {
assert_send::<*const isize>();
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![feature(static_assert)]
-#![allow(dead_code)]
-
-#[static_assert]
-static A: bool = false; //~ ERROR static assertion failed
-
-fn main() {
-}
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![feature(static_assert)]
-#![allow(dead_code)]
-
-#[static_assert]
-static E: bool = 1 == 2; //~ ERROR static assertion failed
-
-fn main() {}
static mut a: Box<isize> = box 3;
//~^ ERROR allocations are not allowed in statics
-//~^^ ERROR mutable statics are not allowed to have owned pointers
+//~^^ ERROR mutable statics are not allowed to have boxes
fn main() {}
fn foo() -> isize { 23 }
static a: [isize; 2] = [foo(); 2];
-//~^ ERROR: function calls in statics are limited to struct and enum constructors
+//~^ ERROR: E0015
fn main() {}
use std::ptr;
fn main() {
- let x = ATOMIC_BOOL_INIT;
+ let x = AtomicBool::new(false);
let x = *&x; //~ ERROR: cannot move out of borrowed content
- let x = ATOMIC_ISIZE_INIT;
+ let x = AtomicIsize::new(0);
let x = *&x; //~ ERROR: cannot move out of borrowed content
- let x = ATOMIC_USIZE_INIT;
+ let x = AtomicUsize::new(0);
let x = *&x; //~ ERROR: cannot move out of borrowed content
let x: AtomicPtr<usize> = AtomicPtr::new(ptr::null_mut());
let x = *&x; //~ ERROR: cannot move out of borrowed content
+++ /dev/null
-// ignore-test
-
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-
-struct Foo<'a> {
- x: &'a isize
-}
-
-pub fn main() {
- let f = Foo { x: &*(box 3) }; //~ ERROR borrowed value does not live long enough
- assert_eq!(*f.x, 3);
-}
assert_eq!(concat_idents!(asd, f_f, dsa), "<.<".to_string());
//~^ ERROR: unresolved name `asdf_fdsa`
- assert!(stringify!(use_mention_distinction) ==
- "use_mention_distinction");
+ assert_eq!(stringify!(use_mention_distinction), "use_mention_distinction");
}
trait MyDefaultImpl {}
impl<T> MyDefaultImpl for .. {}
-//~^ ERROR default trait implementations are not allowed to have genercis
+//~^ ERROR default trait implementations are not allowed to have generics
fn main() {}
fn d(x: Box<Foo>) {
a(x); //~ ERROR mismatched types
- //~| expected `Box<Foo + Send>`
- //~| found `Box<Foo>`
+ //~| expected `Box<Foo + Send + 'static>`
+ //~| found `Box<Foo + 'static>`
//~| expected bounds `Send`
//~| found no bounds
}
}
struct Baz {
-//~^ ERROR not implemented
- a: Foo<isize>,
+ a: Foo<isize>, //~ ERROR not implemented
}
enum Boo {
-//~^ ERROR not implemented
- Quux(Bar<usize>),
+ Quux(Bar<usize>), //~ ERROR not implemented
}
struct Badness<U> {
-//~^ ERROR not implemented
- b: Foo<U>,
+ b: Foo<U>, //~ ERROR not implemented
}
enum MoreBadness<V> {
-//~^ ERROR not implemented
- EvenMoreBadness(Bar<V>),
+ EvenMoreBadness(Bar<V>), //~ ERROR not implemented
+}
+
+struct TupleLike(
+ Foo<i32>, //~ ERROR not implemented
+);
+
+enum Enum {
+ DictionaryLike { field: Bar<u8> }, //~ ERROR not implemented
}
trait PolyTrait<T>
struct Struct;
-impl PolyTrait<Foo<usize>> for Struct {
+impl PolyTrait<Foo<u16>> for Struct {
//~^ ERROR not implemented
}
-// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// except according to those terms.
impl<T> Option<T> {
-//~^ ERROR cannot associate methods with a type outside the crate the type is defined in
+//~^ ERROR cannot define inherent `impl` for a type outside of the crate where the type is defined
pub fn foo(&self) { }
}
struct Outer<T: Send>(T);
-struct TestType;
-impl !Send for TestType {}
-
struct Outer2<T>(T);
unsafe impl<T: Send> Sync for Outer2<T> {}
fn is_sync<T: Sync>(_: T) {}
fn dummy() {
+ struct TestType;
+ impl !Send for TestType {}
+
Outer(TestType);
- //~^ ERROR the trait `core::marker::Send` is not implemented for the type `TestType`
+ //~^ ERROR the trait `core::marker::Send` is not implemented for the type `dummy::TestType`
is_send(TestType);
- //~^ ERROR the trait `core::marker::Send` is not implemented for the type `TestType`
+ //~^ ERROR the trait `core::marker::Send` is not implemented for the type `dummy::TestType`
is_send((8, TestType));
- //~^ ERROR the trait `core::marker::Send` is not implemented for the type `TestType`
+ //~^ ERROR the trait `core::marker::Send` is not implemented for the type `dummy::TestType`
}
fn dummy2() {
+ struct TestType;
+ impl !Send for TestType {}
+
is_send(Box::new(TestType));
- //~^ ERROR the trait `core::marker::Send` is not implemented for the type `TestType`
+ //~^ ERROR the trait `core::marker::Send` is not implemented for the type `dummy2::TestType`
}
fn dummy3() {
+ struct TestType;
+ impl !Send for TestType {}
+
is_send(Box::new(Outer2(TestType)));
- //~^ ERROR the trait `core::marker::Send` is not implemented for the type `TestType`
+ //~^ ERROR the trait `core::marker::Send` is not implemented for the type `dummy3::TestType`
}
fn main() {
+ struct TestType;
+ impl !Send for TestType {}
+
// This will complain about a missing Send impl because `Sync` is implement *just*
// for T that are `Send`. Look at #20366 and #19950
is_sync(Outer2(TestType));
- //~^ ERROR the trait `core::marker::Send` is not implemented for the type `TestType`
+ //~^ ERROR the trait `core::marker::Send` is not implemented for the type `main::TestType`
}
fn main() {
let x : i16 = 22;
((&x) as *const i16) as f32;
- //~^ ERROR illegal cast; cast through an integer first: `*const i16` as `f32`
+ //~^ ERROR illegal cast; cast through a usize first: `*const i16` as `f32`
}
}
fn main() {
- foo::<i32>();
- //~^ ERROR the trait `NotImplemented` is not implemented for the type `core::option::Option<i32>`
+ foo::<u32>();
+ //~^ ERROR the trait `NotImplemented` is not implemented for the type `core::option::Option<u32>`
}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ let foo = 1;
+
+ // `foo` shouldn't be suggested, it is too dissimilar from `bar`.
+ println!("Hello {}", bar);
+ //~^ ERROR: unresolved name `bar`
+
+ // But this is close enough.
+ println!("Hello {}", fob);
+ //~^ ERROR: unresolved name `fob`. Did you mean `foo`?
+}
fn main() {
<String as IntoCow>::into_cow("foo".to_string());
- //~^ ERROR too few type parameters provided: expected 1 parameter(s)
+ //~^ ERROR too few type parameters provided: expected 1 parameter
}
fn bar() {
let x: Box<Bar()> = panic!();
//~^ ERROR parenthesized parameters may only be used with a trait
- //~^^ ERROR associated type bindings are not allowed here
}
fn main() { }
fn foo(b: Box<Bar()>) {
//~^ ERROR parenthesized parameters may only be used with a trait
- //~^^ ERROR associated type bindings are not allowed here
}
fn main() { }
fn f(p: *const u8) {
- *p = 0; //~ ERROR dereference of unsafe pointer requires unsafe function or block
+ *p = 0; //~ ERROR dereference of raw pointer requires unsafe function or block
return;
}
fn f(p: *const u8) -> u8 {
- return *p; //~ ERROR dereference of unsafe pointer requires unsafe function or block
+ return *p; //~ ERROR dereference of raw pointer requires unsafe function or block
}
fn main() {
g: [usize]
}
struct S4 {
- f: str, //~ ERROR `core::marker::Sized` is not implemented
+ f: [u8], //~ ERROR `core::marker::Sized` is not implemented
g: usize
}
enum E<X: ?Sized> {
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Each path node in a `use` declaration must be treated as an item. If not, the following code
+// will trigger an ICE.
+//
+// Related issue: #25763
+
+use std::{mem, ptr};
+use std::mem; //~ ERROR has already been imported
+
+fn main() {}
// conditions above to be satisfied, meaning that if the dropck is
// sound, it should reject this code.
+#![feature(const_fn)]
+
use std::cell::Cell;
use id::Id;
mod s {
#![allow(unstable)]
- use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
+ use std::sync::atomic::{AtomicUsize, Ordering};
- static S_COUNT: AtomicUsize = ATOMIC_USIZE_INIT;
+ static S_COUNT: AtomicUsize = AtomicUsize::new(0);
/// generates globally unique count (global across the current
/// process, that is)
let mut x1 = X { y: [0, 0] };
// This is still an error since we don't allow casts from &mut [T; n] to *mut T.
- let p1: *mut u8 = &mut x1.y as *mut _; //~ ERROR mismatched types
+ let p1: *mut u8 = &mut x1.y as *mut _; //~ ERROR illegal cast
let t1: *mut [u8; 2] = &mut x1.y as *mut _;
let h1: *mut [u8; 2] = &mut x1.y as *mut [u8; 2];
}
#![allow(dead_code, unused_variables)]
#![omit_gdb_pretty_printer_section]
-#![feature(std_misc, core)]
+#![feature(const_fn)]
+#![feature(static_mutex)]
// This test makes sure that the compiler doesn't crash when trying to assign
// debug locations to const-expressions.
-use std::sync::MUTEX_INIT;
+use std::sync::StaticMutex;
use std::cell::UnsafeCell;
const CONSTANT: u64 = 3 + 4;
const NESTED: (Struct, TupleStruct) = (STRUCT, TUPLE_STRUCT);
-const UNSAFE_CELL: UnsafeCell<bool> = UnsafeCell { value: false };
+const UNSAFE_CELL: UnsafeCell<bool> = UnsafeCell::new(false);
fn main() {
let mut _constant = CONSTANT;
let mut _string = STRING;
let mut _vec = VEC;
let mut _nested = NESTED;
- let mut _extern = MUTEX_INIT;
+ let mut _extern = StaticMutex::new();
let mut _unsafe_cell = UNSAFE_CELL;
}
+++ /dev/null
-// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// ignore-windows failing on win32 bot
-// ignore-freebsd: gdb package too new
-// ignore-lldb
-// ignore-android: FIXME(#10381)
-// compile-flags:-g
-// min-gdb-version 7.7
-
-// gdb-command: run
-
-// gdb-command: print slice
-// gdb-check:$1 = &[i32](len: 4) = {0, 1, 2, 3}
-
-// gdb-command: print vec
-// gdb-check:$2 = Vec<u64>(len: 4, cap: [...]) = {4, 5, 6, 7}
-
-// gdb-command: print str_slice
-// gdb-check:$3 = "IAMA string slice!"
-
-// gdb-command: print string
-// gdb-check:$4 = "IAMA string!"
-
-// gdb-command: print some
-// gdb-check:$5 = Some = {8}
-
-// gdb-command: print none
-// gdb-check:$6 = None
-
-#![allow(unused_variables)]
-
-fn main() {
-
- // &[]
- let slice: &[i32] = &[0, 1, 2, 3];
-
- // Vec
- let vec = vec![4u64, 5, 6, 7];
-
- // &str
- let str_slice = "IAMA string slice!";
-
- // String
- let string = "IAMA string!".to_string();
-
- // Option
- let some = Some(8i16);
- let none: Option<i64> = None;
-
- zzz(); // #break
-}
-
-fn zzz() { () }
+++ /dev/null
-// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// ignore-windows failing on win32 bot
-// ignore-freebsd: output doesn't match
-// ignore-tidy-linelength
-// ignore-lldb
-// ignore-android: FIXME(#10381)
-// compile-flags:-g
-
-// This test uses some GDB Python API features (e.g. accessing anonymous fields)
-// which are only available in newer GDB version. The following directive will
-// case the test runner to ignore this test if an older GDB version is used:
-// min-gdb-version 7.7
-
-// gdb-command: run
-
-// gdb-command: print regular_struct
-// gdb-check:$1 = RegularStruct = {the_first_field = 101, the_second_field = 102.5, the_third_field = false, the_fourth_field = "I'm so pretty, oh so pretty..."}
-
-// gdb-command: print tuple
-// gdb-check:$2 = {true, 103, "blub"}
-
-// gdb-command: print tuple_struct
-// gdb-check:$3 = TupleStruct = {-104.5, 105}
-
-// gdb-command: print empty_struct
-// gdb-check:$4 = EmptyStruct
-
-// gdb-command: print c_style_enum1
-// gdb-check:$5 = CStyleEnumVar1
-
-// gdb-command: print c_style_enum2
-// gdb-check:$6 = CStyleEnumVar2
-
-// gdb-command: print c_style_enum3
-// gdb-check:$7 = CStyleEnumVar3
-
-// gdb-command: print mixed_enum_c_style_var
-// gdb-check:$8 = MixedEnumCStyleVar
-
-// gdb-command: print mixed_enum_tuple_var
-// gdb-check:$9 = MixedEnumTupleVar = {106, 107, false}
-
-// gdb-command: print mixed_enum_struct_var
-// gdb-check:$10 = MixedEnumStructVar = {field1 = 108.5, field2 = 109}
-
-// gdb-command: print some
-// gdb-check:$11 = Some = {110}
-
-// gdb-command: print none
-// gdb-check:$12 = None
-
-// gdb-command: print some_fat
-// gdb-check:$13 = Some = {"abc"}
-
-// gdb-command: print none_fat
-// gdb-check:$14 = None
-
-// gdb-command: print nested_variant1
-// gdb-check:$15 = NestedVariant1 = {NestedStruct = {regular_struct = RegularStruct = {the_first_field = 111, the_second_field = 112.5, the_third_field = true, the_fourth_field = "NestedStructString1"}, tuple_struct = TupleStruct = {113.5, 114}, empty_struct = EmptyStruct, c_style_enum = CStyleEnumVar2, mixed_enum = MixedEnumTupleVar = {115, 116, false}}}
-
-// gdb-command: print nested_variant2
-// gdb-check:$16 = NestedVariant2 = {abc = NestedStruct = {regular_struct = RegularStruct = {the_first_field = 117, the_second_field = 118.5, the_third_field = false, the_fourth_field = "NestedStructString10"}, tuple_struct = TupleStruct = {119.5, 120}, empty_struct = EmptyStruct, c_style_enum = CStyleEnumVar3, mixed_enum = MixedEnumStructVar = {field1 = 121.5, field2 = -122}}}
-
-// gdb-command: print none_check1
-// gdb-check:$17 = None
-
-// gdb-command: print none_check2
-// gdb-check:$18 = None
-
-#![allow(dead_code, unused_variables)]
-
-use self::CStyleEnum::{CStyleEnumVar1, CStyleEnumVar2, CStyleEnumVar3};
-use self::MixedEnum::{MixedEnumCStyleVar, MixedEnumTupleVar, MixedEnumStructVar};
-use self::NestedEnum::{NestedVariant1, NestedVariant2};
-
-struct RegularStruct {
- the_first_field: isize,
- the_second_field: f64,
- the_third_field: bool,
- the_fourth_field: &'static str,
-}
-
-struct TupleStruct(f64, i16);
-
-struct EmptyStruct;
-
-enum CStyleEnum {
- CStyleEnumVar1,
- CStyleEnumVar2,
- CStyleEnumVar3,
-}
-
-enum MixedEnum {
- MixedEnumCStyleVar,
- MixedEnumTupleVar(u32, u16, bool),
- MixedEnumStructVar { field1: f64, field2: i32 }
-}
-
-struct NestedStruct {
- regular_struct: RegularStruct,
- tuple_struct: TupleStruct,
- empty_struct: EmptyStruct,
- c_style_enum: CStyleEnum,
- mixed_enum: MixedEnum,
-}
-
-enum NestedEnum {
- NestedVariant1(NestedStruct),
- NestedVariant2 { abc: NestedStruct }
-}
-
-fn main() {
-
- let regular_struct = RegularStruct {
- the_first_field: 101,
- the_second_field: 102.5,
- the_third_field: false,
- the_fourth_field: "I'm so pretty, oh so pretty..."
- };
-
- let tuple = ( true, 103u32, "blub" );
-
- let tuple_struct = TupleStruct(-104.5, 105);
-
- let empty_struct = EmptyStruct;
-
- let c_style_enum1 = CStyleEnumVar1;
- let c_style_enum2 = CStyleEnumVar2;
- let c_style_enum3 = CStyleEnumVar3;
-
- let mixed_enum_c_style_var = MixedEnumCStyleVar;
- let mixed_enum_tuple_var = MixedEnumTupleVar(106, 107, false);
- let mixed_enum_struct_var = MixedEnumStructVar { field1: 108.5, field2: 109 };
-
- let some = Some(110_usize);
- let none: Option<isize> = None;
- let some_fat = Some("abc");
- let none_fat: Option<&'static str> = None;
-
- let nested_variant1 = NestedVariant1(
- NestedStruct {
- regular_struct: RegularStruct {
- the_first_field: 111,
- the_second_field: 112.5,
- the_third_field: true,
- the_fourth_field: "NestedStructString1",
- },
- tuple_struct: TupleStruct(113.5, 114),
- empty_struct: EmptyStruct,
- c_style_enum: CStyleEnumVar2,
- mixed_enum: MixedEnumTupleVar(115, 116, false)
- }
- );
-
- let nested_variant2 = NestedVariant2 {
- abc: NestedStruct {
- regular_struct: RegularStruct {
- the_first_field: 117,
- the_second_field: 118.5,
- the_third_field: false,
- the_fourth_field: "NestedStructString10",
- },
- tuple_struct: TupleStruct(119.5, 120),
- empty_struct: EmptyStruct,
- c_style_enum: CStyleEnumVar3,
- mixed_enum: MixedEnumStructVar {
- field1: 121.5,
- field2: -122
- }
- }
- };
-
- let none_check1: Option<(usize, Vec<usize>)> = None;
- let none_check2: Option<String> = None;
-
- zzz(); // #break
-}
-
-fn zzz() { () }
+++ /dev/null
-// ignore-test
-
-// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// compile-flags:-g
-// gdb-command:run
-
-// gdb-command:print arg1
-// gdb-check:$1 = 1000
-// gdb-command:print *arg2
-// gdb-check:$2 = {1, 2.5}
-// gdb-command:continue
-
-// gdb-command:print arg1
-// gdb-check:$3 = 2000
-// gdb-command:print *arg2
-// gdb-check:$4 = {3.5, {4, 5, 6}}
-// gdb-command:continue
-
-#![omit_gdb_pretty_printer_section]
-
-struct Struct {
- x: isize
-}
-
-trait Trait<T1> {
- fn generic_static_default_method<T2>(arg1: isize, arg2: &(T1, T2)) -> isize {
- zzz(); // #break
- arg1
- }
-}
-
-impl<T> Trait<T> for Struct {}
-
-fn main() {
-
- // Is this really how to use these?
- Trait::generic_static_default_method::<isize, Struct, float>(1000, &(1, 2.5));
- Trait::generic_static_default_method::<float, Struct, (isize, isize, isize)>(2000,
- &(3.5, (4, 5, 6)));
-
-}
-
-fn zzz() {()}
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// This test was actually never run before because commands were only parsed up to the first
-// function definition but the test relied on the function being above the commands. Ignore for now.
-// ignore-test
-
-fn main() {
- let args : Vec<String> = ::std::os::args();
- ::std::io::println(args[0]);
-}
-
-// ignore-lldb
-
-// This test case checks whether compile unit names are set correctly, so that the correct default
-// source file can be found.
-
-// compile-flags:-g
-// gdb-command:list
-// gdb-check:1[...]fn main() {
-// gdb-check:2[...]let args : Vec<String> = ::std::os::args();
-// gdb-check:3[...]::std::io::println(args[0]);
-// gdb-check:4[...]}
// lldb-check:[...]$5 = Void
// lldb-command:print some_str
-// lldb-check:[...]$6 = Some(&str { data_ptr: [...], length: 3 })
+// lldb-check:[...]$6 = Some("abc")
// lldb-command:print none_str
// lldb-check:[...]$7 = None
--- /dev/null
+// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-windows failing on win32 bot
+// ignore-freebsd: gdb package too new
+// ignore-android: FIXME(#10381)
+// compile-flags:-g
+// min-gdb-version 7.7
+// min-lldb-version: 310
+
+// === GDB TESTS ===================================================================================
+
+// gdb-command: run
+
+// gdb-command: print slice
+// gdb-check:$1 = &[i32](len: 4) = {0, 1, 2, 3}
+
+// gdb-command: print vec
+// gdb-check:$2 = Vec<u64>(len: 4, cap: [...]) = {4, 5, 6, 7}
+
+// gdb-command: print str_slice
+// gdb-check:$3 = "IAMA string slice!"
+
+// gdb-command: print string
+// gdb-check:$4 = "IAMA string!"
+
+// gdb-command: print some
+// gdb-check:$5 = Some = {8}
+
+// gdb-command: print none
+// gdb-check:$6 = None
+
+
+// === LLDB TESTS ==================================================================================
+
+// lldb-command: run
+
+// lldb-command: print slice
+// lldb-check:[...]$0 = &[0, 1, 2, 3]
+
+// lldb-command: print vec
+// lldb-check:[...]$1 = vec![4, 5, 6, 7]
+
+// lldb-command: print str_slice
+// lldb-check:[...]$2 = "IAMA string slice!"
+
+// lldb-command: print string
+// lldb-check:[...]$3 = "IAMA string!"
+
+// lldb-command: print some
+// lldb-check:[...]$4 = Some(8)
+
+// lldb-command: print none
+// lldb-check:[...]$5 = None
+
+
+#![allow(unused_variables)]
+
+fn main() {
+
+ // &[]
+ let slice: &[i32] = &[0, 1, 2, 3];
+
+ // Vec
+ let vec = vec![4u64, 5, 6, 7];
+
+ // &str
+ let str_slice = "IAMA string slice!";
+
+ // String
+ let string = "IAMA string!".to_string();
+
+ // Option
+ let some = Some(8i16);
+ let none: Option<i64> = None;
+
+ zzz(); // #break
+}
+
+fn zzz() { () }
#![allow(unused_variables)]
#![omit_gdb_pretty_printer_section]
-#![feature(core)]
+#![feature(core_simd)]
use std::simd::{i8x16, i16x8,i32x4,i64x2,u8x16,u16x8,u32x4,u64x2,f32x4,f64x2};
+++ /dev/null
-// ignore-test
-
-// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// compile-flags:-g
-
-// === GDB TESTS ===================================================================================
-
-// gdb-command:run
-
-// gdb-command:print arg1
-// gdb-check:$1 = 1000
-// gdb-command:print arg2
-// gdb-check:$2 = 0.5
-// gdb-command:continue
-
-// gdb-command:print arg1
-// gdb-check:$3 = 2000
-// gdb-command:print *arg2
-// gdb-check:$4 = {1, 2, 3}
-// gdb-command:continue
-
-
-// === LLDB TESTS ==================================================================================
-
-// lldb-command:run
-
-// lldb-command:print arg1
-// lldb-check:[...]$0 = 1000
-// lldb-command:print arg2
-// lldb-check:[...]$1 = 0.5
-// lldb-command:continue
-
-// lldb-command:print arg1
-// lldb-check:[...]$2 = 2000
-// lldb-command:print *arg2
-// lldb-check:[...]$3 = (1, 2, 3)
-// lldb-command:continue
-
-#![omit_gdb_pretty_printer_section]
-
-struct Struct {
- x: isize
-}
-
-trait Trait {
- fn generic_static_default_method<T>(arg1: isize, arg2: T) -> isize {
- zzz(); // #break
- arg1
- }
-}
-
-impl Trait for Struct {}
-
-fn main() {
-
- // Is this really how to use these?
- Trait::generic_static_default_method::<Struct, float>(1000, 0.5);
- Trait::generic_static_default_method::<Struct, &(isize, isize, isize)>(2000, &(1, 2, 3));
-
-}
-
-fn zzz() {()}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+extern crte foo; //~ ERROR expected one of `crate`, `fn`, or `{`, found `crte`
// Verifies that the expected token errors for `extern crate` are
// raised
-extern "C" mod foo; //~ERROR expected `{` or `fn`, found `mod`
+extern "C" mod foo; //~ERROR expected one of `fn` or `{`, found `mod`
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// compile-flags: -Z parse-only
-
-// ignore-test FIXME(japari) remove test
-
-struct Foo {
- f: for <'b> |&'b isize|:
- 'b -> &'b isize //~ ERROR use of undeclared lifetime name `'b`
-}
-
-fn main() {
- let mut x: Vec< for <'a> ||
- :'a //~ ERROR use of undeclared lifetime name `'a`
- > = Vec::new();
- x.push(|| {});
-
- let foo = Foo {
- f: |x| x
- };
-}
// compile-flags: -Z parse-only
fn main() {
- assert!(1 == 2)
- assert!(3 == 4) //~ ERROR expected one of `.`, `;`, `}`, or an operator, found `assert`
+ assert_eq!(1, 2)
+ assert_eq!(3, 4) //~ ERROR expected one of `.`, `;`, `}`, or an operator, found `assert_eq`
println!("hello");
}
// compile-flags: -Z parse-only
trait A {
- fn foo(*mut self); //~ ERROR cannot pass self by unsafe pointer
- fn bar(*self); //~ ERROR cannot pass self by unsafe pointer
+ fn foo(*mut self); //~ ERROR cannot pass self by raw pointer
+ fn bar(*self); //~ ERROR cannot pass self by raw pointer
}
struct X;
impl A for X {
- fn foo(*mut self) { } //~ ERROR cannot pass self by unsafe pointer
- fn bar(*self) { } //~ ERROR cannot pass self by unsafe pointer
+ fn foo(*mut self) { } //~ ERROR cannot pass self by raw pointer
+ fn bar(*self) { } //~ ERROR cannot pass self by raw pointer
}
fn main() { }
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// compile-flags: -Z parse-only
-
-// ignore-test
-// ignored because the first error does not show up.
-
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// compile-flags: -Z parse-only
-
-fn of<T>() -> |T| { panic!(); }
-fn subtype<T>(x: |T|) { panic!(); }
-
-fn test_fn<'x, 'y, 'z, T>(_x: &'x T, _y: &'y T, _z: &'z T) {
- // Here, x, y, and z are free. Other letters
- // are bound. Note that the arrangement
- // subtype::<T1>(of::<T2>()) will typecheck
- // iff T1 <: T2.
-
- // should be the default:
- subtype::< ||:'static>(of::<||>());
- subtype::<||>(of::< ||:'static>());
-
- //
- subtype::< <'x> ||>(of::<||>()); //~ ERROR mismatched types
- subtype::< <'x> ||>(of::< <'y> ||>()); //~ ERROR mismatched types
-
- subtype::< <'x> ||>(of::< ||:'static>()); //~ ERROR mismatched types
- subtype::< ||:'static>(of::< <'x> ||>());
-
-}
-
-fn main() {}
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// ignore-test
-// ignored due to problems with by value self.
-
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// compile-flags: -Z parse-only
-
-// Here: foo is parameterized because it contains a method that
-// refers to self.
-
-trait foo<'a> {
- fn self_int(self) -> &'a isize;
-
- fn any_int(self) -> &isize;
-}
-
-struct with_foo<'a> {
- f: @foo<'a>
-}
-
-trait set_foo_foo {
- fn set_foo(&mut self, f: @foo);
-}
-
-impl<'a> set_foo_foo for with_foo<'a> {
- fn set_foo(&mut self, f: @foo) {
- self.f = f; //~ ERROR mismatched types: expected `@foo/&self`, found `@foo/&`
- }
-}
-
-// Bar is not region parameterized.
-
-trait bar {
- fn any_int(&self) -> &isize;
-}
-
-struct with_bar {
- f: bar
-}
-
-trait set_foo_bar {
- fn set_foo(&mut self, f: bar);
-}
-
-impl set_foo_bar for with_bar {
- fn set_foo(&mut self, f: bar) {
- self.f = f;
- }
-}
-
-fn main() {}
+++ /dev/null
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// compile-flags: -Z parse-only
-
-// ignore-test #5723
-
-// Test that you cannot escape a reference
-// into a trait.
-
-struct ctxt { v: usize }
-
-trait get_ctxt {
- fn get_ctxt(&self) -> &'a ctxt;
-}
-
-struct has_ctxt<'a> { c: &'a ctxt }
-
-impl<'a> get_ctxt for has_ctxt<'a> {
- fn get_ctxt(&self) -> &'a ctxt { self.c }
-}
-
-fn make_gc() -> @get_ctxt {
- let ctxt = ctxt { v: 22 };
- let hc = has_ctxt { c: &ctxt };
- return @hc as @get_ctxt;
- //~^ ERROR source contains reference
-}
-
-fn main() {
- make_gc().get_ctxt().v;
-}
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// ignore-test
-// ignore'd due to problems with by-value self.
-
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// compile-flags: -Z parse-only
-
-trait get_ctxt<'a> {
- fn get_ctxt(self) -> &'a usize;
-}
-
-fn make_gc1(gc: @get_ctxt<'a>) -> @get_ctxt<'b> {
- return gc; //~ ERROR mismatched types: expected `@get_ctxt/&b`, found `@get_ctxt/&a`
-}
-
-struct Foo {
- r: &'a usize
-}
-
-impl get_ctxt for Foo<'a> {
- fn get_ctxt(&self) -> &'a usize { self.r }
-}
-
-fn make_gc2<'a,'b>(foo: Foo<'a>) -> @get_ctxt<'b> {
- return @foo as @get_ctxt; //~ ERROR cannot infer
-}
-
-fn main() {
-}
fn f<F>(f: F) where F: Fn(isize) { f(10) }
-fn main() { f(|i| { assert!(i == 10) }) }
+fn main() { f(|i| { assert_eq!(i , 10) }) }
+++ /dev/null
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// ignore-test
-// pp-exact
-struct Thing {
- x: isize,
- y: isize,
-}
-
-fn main() {
- let sth = Thing{x: 0, y: 1,};
- let sth2 = Thing{y: 9 , ..sth};
- assert_eq!(sth.x + sth2.y, 9);
-}
use syntax::print::pprust;
fn main() {
- let ps = syntax::parse::new_parse_sess();
+ let ps = syntax::parse::ParseSess::new();
let mut cx = syntax::ext::base::ExtCtxt::new(
&ps, vec![],
syntax::ext::expand::ExpansionConfig::default("qquote".to_string()));
+++ /dev/null
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// ignore-test
-// error-pattern:index out of bounds
-
-use std::usize;
-
-fn main() {
- let x = vec!(1_usize,2_usize,3_usize);
-
- // This should cause a bounds-check panic, but may not if we do our
- // bounds checking by comparing a scaled index value to the vector's
- // length (in bytes), because the scaling of the index will cause it to
- // wrap around to a small number.
-
- let idx = usize::MAX & !(usize::MAX >> 1_usize);
- println!("ov2 idx = 0x%x", idx);
-
- // This should panic.
- println!("ov2 0x%x", x[idx]);
-}
+++ /dev/null
-// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// ignore-test
-// error-pattern:index out of bounds
-
-use std::u64;
-
-#[cfg(target_arch="x86")]
-fn main() {
- let x = vec!(1_usize,2_usize,3_usize);
-
- // This should cause a bounds-check panic, but may not if we do our
- // bounds checking by truncating the index value to the size of the
- // machine word, losing relevant bits of the index value.
-
- // This test is only meaningful on 32-bit hosts.
-
- let idx = u64::MAX & !(u64::MAX >> 1_usize);
- println!("ov3 idx = 0x%8.8x%8.8x",
- (idx >> 32) as usize,
- idx as usize);
-
- // This should panic.
- println!("ov3 0x%x", x[idx]);
-}
-
-#[cfg(any(target_arch="x86_64", target_arch = "aarch64"))]
-fn main() {
- // This version just panics anyways, for symmetry on 64-bit hosts.
- let x = vec!(1_usize,2_usize,3_usize);
- error!("ov3 0x%x", x[200]);
-}
+++ /dev/null
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// ignore-test linked failure
-// error-pattern:explicit failure
-// Testing that runtime failure doesn't cause callbacks to abort abnormally.
-// Instead the failure will be delivered after the callbacks return.
-#![feature(std_misc, libc)]
-
-extern crate libc;
-use std::task;
-
-mod rustrt {
- extern crate libc;
-
- extern {
- pub fn rust_dbg_call(cb: *u8, data: libc::uintptr_t)
- -> libc::uintptr_t;
- }
-}
-
-extern fn cb(data: libc::uintptr_t) -> libc::uintptr_t {
- if data == 1 {
- data
- } else {
- count(data - 1) + count(data - 1)
- }
-}
-
-fn count(n: usize) -> usize {
- unsafe {
- task::deschedule();
- rustrt::rust_dbg_call(cb, n)
- }
-}
-
-fn main() {
- for _ in 0..10 {
- task::spawn(move|| {
- let result = count(5);
- println!("result = %?", result);
- panic!();
- });
- }
-}
+++ /dev/null
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// ignore-test
-// error-pattern: thread '<main>' has overflowed its stack
-
-struct R {
- b: isize,
-}
-
-impl Drop for R {
- fn drop(&mut self) {
- let _y = R { b: self.b };
- }
-}
-
-fn main() {
- let _x = R { b: 0 };
-}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// error-pattern:thread '<main>' panicked at 'shift operation overflowed'
+// compile-flags: -C debug-assertions
+
+#![feature(core_simd)]
+
+use std::simd::i32x4;
+
+// (Work around constant-evaluation)
+fn id<T>(x: T) -> T { x }
+
+fn main() {
+ let _x = i32x4(1, 0, 0, 0) << id(i32x4(32, 0, 0, 0));
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// error-pattern:thread '<main>' panicked at 'shift operation overflowed'
+// compile-flags: -C debug-assertions
+
+#![feature(core_simd)]
+
+use std::simd::i32x4;
+
+// (Work around constant-evaluation)
+fn id<T>(x: T) -> T { x }
+
+fn main() {
+ let _x = i32x4(1, 0, 0, 0) << id(i32x4(-1, 0, 0, 0));
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// error-pattern:thread '<main>' panicked at 'shift operation overflowed'
+// compile-flags: -C debug-assertions
+
+#![feature(core_simd)]
+
+use std::simd::u64x2;
+
+// (Work around constant-evaluation)
+fn id<T>(x: T) -> T { x }
+
+fn main() {
+ let _x = u64x2(1, 0) << id(u64x2(64, 0));
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// error-pattern:thread '<main>' panicked at 'shift operation overflowed'
+// compile-flags: -C debug-assertions
+
+// This function is checking that our automatic truncation does not
+// sidestep the overflow checking.
+
+#![feature(core_simd)]
+
+use std::simd::i8x16;
+
+fn eq_i8x16(i8x16(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15): i8x16,
+ i8x16(y0, y1, y2, y3, y4, y5, y6, y7, y8, y9, y10, y11, y12, y13, y14, y15): i8x16)
+ -> bool
+{
+ (x0 == y0) && (x1 == y1) && (x2 == y2) && (x3 == y3)
+ && (x4 == y4) && (x5 == y5) && (x6 == y6) && (x7 == y7)
+ && (x8 == y8) && (x9 == y9) && (x10 == y10) && (x11 == y11)
+ && (x12 == y12) && (x13 == y13) && (x14 == y14) && (x15 == y15)
+}
+
+// (Work around constant-evaluation)
+fn id<T>(x: T) -> T { x }
+
+fn main() {
+ // this signals overflow when checking is on
+ let x = i8x16(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
+ << id(i8x16(17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
+
+ // ... but when checking is off, the fallback will truncate the
+ // input to its lower three bits (= 1). Note that this is *not*
+ // the behavior of the x86 processor for 8- and 16-bit types,
+ // but it is necessary to avoid undefined behavior from LLVM.
+ //
+ // We check that here, by ensuring the result has only been
+ // shifted by one place; if overflow checking is turned off, then
+ // this assertion will pass (and the compiletest driver will
+ // report that the test did not produce the error expected above).
+ assert!(eq_i8x16(x, i8x16(2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)));
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// error-pattern:thread '<main>' panicked at 'shift operation overflowed'
+// compile-flags: -C debug-assertions
+
+#![feature(core_simd)]
+
+use std::simd::i32x4;
+
+// (Work around constant-evaluation)
+fn id<T>(x: T) -> T { x }
+
+fn main() {
+ let _x = i32x4(-1, 0, 0, 0) >> id(i32x4(32, 0, 0, 0));
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// error-pattern:thread '<main>' panicked at 'shift operation overflowed'
+// compile-flags: -C debug-assertions
+
+#![feature(core_simd)]
+
+use std::simd::i32x4;
+
+// (Work around constant-evaluation)
+fn id<T>(x: T) -> T { x }
+
+fn main() {
+ let _x = i32x4(0, 0, 0, -1) >> id(i32x4(0, 0, 0, -1));
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// error-pattern:thread '<main>' panicked at 'shift operation overflowed'
+// compile-flags: -C debug-assertions
+
+#![feature(core_simd)]
+
+use std::simd::i64x2;
+
+// (Work around constant-evaluation)
+fn id<T>(x: T) -> T { x }
+
+fn main() {
+ let _x = i64x2(0, -1) >> id(i64x2(0, 64));
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// error-pattern:thread '<main>' panicked at 'shift operation overflowed'
+// compile-flags: -C debug-assertions
+
+// This function is checking that our (type-based) automatic
+// truncation does not sidestep the overflow checking.
+
+#![feature(core_simd)]
+
+use std::simd::i8x16;
+
+fn eq_i8x16(i8x16(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15): i8x16,
+ i8x16(y0, y1, y2, y3, y4, y5, y6, y7, y8, y9, y10, y11, y12, y13, y14, y15): i8x16)
+ -> bool
+{
+ (x0 == y0) && (x1 == y1) && (x2 == y2) && (x3 == y3)
+ && (x4 == y4) && (x5 == y5) && (x6 == y6) && (x7 == y7)
+ && (x8 == y8) && (x9 == y9) && (x10 == y10) && (x11 == y11)
+ && (x12 == y12) && (x13 == y13) && (x14 == y14) && (x15 == y15)
+}
+
+// (Work around constant-evaluation)
+fn id<T>(x: T) -> T { x }
+
+fn main() {
+ // this signals overflow when checking is on
+ let x = i8x16(2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
+ >> id(i8x16(17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
+
+ // ... but when checking is off, the fallback will truncate the
+ // input to its lower three bits (= 1). Note that this is *not*
+ // the behavior of the x86 processor for 8- and 16-bit types,
+ // but it is necessary to avoid undefined behavior from LLVM.
+ //
+ // We check that here, by ensuring the result is not zero; if
+ // overflow checking is turned off, then this assertion will pass
+ // (and the compiletest driver will report that the test did not
+ // produce the error expected above).
+ assert!(eq_i8x16(x, i8x16(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)));
+}
// except according to those terms.
// error-pattern:1 == 2
-fn main() { assert!((1 == 2)); }
+fn main() { assert!(1 == 2); }
+++ /dev/null
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// ignore-test leaks
-// error-pattern:ran out of stack
-
-// Test that the thread panicks after hitting the recursion limit
-// during unwinding
-
-fn recurse() {
- println!("don't optimize me out");
- recurse();
-}
-
-struct r {
- recursed: *mut bool,
-}
-
-impl Drop for r {
- fn drop(&mut self) {
- unsafe {
- if !*(self.recursed) {
- *(self.recursed) = true;
- recurse();
- }
- }
- }
-}
-
-fn r(recursed: *mut bool) -> r {
- r { recursed: recursed }
-}
-
-fn main() {
- let mut recursed = false;
- let _r = r(&mut recursed);
- recurse();
-}
--- /dev/null
+-include ../tools.mk
+
+# This is a basic test of LLVM ExecutionEngine functionality using compiled
+# Rust code built using the `rustc` crate.
+
+all:
+ $(RUSTC) test.rs
+ $(call RUN,test $(RUSTC))
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(rustc_private)]
+
+extern crate rustc;
+extern crate rustc_driver;
+extern crate rustc_lint;
+extern crate rustc_resolve;
+extern crate syntax;
+
+use std::ffi::{CStr, CString};
+use std::mem::transmute;
+use std::path::PathBuf;
+use std::thread::Builder;
+
+use rustc::ast_map;
+use rustc::llvm;
+use rustc::metadata::cstore::RequireDynamic;
+use rustc::middle::ty;
+use rustc::session::config::{self, basic_options, build_configuration, Input, Options};
+use rustc::session::build_session;
+use rustc_driver::driver;
+use rustc_resolve::MakeGlobMap;
+
+use syntax::diagnostics::registry::Registry;
+
+fn main() {
+ let program = r#"
+ #[no_mangle]
+ pub static TEST_STATIC: i32 = 42;
+ "#;
+
+ let program2 = r#"
+ #[no_mangle]
+ pub fn test_add(a: i32, b: i32) -> i32 { a + b }
+ "#;
+
+ let mut path = match std::env::args().nth(2) {
+ Some(path) => PathBuf::from(&path),
+ None => panic!("missing rustc path")
+ };
+
+ // Remove two segments from rustc path to get sysroot.
+ path.pop();
+ path.pop();
+
+ let mut ee = ExecutionEngine::new(program, path);
+
+ let test_static = match ee.get_global("TEST_STATIC") {
+ Some(g) => g as *const i32,
+ None => panic!("failed to get global")
+ };
+
+ assert_eq!(unsafe { *test_static }, 42);
+
+ ee.add_module(program2);
+
+ let test_add: fn(i32, i32) -> i32;
+
+ test_add = match ee.get_function("test_add") {
+ Some(f) => unsafe { transmute(f) },
+ None => panic!("failed to get function")
+ };
+
+ assert_eq!(test_add(1, 2), 3);
+}
+
+struct ExecutionEngine {
+ ee: llvm::ExecutionEngineRef,
+ modules: Vec<llvm::ModuleRef>,
+ sysroot: PathBuf,
+}
+
+impl ExecutionEngine {
+ pub fn new(program: &str, sysroot: PathBuf) -> ExecutionEngine {
+ let (llmod, deps) = compile_program(program, sysroot.clone())
+ .expect("failed to compile program");
+
+ let ee = unsafe { llvm::LLVMBuildExecutionEngine(llmod) };
+
+ if ee.is_null() {
+ panic!("Failed to create ExecutionEngine: {}", llvm_error());
+ }
+
+ let ee = ExecutionEngine{
+ ee: ee,
+ modules: vec![llmod],
+ sysroot: sysroot,
+ };
+
+ ee.load_deps(&deps);
+ ee
+ }
+
+ pub fn add_module(&mut self, program: &str) {
+ let (llmod, deps) = compile_program(program, self.sysroot.clone())
+ .expect("failed to compile program in add_module");
+
+ unsafe { llvm::LLVMExecutionEngineAddModule(self.ee, llmod); }
+
+ self.modules.push(llmod);
+ self.load_deps(&deps);
+ }
+
+ /// Returns a raw pointer to the named function.
+ pub fn get_function(&mut self, name: &str) -> Option<*const ()> {
+ let s = CString::new(name.as_bytes()).unwrap();
+
+ for &m in &self.modules {
+ let fv = unsafe { llvm::LLVMGetNamedFunction(m, s.as_ptr()) };
+
+ if !fv.is_null() {
+ let fp = unsafe { llvm::LLVMGetPointerToGlobal(self.ee, fv) };
+
+ assert!(!fp.is_null());
+ return Some(fp);
+ }
+ }
+ None
+ }
+
+ /// Returns a raw pointer to the named global item.
+ pub fn get_global(&mut self, name: &str) -> Option<*const ()> {
+ let s = CString::new(name.as_bytes()).unwrap();
+
+ for &m in &self.modules {
+ let gv = unsafe { llvm::LLVMGetNamedGlobal(m, s.as_ptr()) };
+
+ if !gv.is_null() {
+ let gp = unsafe { llvm::LLVMGetPointerToGlobal(self.ee, gv) };
+
+ assert!(!gp.is_null());
+ return Some(gp);
+ }
+ }
+ None
+ }
+
+ /// Loads all dependencies of compiled code.
+ /// Expects a series of paths to dynamic library files.
+ fn load_deps(&self, deps: &[PathBuf]) {
+ for path in deps {
+ let s = match path.as_os_str().to_str() {
+ Some(s) => s,
+ None => panic!(
+ "Could not convert crate path to UTF-8 string: {:?}", path)
+ };
+ let cs = CString::new(s).unwrap();
+
+ let res = unsafe { llvm::LLVMRustLoadDynamicLibrary(cs.as_ptr()) };
+
+ if res == 0 {
+ panic!("Failed to load crate {:?}: {}",
+ path.display(), llvm_error());
+ }
+ }
+ }
+}
+
+impl Drop for ExecutionEngine {
+ fn drop(&mut self) {
+ unsafe { llvm::LLVMDisposeExecutionEngine(self.ee) };
+ }
+}
+
+/// Returns last error from LLVM wrapper code.
+fn llvm_error() -> String {
+ String::from_utf8_lossy(
+ unsafe { CStr::from_ptr(llvm::LLVMRustGetLastError()).to_bytes() })
+ .into_owned()
+}
+
+fn build_exec_options(sysroot: PathBuf) -> Options {
+ let mut opts = basic_options();
+
+ // librustc derives sysroot from the executable name.
+ // Since we are not rustc, we must specify it.
+ opts.maybe_sysroot = Some(sysroot);
+
+ // Prefer faster build time
+ opts.optimize = config::No;
+
+ // Don't require a `main` function
+ opts.crate_types = vec![config::CrateTypeDylib];
+
+ opts
+}
+
+/// Compiles input up to phase 4, translation to LLVM.
+///
+/// Returns the LLVM `ModuleRef` and a series of paths to dynamic libraries
+/// for crates used in the given input.
+fn compile_program(input: &str, sysroot: PathBuf)
+ -> Option<(llvm::ModuleRef, Vec<PathBuf>)> {
+ let input = Input::Str(input.to_string());
+ let thread = Builder::new().name("compile_program".to_string());
+
+ let handle = thread.spawn(move || {
+ let opts = build_exec_options(sysroot);
+ let sess = build_session(opts, None, Registry::new(&rustc::DIAGNOSTICS));
+ rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
+
+ let cfg = build_configuration(&sess);
+
+ let id = "input".to_string();
+
+ let krate = driver::phase_1_parse_input(&sess, cfg, &input);
+
+ let krate = driver::phase_2_configure_and_expand(&sess, krate, &id, None)
+ .expect("phase_2 returned `None`");
+
+ let mut forest = ast_map::Forest::new(krate);
+ let arenas = ty::CtxtArenas::new();
+ let ast_map = driver::assign_node_ids_and_map(&sess, &mut forest);
+
+ driver::phase_3_run_analysis_passes(
+ sess, ast_map, &arenas, id, MakeGlobMap::No, |tcx, analysis| {
+
+ let trans = driver::phase_4_translate_to_llvm(tcx, analysis);
+
+ let crates = tcx.sess.cstore.get_used_crates(RequireDynamic);
+
+ // Collect crates used in the session.
+ // Reverse order finds dependencies first.
+ let deps = crates.into_iter().rev()
+ .filter_map(|(_, p)| p).collect();
+
+ assert_eq!(trans.modules.len(), 1);
+ let llmod = trans.modules[0].llmod;
+
+ // Workaround because raw pointers do not impl Send
+ let modp = llmod as usize;
+
+ (modp, deps)
+ }).1
+ }).unwrap();
+
+ match handle.join() {
+ Ok((llmod, deps)) => Some((llmod as llvm::ModuleRef, deps)),
+ Err(_) => None
+ }
+}
fn t(a: &'static usize) -> usize { a as *const _ as usize }
fn main() {
- assert!(t(a::token()) == t(b::a_token()));
+ assert_eq!(t(a::token()), t(b::a_token()));
assert!(t(a::token()) != t(c::a_token()));
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(std_misc)]
+#![feature(dynamic_lib)]
use std::dynamic_lib::DynamicLibrary;
use std::path::Path;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(asm, core)]
+#![feature(asm, core_intrinsics)]
#![crate_type="lib"]
use std::intrinsics;
--- /dev/null
+-include ../tools.mk
+
+all:
+ $(CC) -std=c99 test.c -c -o $(TMPDIR)/test.o
+ $(AR) rcs $(TMPDIR)/libtest.a $(TMPDIR)/test.o
+ $(RUSTC) test.rs -L $(TMPDIR)
+ $(call RUN,test) || exit 1
--- /dev/null
+// ignore-license
+#include <stddef.h>
+#include <stdint.h>
+
+struct ByteSlice {
+ uint8_t *data;
+ size_t len;
+};
+
+size_t slice_len(struct ByteSlice bs) {
+ return bs.len;
+}
+
+uint8_t slice_elem(struct ByteSlice bs, size_t idx) {
+ return bs.data[idx];
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(libc)]
+
+extern crate libc;
+
+#[link(name = "test")]
+extern {
+ fn slice_len(s: &[u8]) -> libc::size_t;
+ fn slice_elem(s: &[u8], idx: libc::size_t) -> u8;
+}
+
+fn main() {
+ let data = [1,2,3,4,5];
+
+ unsafe {
+ assert_eq!(data.len(), slice_len(&data) as usize);
+ assert_eq!(data[0], slice_elem(&data, 0));
+ assert_eq!(data[1], slice_elem(&data, 1));
+ assert_eq!(data[2], slice_elem(&data, 2));
+ assert_eq!(data[3], slice_elem(&data, 3));
+ assert_eq!(data[4], slice_elem(&data, 4));
+ }
+}
--- /dev/null
+-include ../tools.mk
+
+ifndef IS_WINDOWS
+all: time
+
+time: libc
+ mkdir -p out/time out/time/deps
+ ln -sf out/libc/liblibc.rlib out/time/deps/
+ $(RUSTC) in/time/lib.rs -Ldependency=out/time/deps/
+
+libc:
+ mkdir -p out/libc
+ $(RUSTC) in/libc/lib.rs --crate-name=libc -o out/libc/liblibc.rlib
+else
+all:
+endif
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+#![crate_type="rlib"]
+
+pub fn something(){}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+#![feature(libc)]
+extern crate libc;
+
+fn main(){}
--- /dev/null
+-include ../tools.mk
+
+all:
+ $(RUSTC) -o "" blank.rs 2>&1 | \
+ grep 'No such file or directory'
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {}
}).join().err().unwrap();
unsafe {
- assert!(lib::statik == 1);
- assert!(statik == 1);
+ assert_eq!(lib::statik, 1);
+ assert_eq!(statik, 1);
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(core)]
+#![feature(core_intrinsics)]
use std::intrinsics::{volatile_load, volatile_store};
// we should never get use this filename, but lets make sure they are valid args.
let args = vec!["compiler-calls".to_string(), "foo.rs".to_string()];
rustc_driver::run_compiler(&args, &mut tc);
- assert!(tc.count == 30);
+ assert_eq!(tc.count, 30);
}
let path = {
let mut paths: Vec<_> = env::split_paths(&env::var_os("PATH").unwrap()).collect();
paths.push(child_dir.to_path_buf());
- env::join_paths(paths.iter()).unwrap()
+ env::join_paths(paths).unwrap()
};
let child_output = process::Command::new("mytest").env("PATH", &path)
str::from_utf8(&child_output.stdout).unwrap(),
str::from_utf8(&child_output.stderr).unwrap()));
- fs::remove_dir_all(&child_dir).unwrap();
-
+ let res = fs::remove_dir_all(&child_dir);
+ if res.is_err() {
+ // On Windows deleting just executed mytest.exe can fail because it's still locked
+ std::thread::sleep_ms(1000);
+ fs::remove_dir_all(&child_dir).unwrap();
+ }
}
use syntax::print::pprust::*;
fn main() {
- let ps = syntax::parse::new_parse_sess();
+ let ps = syntax::parse::ParseSess::new();
let mut cx = syntax::ext::base::ExtCtxt::new(
&ps, vec![],
syntax::ext::expand::ExpansionConfig::default("qquote".to_string()));
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(dead_code)]
+#![feature(const_fn)]
+
+// check dtor calling order when casting enums.
+
+use std::sync::atomic;
+use std::sync::atomic::Ordering;
+use std::mem;
+
+enum E {
+ A = 0,
+ B = 1,
+ C = 2
+}
+
+static FLAG: atomic::AtomicUsize = atomic::AtomicUsize::new(0);
+
+impl Drop for E {
+ fn drop(&mut self) {
+ // avoid dtor loop
+ unsafe { mem::forget(mem::replace(self, E::B)) };
+
+ FLAG.store(FLAG.load(Ordering::SeqCst)+1, Ordering::SeqCst);
+ }
+}
+
+fn main() {
+ assert_eq!(FLAG.load(Ordering::SeqCst), 0);
+ {
+ let e = E::C;
+ assert_eq!(e as u32, 2);
+ assert_eq!(FLAG.load(Ordering::SeqCst), 0);
+ }
+ assert_eq!(FLAG.load(Ordering::SeqCst), 1);
+}
let _x: Box<Fat<[Foo]>> = Box::<Fat<[Foo; 3]>>::new(Fat { f: [Foo, Foo, Foo] });
}
unsafe {
- assert!(DROP_RAN == 3);
+ assert_eq!(DROP_RAN, 3);
}
}
pub fn main() {
let i32_c: isize = 0x10101010;
- assert!(i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3) ==
+ assert_eq!(i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3),
i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3));
}
fn f() -> isize { { return 3; } }
-pub fn main() { assert!((f() == 3)); }
+pub fn main() { assert_eq!(f(), 3); }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
#![feature(asm)]
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
unsafe fn next_power_of_2(n: u32) -> u32 {
let mut tmp = n;
asm!("dec $0" : "+rm"(tmp) :: "cc");
- let mut shift = 1_usize;
+ let mut shift = 1_u32;
while shift <= 16 {
asm!(
"shr %cl, $2
pub fn main() {
let x: Vec<isize> = vec!(0,1,2,3);
// Call a method
- x.iterate(|y| { assert!(x[*y as usize] == *y); true });
+ x.iterate(|y| { assert_eq!(x[*y as usize], *y); true });
// Call a parameterized function
assert_eq!(length(x.clone()), x.len());
// Call a parameterized function, with type arguments that require
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(associated_consts)]
+
+struct Foo;
+
+trait HasNum {
+ const NUM: isize;
+}
+impl HasNum for Foo {
+ const NUM: isize = 1;
+}
+
+fn main() {
+ assert!(match 2 {
+ Foo::NUM ... 3 => true,
+ _ => false,
+ });
+ assert!(match 0 {
+ -1 ... <Foo as HasNum>::NUM => true,
+ _ => false,
+ });
+ assert!(match 1 {
+ <Foo as HasNum>::NUM ... <Foo>::NUM => true,
+ _ => false,
+ });
+}
{
fn eq(&self, other: &[B]) -> bool {
self.len() == other.len() &&
- self.iter().zip(other.iter())
- .all(|(a, b)| MyEq::eq(a, b))
+ self.iter().zip(other).all(|(a, b)| MyEq::eq(a, b))
}
}
fn main() {
let v = vec!(1, 2, 3, 4, 5, 6);
- let r =pairwise_sub(v.into_iter());
+ let r = pairwise_sub(v.into_iter());
assert_eq!(r, 9);
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that methods whose impl-trait-ref contains associated types
+// are supported.
+
+trait Device {
+ type Resources;
+}
+struct Foo<D, R>(D, R);
+
+trait Tr {
+ fn present(&self) {}
+}
+
+impl<D: Device> Tr for Foo<D, D::Resources> {
+ fn present(&self) {}
+}
+
+struct Res;
+struct Dev;
+impl Device for Dev {
+ type Resources = Res;
+}
+
+fn main() {
+ let foo = Foo(Dev, Res);
+ foo.present();
+}
// `Item` originates in a where-clause, not the declaration of
// `T`. Issue #20300.
+#![feature(const_fn)]
+
use std::marker::{PhantomData};
-use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT};
+use std::sync::atomic::{AtomicUsize};
use std::sync::atomic::Ordering::SeqCst;
-static COUNTER: AtomicUsize = ATOMIC_USIZE_INIT;
+static COUNTER: AtomicUsize = AtomicUsize::new(0);
// Preamble.
trait Trait { type Item; }
fn boo(&self) -> <Self as Foo>::A;
}
-#[derive(PartialEq)]
+#[derive(PartialEq, Debug)]
pub struct Bar;
impl Foo for isize {
pub fn main() {
let a = 42;
- assert!(foo2(a) == 42);
+ assert_eq!(foo2(a), 42);
let a = Bar;
- assert!(foo2(a) == 43);
+ assert_eq!(foo2(a), 43);
let a = 'a';
foo1(a);
- assert!(foo2(a) == Bar);
+ assert_eq!(foo2(a), Bar);
}
+++ /dev/null
-// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// ignore-test FIXME(#5121)
-
-extern crate rbml;
-extern crate serialize;
-extern crate time;
-
-// These tests used to be separate files, but I wanted to refactor all
-// the common code.
-
-use std::collections::{HashMap, HashSet};
-
-use rbml::reader as EBReader;
-use rbml::writer as EBWriter;
-use std::cmp::Eq;
-use std::cmp;
-use std::io;
-use serialize::{Decodable, Encodable};
-
-fn test_rbml<'a, 'b, A:
- Eq +
- Encodable<EBWriter::Encoder<'a>> +
- Decodable<EBReader::Decoder<'b>>
->(a1: &A) {
- let mut wr = Vec::new();
- let mut rbml_w = EBwriter::Encoder::new(&mut wr);
- a1.encode(&mut rbml_w);
-
- let d: serialize::rbml::Doc<'a> = EBDoc::new(&wr);
- let mut decoder: EBReader::Decoder<'a> = EBreader::Decoder::new(d);
- let a2: A = Decodable::decode(&mut decoder);
- assert!(*a1 == a2);
-}
-
-#[derive(Decodable, Encodable)]
-enum Expr {
- Val(usize),
- Plus(@Expr, @Expr),
- Minus(@Expr, @Expr)
-}
-
-impl cmp::Eq for Expr {
- fn eq(&self, other: &Expr) -> bool {
- match *self {
- Val(e0a) => {
- match *other {
- Val(e0b) => e0a == e0b,
- _ => false
- }
- }
- Plus(e0a, e1a) => {
- match *other {
- Plus(e0b, e1b) => e0a == e0b && e1a == e1b,
- _ => false
- }
- }
- Minus(e0a, e1a) => {
- match *other {
- Minus(e0b, e1b) => e0a == e0b && e1a == e1b,
- _ => false
- }
- }
- }
- }
- fn ne(&self, other: &Expr) -> bool { !(*self).eq(other) }
-}
-
-impl cmp::Eq for Point {
- fn eq(&self, other: &Point) -> bool {
- self.x == other.x && self.y == other.y
- }
- fn ne(&self, other: &Point) -> bool { !(*self).eq(other) }
-}
-
-impl<T:cmp::Eq> cmp::Eq for Quark<T> {
- fn eq(&self, other: &Quark<T>) -> bool {
- match *self {
- Top(ref q) => {
- match *other {
- Top(ref r) => q == r,
- Bottom(_) => false
- }
- },
- Bottom(ref q) => {
- match *other {
- Top(_) => false,
- Bottom(ref r) => q == r
- }
- },
- }
- }
- fn ne(&self, other: &Quark<T>) -> bool { !(*self).eq(other) }
-}
-
-impl cmp::Eq for CLike {
- fn eq(&self, other: &CLike) -> bool {
- (*self) as isize == *other as isize
- }
- fn ne(&self, other: &CLike) -> bool { !self.eq(other) }
-}
-
-#[derive(Decodable, Encodable, Eq)]
-struct Spanned<T> {
- lo: usize,
- hi: usize,
- node: T,
-}
-
-#[derive(Decodable, Encodable)]
-struct SomeStruct { v: Vec<usize> }
-
-#[derive(Decodable, Encodable)]
-struct Point {x: usize, y: usize}
-
-#[derive(Decodable, Encodable)]
-enum Quark<T> {
- Top(T),
- Bottom(T)
-}
-
-#[derive(Decodable, Encodable)]
-enum CLike { A, B, C }
-
-pub fn main() {
- let a = &Plus(@Minus(@Val(3), @Val(10)), @Plus(@Val(22), @Val(5)));
- test_rbml(a);
-
- let a = &Spanned {lo: 0, hi: 5, node: 22};
- test_rbml(a);
-
- let a = &Point {x: 3, y: 5};
- test_rbml(a);
-
- let a = &Top(22);
- test_rbml(a);
-
- let a = &Bottom(222);
- test_rbml(a);
-
- let a = &A;
- test_rbml(a);
-
- let a = &B;
- test_rbml(a);
-
- let a = &time::now();
- test_rbml(a);
-
- test_rbml(&1.0f32);
- test_rbml(&1.0f64);
- test_rbml(&'a');
-
- let mut a = HashMap::new();
- test_rbml(&a);
- a.insert(1, 2);
- test_rbml(&a);
-
- let mut a = HashSet::new();
- test_rbml(&a);
- a.insert(1);
- test_rbml(&a);
-}
let inner_pos = pos!(); aux::callback_inlined(|aux_pos| {
check!(counter; main_pos, outer_pos, inner_pos, aux_pos);
});
-
- // this tests a distinction between two independent calls to the inlined function.
- // (un)fortunately, LLVM somehow merges two consecutive such calls into one node.
- inner_further_inlined(counter, main_pos, outer_pos, pos!());
}
#[inline(never)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(std_misc, collections, catch_panic, rand)]
+#![feature(std_misc, collections, catch_panic, rand, sync_poison)]
use std::__rand::{thread_rng, Rng};
use std::thread;
// pretty-expanded FIXME #23616
-#![allow(unknown_features)]
-#![feature(box_syntax, collections)]
+#![feature(bitvec)]
-extern crate collections;
use std::collections::BitVec;
fn bitv_test() {
- let mut v1: Box<_> = box BitVec::from_elem(31, false);
- let v2: Box<_> = box BitVec::from_elem(31, true);
- v1.union(&*v2);
+ let mut v1 = BitVec::from_elem(31, false);
+ let v2 = BitVec::from_elem(31, true);
+ v1.union(&v2);
}
pub fn main() {
assert!(true >= false);
assert!(!(true <= false));
- assert!(true.cmp(&true) == Equal);
- assert!(false.cmp(&false) == Equal);
- assert!(true.cmp(&false) == Greater);
- assert!(false.cmp(&true) == Less);
+ assert_eq!(true.cmp(&true), Equal);
+ assert_eq!(false.cmp(&false), Equal);
+ assert_eq!(true.cmp(&false), Greater);
+ assert_eq!(false.cmp(&true), Less);
}
+++ /dev/null
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// ignore-test FIXME (#6268) nested method calls
-
-// Test that (safe) nested calls with `&mut` receivers are permitted.
-
-struct Foo {a: usize, b: usize}
-
-impl Foo {
- pub fn inc_a(&mut self, v: usize) { self.a += v; }
-
- pub fn next_b(&mut self) -> usize {
- let b = self.b;
- self.b += 1;
- b
- }
-}
-
-pub fn main() {
- let mut f = Foo {a: 22, b: 23};
- f.inc_a(f.next_b());
- assert_eq!(f.a, 22+23);
- assert_eq!(f.b, 24);
-}
// Test that we cleanup a fixed size Box<[D; k]> properly when D has a
// destructor.
+#![feature(const_fn)]
+
use std::thread;
-use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
+use std::sync::atomic::{AtomicUsize, Ordering};
-static LOG: AtomicUsize = ATOMIC_USIZE_INIT;
+static LOG: AtomicUsize = AtomicUsize::new(0);
struct D(u8);
// Test that we cleanup dynamic sized Box<[D]> properly when D has a
// destructor.
+#![feature(const_fn)]
+
use std::thread;
-use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
+use std::sync::atomic::{AtomicUsize, Ordering};
-static LOG: AtomicUsize = ATOMIC_USIZE_INIT;
+static LOG: AtomicUsize = AtomicUsize::new(0);
struct D(u8);
pub fn main() {
let (tx, rx) = channel();
foo(31337, tx);
- assert!(rx.recv().unwrap() == 31337);
+ assert_eq!(rx.recv().unwrap(), 31337);
}
use std::sync::mpsc::{channel, Sender, Receiver};
use trait_superkinds_in_metadata::{RequiresRequiresShareAndSend, RequiresShare};
-#[derive(PartialEq)]
+#[derive(PartialEq, Debug)]
struct X<T>(T);
impl <T: Sync> RequiresShare for X<T> { }
pub fn main() {
let (tx, rx): (Sender<X<isize>>, Receiver<X<isize>>) = channel();
foo(X(31337), tx);
- assert!(rx.recv().unwrap() == X(31337));
+ assert_eq!(rx.recv().unwrap(), X(31337));
}
pub fn main() {
let (tx, rx): (Sender<isize>, Receiver<isize>) = channel();
foo(31337, tx);
- assert!(rx.recv().unwrap() == 31337);
+ assert_eq!(rx.recv().unwrap(), 31337);
}
pub fn main() {
let (tx, rx) = channel();
1193182.foo(tx);
- assert!(rx.recv().unwrap() == 1193182);
+ assert_eq!(rx.recv().unwrap(), 1193182);
}
pub fn main() {
assert_eq!(atol("1024".to_string()) * 10, atol("10240".to_string()));
- assert!((atoll("11111111111111111".to_string()) * 10) ==
+ assert_eq!((atoll("11111111111111111".to_string()) * 10),
atoll("111111111111111110".to_string()));
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Check that you can cast between different pointers to trait objects
+// whose vtable have the same kind (both lengths, or both trait pointers).
+
+trait Foo<T> {
+ fn foo(&self, _: T) -> u32 { 42 }
+}
+
+trait Bar {
+ fn bar(&self) { println!("Bar!"); }
+}
+
+impl<T> Foo<T> for () {}
+impl Foo<u32> for u32 { fn foo(&self, _: u32) -> u32 { self+43 } }
+impl Bar for () {}
+
+unsafe fn round_trip_and_call<'a>(t: *const (Foo<u32>+'a)) -> u32 {
+ let foo_e : *const Foo<u16> = t as *const _;
+ let r_1 = foo_e as *mut Foo<u32>;
+
+ (&*r_1).foo(0)
+}
+
+#[repr(C)]
+struct FooS<T:?Sized>(T);
+#[repr(C)]
+struct BarS<T:?Sized>(T);
+
+fn foo_to_bar<T:?Sized>(u: *const FooS<T>) -> *const BarS<T> {
+ u as *const BarS<T>
+}
+
+fn main() {
+ let x = 4u32;
+ let y : &Foo<u32> = &x;
+ let fl = unsafe { round_trip_and_call(y as *const Foo<u32>) };
+ assert_eq!(fl, (43+4));
+
+ let s = FooS([0,1,2]);
+ let u: &FooS<[u32]> = &s;
+ let u: *const FooS<[u32]> = u;
+ let bar_ref : *const BarS<[u32]> = foo_to_bar(u);
+ let z : &BarS<[u32]> = unsafe{&*bar_ref};
+ assert_eq!(&z.0, &[0,1,2]);
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(dead_code)]
+
+use std::vec;
+
+enum Simple {
+ A,
+ B,
+ C
+}
+
+enum Valued {
+ H8=163,
+ Z=0,
+ X=256,
+ H7=67,
+}
+
+enum ValuedSigned {
+ M1=-1,
+ P1=1
+}
+
+fn main()
+{
+ // coercion-cast
+ let mut it = vec![137].into_iter();
+ let itr: &mut vec::IntoIter<u32> = &mut it;
+ assert_eq!((itr as &mut Iterator<Item=u32>).next(), Some(137));
+ assert_eq!((itr as &mut Iterator<Item=u32>).next(), None);
+
+ assert_eq!(Some(4u32) as Option<u32>, Some(4u32));
+ assert_eq!((1u32,2u32) as (u32,u32), (1,2));
+
+ // this isn't prim-int-cast. Check that it works.
+ assert_eq!(false as bool, false);
+ assert_eq!(true as bool, true);
+
+ // numeric-cast
+ let l: u64 = 0x8090a0b0c0d0e0f0;
+ let lsz: usize = l as usize;
+ assert_eq!(l as u32, 0xc0d0e0f0);
+
+ // numeric-cast
+ assert_eq!(l as u8, 0xf0);
+ assert_eq!(l as i8,-0x10);
+ assert_eq!(l as u32, 0xc0d0e0f0);
+ assert_eq!(l as u32 as usize as u32, l as u32);
+ assert_eq!(l as i32,-0x3f2f1f10);
+ assert_eq!(l as i32 as isize as i32, l as i32);
+ assert_eq!(l as i64,-0x7f6f5f4f3f2f1f10);
+
+ assert_eq!(0 as f64, 0f64);
+ assert_eq!(1 as f64, 1f64);
+
+ assert_eq!(l as f64, 9264081114510712022f64);
+
+ assert_eq!(l as i64 as f64, -9182662959198838444f64);
+// float overflow : needs fixing
+// assert_eq!(l as f32 as i64 as u64, 9264082620822882088u64);
+// assert_eq!(l as i64 as f32 as i64, 9182664080220408446i64);
+
+ assert_eq!(4294967040f32 as u32, 0xffffff00u32);
+ assert_eq!(1.844674407370955e19f64 as u64, 0xfffffffffffff800u64);
+
+ assert_eq!(9.223372036854775e18f64 as i64, 0x7ffffffffffffc00i64);
+ assert_eq!(-9.223372036854776e18f64 as i64, 0x8000000000000000u64 as i64);
+
+ // addr-ptr-cast/ptr-addr-cast (thin ptr)
+ let p: *const [u8; 1] = lsz as *const [u8; 1];
+ assert_eq!(p as usize, lsz);
+
+ // ptr-ptr-cast (thin ptr)
+ let w: *const () = p as *const ();
+ assert_eq!(w as usize, lsz);
+
+ // ptr-ptr-cast (fat->thin)
+ let u: *const [u8] = unsafe{&*p};
+ assert_eq!(u as *const u8, p as *const u8);
+ assert_eq!(u as *const u16, p as *const u16);
+
+ // ptr-ptr-cast (Length vtables)
+ let mut l : [u8; 2] = [0,1];
+ let w: *mut [u16; 2] = &mut l as *mut [u8; 2] as *mut _;
+ let w: *mut [u16] = unsafe {&mut *w};
+ let w_u8 : *const [u8] = w as *const [u8];
+ assert_eq!(unsafe{&*w_u8}, &l);
+
+ let s: *mut str = w as *mut str;
+ let l_via_str = unsafe{&*(s as *const [u8])};
+ assert_eq!(&l, l_via_str);
+
+ // ptr-ptr-cast (Length vtables, check length is preserved)
+ let l: [[u8; 3]; 2] = [[3, 2, 6], [4, 5, 1]];
+ let p: *const [[u8; 3]] = &l;
+ let p: &[[u8; 2]] = unsafe {&*(p as *const [[u8; 2]])};
+ assert_eq!(p, [[3, 2], [6, 4]]);
+
+ // enum-cast
+ assert_eq!(Simple::A as u8, 0);
+ assert_eq!(Simple::B as u8, 1);
+
+ assert_eq!(Valued::H8 as i8, -93);
+ assert_eq!(Valued::H7 as i8, 67);
+ assert_eq!(Valued::Z as i8, 0);
+
+ assert_eq!(Valued::H8 as u8, 163);
+ assert_eq!(Valued::H7 as u8, 67);
+ assert_eq!(Valued::Z as u8, 0);
+
+ assert_eq!(Valued::H8 as u16, 163);
+ assert_eq!(Valued::Z as u16, 0);
+ assert_eq!(Valued::H8 as u16, 163);
+ assert_eq!(Valued::Z as u16, 0);
+
+ assert_eq!(ValuedSigned::M1 as u16, 65535);
+ assert_eq!(ValuedSigned::M1 as i16, -1);
+ assert_eq!(ValuedSigned::P1 as u16, 1);
+ assert_eq!(ValuedSigned::P1 as i16, 1);
+
+ // prim-int-cast
+ assert_eq!(false as u16, 0);
+ assert_eq!(true as u16, 1);
+ assert_eq!(false as i64, 0);
+ assert_eq!(true as i64, 1);
+ assert_eq!('a' as u32, 0x61);
+ assert_eq!('a' as u16, 0x61);
+ assert_eq!('a' as u8, 0x61);
+ assert_eq!('א' as u8, 0xd0);
+ assert_eq!('א' as u16, 0x5d0);
+ assert_eq!('א' as u32, 0x5d0);
+ assert_eq!('🐵' as u8, 0x35);
+ assert_eq!('🐵' as u16, 0xf435);
+ assert_eq!('🐵' as u32, 0x1f435);
+ assert_eq!('英' as i16, -0x7d0f);
+ assert_eq!('英' as u16, 0x82f1);
+
+ // u8-char-cast
+ assert_eq!(0x61 as char, 'a');
+ assert_eq!(0u8 as char, '\0');
+ assert_eq!(0xd7 as char, '×');
+
+ // array-ptr-cast
+ let x = [1,2,3];
+ let first : *const u32 = &x[0];
+
+ assert_eq!(first, &x as *const _);
+ assert_eq!(first, &x as *const u32);
+
+ // fptr-addr-cast
+ fn foo() {
+ println!("foo!");
+ }
+ fn bar() {
+ println!("bar!");
+ }
+
+ assert!(foo as usize != bar as usize);
+
+ assert_eq!(foo as i16, foo as usize as i16);
+
+ // fptr-ptr-cast
+
+ assert_eq!(foo as *const u8 as usize, foo as usize);
+ assert!(foo as *const u32 != first);
+}
+fn foo() { }
//let bt1 = sys::frame_address();
//println!("%?", bt1);
- //assert!(bt0 == bt1);
+ //assert_eq!(bt0, bt1);
})
}
//println!("%?", bt0);
cci_iter_lib::iter(&[1, 2, 3], |i| {
println!("{}", *i);
- //assert!(bt0 == sys::rusti::frame_address(2));
+ //assert_eq!(bt0, sys::rusti::frame_address(2));
})
}
fn main () {
let b: &[isize] = &[1, 2, 3];
- assert!(ac == b);
- assert!(ad == b);
- assert!(af == b);
+ assert_eq!(ac, b);
+ assert_eq!(ad, b);
+ assert_eq!(af, b);
- assert!(ca == 1);
- assert!(cb == 2);
- assert!(cc == 3);
- assert!(cd == 1);
- assert!(ce == 2);
- assert!(cf == 3);
+ assert_eq!(ca, 1);
+ assert_eq!(cb, 2);
+ assert_eq!(cc, 3);
+ assert_eq!(cd, 1);
+ assert_eq!(ce, 2);
+ assert_eq!(cf, 3);
}
pub fn main() {
let mut nyan: cat<String> = cat::new(0, 2, "nyan".to_string());
for _ in 1_usize..5 { nyan.speak(); }
- assert!(*nyan.find(&1).unwrap() == "nyan".to_string());
+ assert_eq!(*nyan.find(&1).unwrap(), "nyan".to_string());
assert_eq!(nyan.find(&10), None);
let mut spotty: cat<cat_type> = cat::new(2, 57, cat_type::tuxedo);
for _ in 0_usize..6 { spotty.speak(); }
// Test default methods in PartialOrd and PartialEq
//
+#[derive(Debug)]
struct Fool(bool);
impl PartialEq for Fool {
assert!(RevInt(1) >= RevInt(2));
assert!(RevInt(1) >= RevInt(1));
- assert!(Fool(true) == Fool(false));
+ assert_eq!(Fool(true), Fool(false));
assert!(Fool(true) != Fool(true));
assert!(Fool(false) != Fool(false));
- assert!(Fool(false) == Fool(true));
+ assert_eq!(Fool(false), Fool(true));
}
_ => panic!()
}
match Y {
- Foo::Bar(s) => assert!(s == 2654435769),
+ Foo::Bar(s) => assert_eq!(s, 2654435769),
_ => panic!()
}
match Z {
pub fn main() {
match C {
E::S0 { .. } => panic!(),
- E::S1 { u } => assert!(u == 23)
+ E::S1 { u } => assert_eq!(u, 23)
}
}
_ => panic!()
}
match C1 {
- E::V1(n) => assert!(n == 0xDEADBEE),
+ E::V1(n) => assert_eq!(n, 0xDEADBEE),
_ => panic!()
}
_ => panic!()
}
match D1 {
- E::V1(n) => assert!(n == 0xDEADBEE),
+ E::V1(n) => assert_eq!(n, 0xDEADBEE),
_ => panic!()
}
}
pub fn main() {
match C[1] {
- E::V1(n) => assert!(n == 0xDEADBEE),
+ E::V1(n) => assert_eq!(n, 0xDEADBEE),
_ => panic!()
}
match C[2] {
pub fn main() {
match C[1] {
- E::V1(n) => assert!(n == 0xDEADBEE),
+ E::V1(n) => assert_eq!(n, 0xDEADBEE),
_ => panic!()
}
match C[2] {
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:const_fn_lib.rs
+
+// A very basic test of const fn functionality.
+
+#![feature(const_fn)]
+
+extern crate const_fn_lib;
+
+use const_fn_lib::foo;
+
+const FOO: usize = foo();
+
+fn main() {
+ assert_eq!(FOO, 22);
+}
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(const_fn)]
+
+struct Foo { value: u32 }
+
+impl Foo {
+ const fn new() -> Foo {
+ Foo { value: 22 }
+ }
+}
+
+const FOO: Foo = Foo::new();
+
+pub fn main() {
+ assert_eq!(FOO.value, 22);
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test a call whose argument is the result of another call.
+
+#![feature(const_fn)]
+
+const fn sub(x: u32, y: u32) -> u32 {
+ x - y
+}
+
+const X: u32 = sub(sub(88, 44), 22);
+
+fn main() {
+ assert_eq!(X, 22);
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// A very basic test of const fn functionality.
+
+#![feature(const_fn)]
+
+const fn add(x: u32, y: u32) -> u32 {
+ x + y
+}
+
+const fn sub(x: u32, y: u32) -> u32 {
+ x - y
+}
+
+const SUM: u32 = add(44, 22);
+const DIFF: u32 = sub(44, 22);
+
+fn main() {
+ assert_eq!(SUM, 66);
+ assert!(SUM != 88);
+
+ assert_eq!(DIFF, 22);
+
+}
unsafe {
let foo = &A as *const u8;
assert_eq!(str::from_utf8_unchecked(&A), "hi");
- assert!(*C == A[0]);
- assert!(*(&B[0] as *const u8) == A[0]);
+ assert_eq!(*C, A[0]);
+ assert_eq!(*(&B[0] as *const u8), A[0]);
}
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Issue #24644 - block causes a &Trait -> &Trait coercion:
+trait Trait {}
+
+struct Bar;
+impl Trait for Bar {}
+
+fn main() {
+ let x: &[&Trait] = &[{ &Bar }];
+}
+
+// Issue #25748 - the cast causes an &Encoding -> &Encoding coercion:
+pub struct UTF8Encoding;
+pub const UTF_8: &'static UTF8Encoding = &UTF8Encoding;
+pub trait Encoding {}
+impl Encoding for UTF8Encoding {}
+pub fn f() -> &'static Encoding { UTF_8 as &'static Encoding }
+
+// Root of the problem: &Trait -> &Trait coercions:
+const FOO: &'static Trait = &Bar;
+const BAR: &'static Trait = FOO;
+fn foo() { let _x = BAR; }
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// ignore-test
-//
-// Too big for our poor macro infrastructure.
-
-pub fn main() {
- let _x = vec!(
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
- );
-}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// ignore-test
-//
-// Too big for our poor macro infrastructure.
-
-pub fn main() {
- let _x = vec!(
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
- );
-}
if x == 1 { return 1; } else { let y: isize = 1 + f(x - 1); return y; }
}
-pub fn main() { assert!((f(5000) == 5000)); }
+pub fn main() { assert_eq!(f(5000), 5000); }
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(associated_type_defaults)]
+
+trait Foo<T> {
+ type Out = T;
+ fn foo(&self) -> Self::Out;
+}
+
+impl Foo<u32> for () {
+ fn foo(&self) -> u32 {
+ 4u32
+ }
+}
+
+impl Foo<u64> for bool {
+ type Out = ();
+ fn foo(&self) {}
+}
+
+fn main() {
+ assert_eq!(<() as Foo<u32>>::foo(&()), 4u32);
+ assert_eq!(<bool as Foo<u64>>::foo(&true), ());
+}
fn main() {
let x = Rc::new([1, 2, 3, 4]);
- assert!(*x == [1, 2, 3, 4]);
+ assert_eq!(*x, [1, 2, 3, 4]);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(core, debug_builders)]
+#![feature(core)]
pub trait DeclaredTrait {
type Type;
let obj = A { foo: Box::new([true, false]) };
let s = json::encode(&obj).unwrap();
let obj2: A = json::decode(&s).unwrap();
- assert!(obj.foo == obj2.foo);
+ assert_eq!(obj.foo, obj2.foo);
}
};
let s = json::encode(&obj).unwrap();
let obj2: B = json::decode(&s).unwrap();
- assert!(obj.foo.get() == obj2.foo.get());
- assert!(obj.bar.borrow().baz == obj2.bar.borrow().baz);
+ assert_eq!(obj.foo.get(), obj2.foo.get());
+ assert_eq!(obj.bar.borrow().baz, obj2.bar.borrow().baz);
}
+++ /dev/null
-// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// This actually tests a lot more than just encodable/decodable, but it gets the
-// job done at least
-
-// ignore-test FIXME(#5121)
-
-extern crate rand;
-extern crate rbml;
-extern crate serialize;
-
-use rand::{random, Rand};
-use rbml;
-use rbml::Doc;
-use rbml::writer::Encoder;
-use rbml::reader::Decoder;
-use serialize::{Encodable, Decodable};
-
-#[derive(Encodable, Decodable, Eq, Rand)]
-struct A;
-#[derive(Encodable, Decodable, Eq, Rand)]
-struct B(isize);
-#[derive(Encodable, Decodable, Eq, Rand)]
-struct C(isize, isize, usize);
-
-#[derive(Encodable, Decodable, Eq, Rand)]
-struct D {
- a: isize,
- b: usize,
-}
-
-#[derive(Encodable, Decodable, Eq, Rand)]
-enum E {
- E1,
- E2(usize),
- E3(D),
- E4{ x: usize },
-}
-
-#[derive(Encodable, Decodable, Eq, Rand)]
-enum F { F1 }
-
-#[derive(Encodable, Decodable, Eq, Rand)]
-struct G<T> {
- t: T
-}
-
-fn roundtrip<'a, T: Rand + Eq + Encodable<Encoder<'a>> +
- Decodable<Decoder<'a>>>() {
- let obj: T = random();
- let mut w = Vec::new();
- let mut e = Encoder::new(&mut w);
- obj.encode(&mut e);
- let doc = rbml::Doc::new(&w);
- let mut dec = Decoder::new(doc);
- let obj2 = Decodable::decode(&mut dec);
- assert!(obj == obj2);
-}
-
-pub fn main() {
- roundtrip::<A>();
- roundtrip::<B>();
- roundtrip::<C>();
- roundtrip::<D>();
-
- for _ in 0..20 {
- roundtrip::<E>();
- roundtrip::<F>();
- roundtrip::<G<isize>>();
- }
-}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#[derive(PartialEq, PartialOrd, Eq, Ord)]
+#[derive(PartialEq, PartialOrd, Eq, Ord, Debug)]
struct Foo(Box<[u8]>);
pub fn main() {
// FIXME (#22405): Replace `Box::new` with `box` here when/if possible.
let a = Foo(Box::new([0, 1, 2]));
let b = Foo(Box::new([0, 1, 2]));
- assert!(a == b);
+ assert_eq!(a, b);
println!("{}", a != b);
println!("{}", a < b);
println!("{}", a <= b);
// except according to those terms.
-#![feature(hash)]
+#![feature(hash_default)]
use std::hash::{Hash, SipHasher};
name: "Bob".to_string(),
phone: 555_666_7777
};
- assert!(hash(&person1) == hash(&person1));
+ assert_eq!(hash(&person1), hash(&person1));
assert!(hash(&person1) != hash(&person2));
}
+++ /dev/null
-// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// ignore-test FIXME #11820: & is unreliable in deriving
-
-#[derive(Eq,Ord)]
-struct A<'a> {
- x: &'a isize
-}
-
-pub fn main() {
- let a = A { x: &1 };
- let b = A { x: &2 };
-
- assert_eq!(a, a);
- assert_eq!(b, b);
-
-
- assert!(a < b);
- assert!(b > a);
-
- assert!(a <= b);
- assert!(a <= a);
- assert!(b <= b);
-
- assert!(b >= a);
- assert!(b >= b);
- assert!(a >= a);
-}
let a2 = Foo(5, 6, "abc".to_string());
let b = Foo(5, 7, "def".to_string());
- assert!(a1 == a1);
- assert!(a2 == a1);
+ assert_eq!(a1, a1);
+ assert_eq!(a2, a1);
assert!(!(a1 == b));
assert!(a1 != b);
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(core)]
+#![feature(core, core_intrinsics)]
extern crate core;
use core::intrinsics::discriminant_value;
// Test a very simple custom DST coercion.
-#![feature(core)]
+#![feature(unsize, coerce_unsized)]
use std::ops::CoerceUnsized;
use std::marker::Unsize;
#![feature(core)]
+use std::cell::RefCell;
use std::rc::Rc;
trait Baz {
assert_eq!(b.get(), 42);
let _c = b.clone();
+
+ let a: Rc<RefCell<i32>> = Rc::new(RefCell::new(42));
+ let b: Rc<RefCell<Baz>> = a.clone();
+ assert_eq!(b.borrow().get(), 42);
}
pub fn foo(arr: &mut Arr) {
let x: &mut [usize] = &mut **arr;
- assert!(x[0] == 1);
- assert!(x[1] == 2);
- assert!(x[2] == 3);
+ assert_eq!(x[0], 1);
+ assert_eq!(x[1], 2);
+ assert_eq!(x[2], 3);
}
fn main() {
}
pub fn foo(arr: &Arr) {
- assert!(arr.len() == 3);
+ assert_eq!(arr.len(), 3);
let x: &[usize] = &**arr;
- assert!(x[0] == 1);
- assert!(x[1] == 2);
- assert!(x[2] == 3);
+ assert_eq!(x[0], 1);
+ assert_eq!(x[1], 2);
+ assert_eq!(x[2], 3);
}
fn main() {
let r = unsafe {
(&*z).foo()
};
- assert!(r == 42);
+ assert_eq!(r, 42);
// raw DST struct
let p = Foo {f: A { f: 42 }};
let r = unsafe {
(&*o).f.foo()
};
- assert!(r == 42);
+ assert_eq!(r, 42);
// raw slice
let a: *const [_] = &[1, 2, 3];
unsafe {
let b = (*a)[2];
- assert!(b == 3);
+ assert_eq!(b, 3);
let len = (*a).len();
- assert!(len == 3);
+ assert_eq!(len, 3);
}
// raw slice with explicit cast
let a = &[1, 2, 3] as *const [i32];
unsafe {
let b = (*a)[2];
- assert!(b == 3);
+ assert_eq!(b, 3);
let len = (*a).len();
- assert!(len == 3);
+ assert_eq!(len, 3);
}
// raw DST struct with slice
let c: *const Foo<[_]> = &Foo {f: [1, 2, 3]};
unsafe {
let b = (&*c).f[0];
- assert!(b == 1);
+ assert_eq!(b, 1);
let len = (&*c).f.len();
- assert!(len == 3);
+ assert_eq!(len, 3);
}
// all of the above with *mut
let r = unsafe {
(&*z).foo()
};
- assert!(r == 42);
+ assert_eq!(r, 42);
let mut p = Foo {f: A { f: 42 }};
let o: *mut Foo<Trait> = &mut p;
let r = unsafe {
(&*o).f.foo()
};
- assert!(r == 42);
+ assert_eq!(r, 42);
let a: *mut [_] = &mut [1, 2, 3];
unsafe {
let b = (*a)[2];
- assert!(b == 3);
+ assert_eq!(b, 3);
let len = (*a).len();
- assert!(len == 3);
+ assert_eq!(len, 3);
}
let a = &mut [1, 2, 3] as *mut [i32];
unsafe {
let b = (*a)[2];
- assert!(b == 3);
+ assert_eq!(b, 3);
let len = (*a).len();
- assert!(len == 3);
+ assert_eq!(len, 3);
}
let c: *mut Foo<[_]> = &mut Foo {f: [1, 2, 3]};
unsafe {
let b = (&*c).f[0];
- assert!(b == 1);
+ assert_eq!(b, 1);
let len = (&*c).f.len();
- assert!(len == 3);
+ assert_eq!(len, 3);
}
}
// x is a fat pointer
fn foo(x: &Fat<[isize]>) {
let y = &x.ptr;
- assert!(x.ptr.len() == 3);
- assert!(y[0] == 1);
- assert!(x.ptr[1] == 2);
+ assert_eq!(x.ptr.len(), 3);
+ assert_eq!(y[0], 1);
+ assert_eq!(x.ptr[1], 2);
}
fn foo2<T:ToBar>(x: &Fat<[T]>) {
let y = &x.ptr;
let bar = Bar;
- assert!(x.ptr.len() == 3);
- assert!(y[0].to_bar() == bar);
- assert!(x.ptr[1].to_bar() == bar);
+ assert_eq!(x.ptr.len(), 3);
+ assert_eq!(y[0].to_bar(), bar);
+ assert_eq!(x.ptr[1].to_bar(), bar);
}
-#[derive(Copy, Clone, PartialEq, Eq)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
struct Bar;
trait ToBar {
// Assignment.
let f5: &mut Fat<[isize]> = &mut Fat { ptr: [1, 2, 3] };
f5.ptr[1] = 34;
- assert!(f5.ptr[0] == 1);
- assert!(f5.ptr[1] == 34);
- assert!(f5.ptr[2] == 3);
+ assert_eq!(f5.ptr[0], 1);
+ assert_eq!(f5.ptr[1], 34);
+ assert_eq!(f5.ptr[2], 3);
// Zero size vec.
let f5: &Fat<[isize]> = &Fat { ptr: [] };
// x is a fat pointer
fn foo(x: &Fat<[isize]>) {
let y = &x.ptr;
- assert!(x.ptr.len() == 3);
- assert!(y[0] == 1);
- assert!(x.ptr[1] == 2);
- assert!(x.f1 == 5);
- assert!(x.f2 == "some str");
+ assert_eq!(x.ptr.len(), 3);
+ assert_eq!(y[0], 1);
+ assert_eq!(x.ptr[1], 2);
+ assert_eq!(x.f1, 5);
+ assert_eq!(x.f2, "some str");
}
fn foo2<T:ToBar>(x: &Fat<[T]>) {
let y = &x.ptr;
let bar = Bar;
- assert!(x.ptr.len() == 3);
- assert!(y[0].to_bar() == bar);
- assert!(x.ptr[1].to_bar() == bar);
- assert!(x.f1 == 5);
- assert!(x.f2 == "some str");
+ assert_eq!(x.ptr.len(), 3);
+ assert_eq!(y[0].to_bar(), bar);
+ assert_eq!(x.ptr[1].to_bar(), bar);
+ assert_eq!(x.f1, 5);
+ assert_eq!(x.f2, "some str");
}
fn foo3(x: &Fat<Fat<[isize]>>) {
let y = &x.ptr.ptr;
- assert!(x.f1 == 5);
- assert!(x.f2 == "some str");
- assert!(x.ptr.f1 == 8);
- assert!(x.ptr.f2 == "deep str");
- assert!(x.ptr.ptr.len() == 3);
- assert!(y[0] == 1);
- assert!(x.ptr.ptr[1] == 2);
+ assert_eq!(x.f1, 5);
+ assert_eq!(x.f2, "some str");
+ assert_eq!(x.ptr.f1, 8);
+ assert_eq!(x.ptr.f2, "deep str");
+ assert_eq!(x.ptr.ptr.len(), 3);
+ assert_eq!(y[0], 1);
+ assert_eq!(x.ptr.ptr[1], 2);
}
-#[derive(Copy, Clone, PartialEq, Eq)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
struct Bar;
trait ToBar {
// Assignment.
let f5: &mut Fat<[isize]> = &mut Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] };
f5.ptr[1] = 34;
- assert!(f5.ptr[0] == 1);
- assert!(f5.ptr[1] == 34);
- assert!(f5.ptr[2] == 3);
+ assert_eq!(f5.ptr[0], 1);
+ assert_eq!(f5.ptr[1], 34);
+ assert_eq!(f5.ptr[2], 3);
// Zero size vec.
let f5: &Fat<[isize]> = &Fat { f1: 5, f2: "some str", ptr: [] };
// Box.
let f1 = Box::new([1, 2, 3]);
- assert!((*f1)[1] == 2);
+ assert_eq!((*f1)[1], 2);
let f2: Box<[isize]> = f1;
- assert!((*f2)[1] == 2);
+ assert_eq!((*f2)[1], 2);
// Nested Box.
let f1 : Box<Fat<[isize; 3]>> = box Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] };
ptr: T
}
-#[derive(Copy, Clone, PartialEq, Eq)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
struct Bar;
#[derive(Copy, Clone, PartialEq, Eq)]
// x is a fat pointer
fn foo(x: &Fat<ToBar>) {
- assert!(x.f1 == 5);
- assert!(x.f2 == "some str");
- assert!(x.ptr.to_bar() == Bar);
- assert!(x.ptr.to_val() == 42);
+ assert_eq!(x.f1, 5);
+ assert_eq!(x.f2, "some str");
+ assert_eq!(x.ptr.to_bar(), Bar);
+ assert_eq!(x.ptr.to_val(), 42);
let y = &x.ptr;
- assert!(y.to_bar() == Bar);
- assert!(y.to_val() == 42);
+ assert_eq!(y.to_bar(), Bar);
+ assert_eq!(y.to_val(), 42);
}
fn bar(x: &ToBar) {
- assert!(x.to_bar() == Bar);
- assert!(x.to_val() == 42);
+ assert_eq!(x.to_bar(), Bar);
+ assert_eq!(x.to_val(), 42);
}
fn baz(x: &Fat<Fat<ToBar>>) {
- assert!(x.f1 == 5);
- assert!(x.f2 == "some str");
- assert!(x.ptr.f1 == 8);
- assert!(x.ptr.f2 == "deep str");
- assert!(x.ptr.ptr.to_bar() == Bar);
- assert!(x.ptr.ptr.to_val() == 42);
+ assert_eq!(x.f1, 5);
+ assert_eq!(x.f2, "some str");
+ assert_eq!(x.ptr.f1, 8);
+ assert_eq!(x.ptr.f2, "deep str");
+ assert_eq!(x.ptr.ptr.to_bar(), Bar);
+ assert_eq!(x.ptr.ptr.to_val(), 42);
let y = &x.ptr.ptr;
- assert!(y.to_bar() == Bar);
- assert!(y.to_val() == 42);
+ assert_eq!(y.to_bar(), Bar);
+ assert_eq!(y.to_val(), 42);
}
// Zero size object.
let f6: &Fat<ToBar> = &Fat { f1: 5, f2: "some str", ptr: Bar };
- assert!(f6.ptr.to_bar() == Bar);
+ assert_eq!(f6.ptr.to_bar(), Bar);
// &*
//
pub fn main() {
let pet: Animal = Animal::Snake;
let hero: Hero = Hero::Superman;
- assert!(pet as usize == 3);
- assert!(hero as isize == -2);
+ assert_eq!(pet as usize, 3);
+ assert_eq!(hero as isize, -2);
}
}
fn test_color(color: color, val: isize, _name: String) {
- assert!(color as isize == val);
+ assert_eq!(color as isize , val);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
-#![feature(core)]
+#![feature(nonzero, core)]
extern crate core;
let oldhome = var("HOME");
set_var("HOME", "/home/MountainView");
- assert!(home_dir() == Some(PathBuf::from("/home/MountainView")));
+ assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView")));
remove_var("HOME");
if cfg!(target_os = "android") {
assert!(home_dir().is_some());
set_var("HOME", "/home/MountainView");
- assert!(home_dir() == Some(PathBuf::from("/home/MountainView")));
+ assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView")));
remove_var("HOME");
set_var("USERPROFILE", "/home/MountainView");
- assert!(home_dir() == Some(PathBuf::from("/home/MountainView")));
+ assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView")));
set_var("HOME", "/home/MountainView");
set_var("USERPROFILE", "/home/PaloAlto");
- assert!(home_dir() == Some(PathBuf::from("/home/MountainView")));
+ assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView")));
}
// except according to those terms.
-#[derive(PartialEq)]
+#[derive(PartialEq, Debug)]
struct Bar;
+#[derive(Debug)]
struct Baz;
+#[derive(Debug)]
struct Foo;
+#[derive(Debug)]
struct Fu;
impl PartialEq for Baz { fn eq(&self, _: &Baz) -> bool { true } }
assert!(Bar != Foo);
assert!(Foo != Bar);
- assert!(Bar == Bar);
+ assert_eq!(Bar, Bar);
- assert!(Baz == Baz);
+ assert_eq!(Baz, Baz);
- assert!(Foo == Fu);
- assert!(Fu == Foo);
+ assert_eq!(Foo, Fu);
+ assert_eq!(Fu, Foo);
}
+++ /dev/null
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// ignore-test
-
-// Doesn't work; needs a design decision.
-
-pub fn main() {
- let x : [isize; 5] = [1,2,3,4,5];
- let _y : [isize; 5] = [1,2,3,4,5];
- let mut z = [1,2,3,4,5];
- z = x;
- assert_eq!(z[0], 1);
- assert_eq!(z[4], 5);
-
- let a : [isize; 5] = [1,1,1,1,1];
- let b : [isize; 5] = [2,2,2,2,2];
- let c : [isize; 5] = [2,2,2,2,3];
-
- log(debug, a);
-
- assert!(a < b);
- assert!(a <= b);
- assert!(a != b);
- assert!(b >= a);
- assert!(b > a);
-
- log(debug, b);
-
- assert!(b < c);
- assert!(b <= c);
- assert!(b != c);
- assert!(c >= b);
- assert!(c > b);
-
- assert!(a < c);
- assert!(a <= c);
- assert!(a != c);
- assert!(c >= a);
- assert!(c > a);
-
- log(debug, c);
-
-
-}
fn test_fn() {
fn ten() -> isize { return 10; }
let rs = ten;
- assert!((rs() == 10));
+ assert_eq!(rs(), 10);
}
pub fn main() { test_fn(); }
#![allow(unknown_features)]
#![feature(box_syntax)]
-pub fn main() { let x: Box<_> = { box 100 }; assert!((*x == 100)); }
+pub fn main() { let x: Box<_> = { box 100 }; assert_eq!(*x, 100); }
struct RS { v1: isize, v2: isize }
-fn test_rec() { let rs = { RS {v1: 10, v2: 20} }; assert!((rs.v2 == 20)); }
+fn test_rec() { let rs = { RS {v1: 10, v2: 20} }; assert_eq!(rs.v2, 20); }
fn test_filled_with_stuff() {
let rs = { let mut a = 0; while a < 10 { a += 1; } a };
fn test_if_panic() {
let x = if false { panic!() } else { 10 };
- assert!((x == 10));
+ assert_eq!(x, 10);
}
fn test_else_panic() {
struct Point {x: isize, y: isize, z: isize}
fn f(p: &Cell<Point>) {
- assert!((p.get().z == 12));
+ assert_eq!(p.get().z, 12);
p.set(Point {x: 10, y: 11, z: 13});
- assert!((p.get().z == 13));
+ assert_eq!(p.get().z, 13);
}
pub fn main() {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(core)]
+#![feature(raw)]
use std::mem;
use std::raw;
let a: *const [i32] = &[1, 2, 3];
let b = a as *const [i32; 2];
unsafe {
- assert!(*b == [1, 2]);
+ assert_eq!(*b, [1, 2]);
}
// Test conversion to an address (usize).
let a: *const [i32; 3] = &[1, 2, 3];
let b: *const [i32] = a;
- assert!(a as usize == b as usize);
+ assert_eq!(a as usize, b as *const () as usize);
// And conversion to a void pointer/address for trait objects too.
let a: *mut Foo = &mut Bar;
let b = a as *mut ();
- let c = a as usize;
-
+ let c = a as *const () as usize;
let d = unsafe {
let r: raw::TraitObject = mem::transmute(a);
r.data
};
- assert!(b == d);
- assert!(c == d as usize);
+ assert_eq!(b, d);
+ assert_eq!(c, d as usize);
+
}
// pretty-expanded FIXME #23616
-#![feature(lang_items, start, no_std, core, collections)]
+#![feature(lang_items, start, no_std, core_slice_ext, core, collections)]
#![no_std]
extern crate std as other;
}
y += *i;
}
- assert!(y == 11);
+ assert_eq!(y, 11);
}
}
q += *i + p;
}
- assert!(q == 1010100);
+ assert_eq!(q, 1010100);
}
for i in &x[..] {
y += *i
}
- assert!(y == 100);
+ assert_eq!(y, 100);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// pretty-expanded FIXME #23616
-
#![feature(lang_items, start, no_std, core, collections)]
#![no_std]
fn id<T>(x: T) -> T { return x; }
-pub fn main() { let x: isize = 42; let y: isize = id(x); assert!((x == y)); }
+pub fn main() { let x: isize = 42; let y: isize = id(x); assert_eq!(x, y); }
pub fn main() {
let nop: noption<isize> = noption::some::<isize>(5);
- match nop { noption::some::<isize>(n) => { println!("{}", n); assert!((n == 5)); } }
+ match nop { noption::some::<isize>(n) => { println!("{}", n); assert_eq!(n, 5); } }
let nop2: noption<Pair> = noption::some(Pair{x: 17, y: 42});
match nop2 {
noption::some(t) => {
fn mk() -> isize { return 1; }
-fn chk(a: isize) { println!("{}", a); assert!((a == 1)); }
+fn chk(a: isize) { println!("{}", a); assert_eq!(a, 1); }
fn apply<T>(produce: fn() -> T,
consume: fn(T)) {
pub mod foo {
pub fn f() -> isize { return 2; }
- pub fn g() { assert!((f() == 2)); assert!((::f() == 1)); }
+ pub fn g() {
+ assert_eq!(f(), 2);
+ assert_eq!(::f(), 1);
+ }
}
pub fn main() { return foo::g(); }
// A test of the macro system. Can we do HTML literals?
-// ignore-test FIXME #20673
-
/*
This is an HTML parser written as a macro. It's all CPS, and we have
-pub fn main() { let mut x: i32 = -400; x = 0 - x; assert!((x == 400)); }
+pub fn main() { let mut x: i32 = -400; x = 0 - x; assert_eq!(x, 400); }
#![allow(unknown_features)]
#![feature(box_syntax)]
-use std::fmt;
+use std::fmt::{self, Write};
use std::usize;
struct A;
struct B;
struct C;
+struct D;
impl fmt::LowerHex for A {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad_integral(true, "☃", "123")
}
}
+impl fmt::Binary for D {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ try!(f.write_str("aa"));
+ try!(f.write_char('☃'));
+ f.write_str("bb")
+ }
+}
macro_rules! t {
($a:expr, $b:expr) => { assert_eq!($a, $b) }
t!(format!("{foo_bar}", foo_bar=1), "1");
t!(format!("{}", 5 + 5), "10");
t!(format!("{:#4}", C), "☃123");
+ t!(format!("{:b}", D), "aa☃bb");
let a: &fmt::Debug = &1;
t!(format!("{:?}", a), "1");
+++ /dev/null
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-/*
- A simple way to make sure threading works. This should use all the
- CPU cycles an any machines that we're likely to see for a while.
-*/
-// ignore-test
-
-fn loopy(n: isize) {
- if n > 0 { spawn(move|| { loopy(n - 1) }); spawn(move|| { loopy(n - 1) }); }
- loop { }
-}
-
-pub fn main() {
- // Commenting this out, as this will hang forever otherwise.
- // Even after seeing the comment above, I'm not sure what the
- // intention of this test is.
- // spawn(move|| { loopy(5) });
-}
// pretty-expanded FIXME #23616
-#![feature(core)]
-
-use std::u8;
-
trait IntoIterator {
type Iter: Iterator;
fn desugared_for_loop_bad(byte: u8) -> u8 {
let mut result = 0;
- let mut x = IntoIterator::into_iter(0..u8::BITS);
+ let mut x = IntoIterator::into_iter(0..8);
let mut y = Iterator::next(&mut x);
let mut z = y.unwrap();
byte >> z;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
-#![feature(core)]
+#![feature(core_intrinsics)]
use std::intrinsics::assume;
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This test is checking that the move_val_init intrinsic is
+// respecting cleanups for both of its argument expressions.
+//
+// In other words, if either DEST or SOURCE in
+//
+// `intrinsics::move_val_init(DEST, SOURCE)
+//
+// introduce temporaries that require cleanup, and SOURCE panics, then
+// make sure the cleanups still occur.
+
+#![feature(core_intrinsics, sync_poison)]
+
+use std::cell::RefCell;
+use std::intrinsics;
+use std::sync::{Arc, LockResult, Mutex, MutexGuard};
+use std::thread;
+
+type LogEntry = (&'static str, i32);
+type Guarded = RefCell<Vec<LogEntry>>;
+#[derive(Clone)]
+struct Log(Arc<Mutex<Guarded>>);
+struct Acquired<'a>(MutexGuard<'a, Guarded>);
+type LogState = (MutexWas, &'static [LogEntry]);
+
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+enum MutexWas { Poisoned, NotPoisoned }
+
+impl Log {
+ fn lock(&self) -> LockResult<MutexGuard<RefCell<Vec<LogEntry>>>> { self.0.lock() }
+ fn acquire(&self) -> Acquired { Acquired(self.0.lock().unwrap()) }
+}
+
+impl<'a> Acquired<'a> {
+ fn log(&self, s: &'static str, i: i32) { self.0.borrow_mut().push((s, i)); }
+}
+
+const TEST1_EXPECT: LogState = (MutexWas::NotPoisoned,
+ &[("double-check non-poisoning path", 1)
+ ]);
+
+fn test1(log: Log) {
+ {
+ let acq = log.acquire();
+ acq.log("double-check non-poisoning path", 1);
+ }
+ panic!("every test ends in a panic");
+}
+
+const TEST2_EXPECT: LogState = (MutexWas::Poisoned,
+ &[("double-check poisoning path", 1),
+ ("and multiple log entries", 2),
+ ]);
+fn test2(log: Log) {
+ let acq = log.acquire();
+ acq.log("double-check poisoning path", 1);
+ acq.log("and multiple log entries", 2);
+ panic!("every test ends in a panic");
+}
+
+struct LogOnDrop<'a>(&'a Acquired<'a>, &'static str, i32);
+impl<'a> Drop for LogOnDrop<'a> {
+ fn drop(&mut self) {
+ self.0.log(self.1, self.2);
+ }
+}
+
+const TEST3_EXPECT: LogState = (MutexWas::Poisoned,
+ &[("double-check destructors can log", 1),
+ ("drop d2", 2),
+ ("drop d1", 3),
+ ]);
+fn test3(log: Log) {
+ let acq = log.acquire();
+ acq.log("double-check destructors can log", 1);
+ let _d1 = LogOnDrop(&acq, "drop d1", 3);
+ let _d2 = LogOnDrop(&acq, "drop d2", 2);
+ panic!("every test ends in a panic");
+}
+
+// The *real* tests of panic-handling for move_val_init intrinsic
+// start here.
+
+const TEST4_EXPECT: LogState = (MutexWas::Poisoned,
+ &[("neither arg panics", 1),
+ ("drop temp LOD", 2),
+ ("drop temp LOD", 3),
+ ("drop dest_b", 4),
+ ("drop dest_a", 5),
+ ]);
+fn test4(log: Log) {
+ let acq = log.acquire();
+ acq.log("neither arg panics", 1);
+ let mut dest_a = LogOnDrop(&acq, "a will be overwritten, not dropped", 0);
+ let mut dest_b = LogOnDrop(&acq, "b will be overwritten, not dropped", 0);
+ unsafe {
+ intrinsics::move_val_init({ LogOnDrop(&acq, "drop temp LOD", 2); &mut dest_a },
+ LogOnDrop(&acq, "drop dest_a", 5));
+ intrinsics::move_val_init(&mut dest_b, { LogOnDrop(&acq, "drop temp LOD", 3);
+ LogOnDrop(&acq, "drop dest_b", 4) });
+ }
+ panic!("every test ends in a panic");
+}
+
+
+// Check that move_val_init(PANIC, SOURCE_EXPR) never evaluates SOURCE_EXPR
+const TEST5_EXPECT: LogState = (MutexWas::Poisoned,
+ &[("first arg panics", 1),
+ ("drop orig dest_a", 2),
+ ]);
+fn test5(log: Log) {
+ let acq = log.acquire();
+ acq.log("first arg panics", 1);
+ let mut _dest_a = LogOnDrop(&acq, "drop orig dest_a", 2);
+ unsafe {
+ intrinsics::move_val_init({ panic!("every test ends in a panic") },
+ LogOnDrop(&acq, "we never get here", 0));
+ }
+}
+
+// Check that move_val_init(DEST_EXPR, PANIC) cleans up temps from DEST_EXPR.
+const TEST6_EXPECT: LogState = (MutexWas::Poisoned,
+ &[("second arg panics", 1),
+ ("drop temp LOD", 2),
+ ("drop orig dest_a", 3),
+ ]);
+fn test6(log: Log) {
+ let acq = log.acquire();
+ acq.log("second arg panics", 1);
+ let mut dest_a = LogOnDrop(&acq, "drop orig dest_a", 3);
+ unsafe {
+ intrinsics::move_val_init({ LogOnDrop(&acq, "drop temp LOD", 2); &mut dest_a },
+ { panic!("every test ends in a panic"); });
+ }
+}
+
+// Check that move_val_init(DEST_EXPR, COMPLEX_PANIC) cleans up temps from COMPLEX_PANIC.
+const TEST7_EXPECT: LogState = (MutexWas::Poisoned,
+ &[("second arg panics", 1),
+ ("drop temp LOD", 2),
+ ("drop temp LOD", 3),
+ ("drop orig dest_a", 4),
+ ]);
+fn test7(log: Log) {
+ let acq = log.acquire();
+ acq.log("second arg panics", 1);
+ let mut dest_a = LogOnDrop(&acq, "drop orig dest_a", 4);
+ unsafe {
+ intrinsics::move_val_init({ LogOnDrop(&acq, "drop temp LOD", 2); &mut dest_a },
+ { LogOnDrop(&acq, "drop temp LOD", 3);
+ panic!("every test ends in a panic"); });
+ }
+}
+
+const TEST_SUITE: &'static [(&'static str, fn (Log), LogState)] =
+ &[("test1", test1, TEST1_EXPECT),
+ ("test2", test2, TEST2_EXPECT),
+ ("test3", test3, TEST3_EXPECT),
+ ("test4", test4, TEST4_EXPECT),
+ ("test5", test5, TEST5_EXPECT),
+ ("test6", test6, TEST6_EXPECT),
+ ("test7", test7, TEST7_EXPECT),
+ ];
+
+fn main() {
+ for &(name, test, expect) in TEST_SUITE {
+ let log = Log(Arc::new(Mutex::new(RefCell::new(Vec::new()))));
+ let ret = { let log = log.clone(); thread::spawn(move || test(log)).join() };
+ assert!(ret.is_err(), "{} must end with panic", name);
+ {
+ let l = log.lock();
+ match l {
+ Ok(acq) => {
+ assert_eq!((MutexWas::NotPoisoned, &acq.borrow()[..]), expect);
+ println!("{} (unpoisoned) log: {:?}", name, *acq);
+ }
+ Err(e) => {
+ let acq = e.into_inner();
+ assert_eq!((MutexWas::Poisoned, &acq.borrow()[..]), expect);
+ println!("{} (poisoned) log: {:?}", name, *acq);
+ }
+ }
+ }
+ }
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
-#![feature(core)]
+#![feature(core_intrinsics)]
use std::intrinsics;
// Causes linker error
// undefined reference to llvm.ceil.f32/64
- //assert!((ceilf32(-2.3f32) == -2.0f32));
- //assert!((ceilf64(3.8f64) == 4.0f64));
+ //assert_eq!(ceilf32(-2.3f32), -2.0f32);
+ //assert_eq!(ceilf64(3.8f64), 4.0f64);
// Causes linker error
// undefined reference to llvm.trunc.f32/64
- //assert!((truncf32(0.1f32) == 0.0f32));
- //assert!((truncf64(-0.1f64) == 0.0f64));
+ //assert_eq!(truncf32(0.1f32), 0.0f32);
+ //assert_eq!(truncf64(-0.1f64), 0.0f64);
}
}
let _a = Foo{ dropped: false };
}
// Check that we dropped already (as expected from a `{ expr }`).
- unsafe { assert!(drop_count == 1); }
+ unsafe { assert_eq!(drop_count, 1); }
// An `if false {} else { expr }` statement should compile the same as `{ expr }`.
if false {
let _a = Foo{ dropped: false };
}
// Check that we dropped already (as expected from a `{ expr }`).
- unsafe { assert!(drop_count == 2); }
+ unsafe { assert_eq!(drop_count, 2); }
}
// when this bug was opened. The cases where the compiler
// panics before the fix have a comment.
-#![feature(std_misc)]
+#![feature(thunk)]
use std::thunk::Thunk;
// pretty-expanded FIXME #23616
-#![feature(collections)]
+#![feature(bitvec)]
use std::collections::BitVec;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// pretty-expanded FIXME #23616
-
#![forbid(warnings)]
-#![feature(std_misc)]
-
-// Pretty printing tests complain about `use std::predule::*`
-#![allow(unused_imports)]
// We shouldn't need to rebind a moved upvar as mut if it's already
// marked as mut
-use std::thunk::Thunk;
-
pub fn main() {
let mut x = 1;
let _thunk = Box::new(move|| { x = 2; });
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// pretty-expanded FIXME #23616
-
#![feature(libc, std_misc)]
extern crate libc;
// This test may not always fail, but it can be flaky if the race it used to
// expose is still present.
-// pretty-expanded FIXME #23616
-
-#![feature(std_misc)]
+#![feature(mpsc_select)]
use std::sync::mpsc::{channel, Sender, Receiver};
use std::thread;
// pretty-expanded FIXME #23616
-#![feature(core)]
+#![feature(num_bits_bytes)]
use std::u8;
break
}
}
- assert!(result == [2, 4]);
+ assert_eq!(result, [2, 4]);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
-#![feature(core)]
+#![feature(iter_arith)]
fn main() {
let x: [u64; 3] = [1, 2, 3];
// except according to those terms.
-#[derive(PartialEq)]
+#[derive(PartialEq, Debug)]
enum Test<'a> {
Slice(&'a isize)
}
fn main() {
- assert!(Test::Slice(&1) == Test::Slice(&1))
+ assert_eq!(Test::Slice(&1), Test::Slice(&1))
}
let m = Mat::new(vec!(1, 2, 3, 4, 5, 6), 3);
let r = m.row(1);
- assert!(r.index(2) == &6);
- assert!(r[2] == 6);
- assert!(r[2] == 6);
- assert!(6 == r[2]);
+ assert_eq!(r.index(2), &6);
+ assert_eq!(r[2], 6);
+ assert_eq!(r[2], 6);
+ assert_eq!(6, r[2]);
let e = r[2];
- assert!(e == 6);
+ assert_eq!(e, 6);
let e: usize = r[2];
- assert!(e == 6);
+ assert_eq!(e, 6);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
-#![feature(hash)]
+#![feature(hash_default)]
use std::hash::{SipHasher, hash};
struct Empty;
pub fn main() {
- assert!(hash::<_, SipHasher>(&Empty) == hash::<_, SipHasher>(&Empty));
+ assert_eq!(hash::<_, SipHasher>(&Empty), hash::<_, SipHasher>(&Empty));
}
// pretty-expanded FIXME #23616
#![feature(core)]
+#![feature(const_fn)]
+
use std::marker;
use std::cell::UnsafeCell;
static STATIC1: UnsafeEnum<isize> = UnsafeEnum::VariantSafe;
-static STATIC2: MyUnsafePack<isize> = MyUnsafePack(UnsafeCell { value: 1 });
-const CONST: MyUnsafePack<isize> = MyUnsafePack(UnsafeCell { value: 1 });
+static STATIC2: MyUnsafePack<isize> = MyUnsafePack(UnsafeCell::new(1));
+const CONST: MyUnsafePack<isize> = MyUnsafePack(UnsafeCell::new(1));
static STATIC3: MyUnsafe<isize> = MyUnsafe{value: CONST};
static STATIC4: &'static MyUnsafePack<isize> = &STATIC2;
unsafe impl<T: Send> Sync for Wrap<T> {}
-static UNSAFE: MyUnsafePack<isize> = MyUnsafePack(UnsafeCell{value: 2});
+static UNSAFE: MyUnsafePack<isize> = MyUnsafePack(UnsafeCell::new(2));
static WRAPPED_UNSAFE: Wrap<&'static MyUnsafePack<isize>> = Wrap { value: &UNSAFE };
fn main() {
#![feature(core)]
+#![feature(const_fn)]
extern crate issue_17718 as other;
-use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
+use std::sync::atomic::{AtomicUsize, Ordering};
const C1: usize = 1;
-const C2: AtomicUsize = ATOMIC_USIZE_INIT;
+const C2: AtomicUsize = AtomicUsize::new(0);
const C3: fn() = foo;
const C4: usize = C1 * C1 + C1 / C1;
const C5: &'static usize = &C4;
};
static S1: usize = 3;
-static S2: AtomicUsize = ATOMIC_USIZE_INIT;
+static S2: AtomicUsize = AtomicUsize::new(0);
mod test {
static A: usize = 4;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(unboxed_closures, std_misc)]
+#![feature(thunk)]
use std::thunk::Thunk;
// pretty-expanded FIXME #23616
-#![feature(unboxed_closures, std_misc)]
+#![feature(thunk)]
use std::thunk::Thunk;
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait Factory {
+ type Product;
+ fn create(&self) -> <Self as Factory>::Product;
+}
+
+impl Factory for f64 {
+ type Product = f64;
+ fn create(&self) -> f64 { *self * *self }
+}
+
+impl<A: Factory, B: Factory> Factory for (A, B) {
+ type Product = (<A as Factory>::Product, <B as Factory>::Product);
+ fn create(&self) -> (<A as Factory>::Product, <B as Factory>::Product) {
+ let (ref a, ref b) = *self;
+ (a.create(), b.create())
+ }
+}
+
+fn main() {
+ assert_eq!((16., 25.), (4., 5.).create());
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait Tup {
+ type T0;
+ type T1;
+}
+
+impl Tup for isize {
+ type T0 = f32;
+ type T1 = ();
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This used to generate invalid IR in that even if we took the
+// `false` branch we'd still try to free the Box from the other
+// arm. This was due to treating `*Box::new(9)` as an rvalue datum
+// instead of as an lvalue.
+
+fn test(foo: bool) -> u8 {
+ match foo {
+ true => *Box::new(9),
+ false => 0
+ }
+}
+
+fn main() {
+ assert_eq!(9, test(true));
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:issue-18913-1.rs
+// aux-build:issue-18913-2.rs
+
+extern crate foo;
+
+fn main() {
+ assert_eq!(foo::foo(), 1);
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub trait Foo : Send { }
+
+pub struct MyFoo {
+ children: Vec<Box<Foo>>,
+}
+
+impl Foo for MyFoo { }
+
+pub fn main() { }
#![feature(collections)]
fn main() {
- let mut escaped = String::from_str("");
+ let mut escaped = String::from("");
for c in '\u{10401}'.escape_unicode() {
escaped.push(c);
}
if path.is_dir() {
let result = self.strategy.get_more(&path);
match result {
- Ok(dirs) => { self.stack.extend(dirs.into_iter()); },
+ Ok(dirs) => { self.stack.extend(dirs); },
Err(..) => { }
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
-#![feature(core)]
+#![feature(core_intrinsics)]
struct NT(str);
struct DST { a: u32, b: str }
std::intrinsics::type_name::<NT>(),
// DST
std::intrinsics::type_name::<DST>()
- )}, ("[u8]", "str", "core::marker::Copy", "NT", "DST"));
+ )}, ("[u8]", "str", "core::marker::Copy + 'static", "NT", "DST"));
}
arg.clone()
}
-#[derive(PartialEq)]
+#[derive(PartialEq, Debug)]
struct Test(isize);
fn main() {
// Check that ranges implement clone
- assert!(test(1..5) == (1..5));
- assert!(test(..5) == (..5));
- assert!(test(1..) == (1..));
- assert!(test(RangeFull) == (RangeFull));
+ assert_eq!(test(1..5), (1..5));
+ assert_eq!(test(..5), (..5));
+ assert_eq!(test(1..), (1..));
+ assert_eq!(test(RangeFull), (RangeFull));
// Check that ranges can still be used with non-clone limits
- assert!((Test(1)..Test(5)) == (Test(1)..Test(5)));
+ assert_eq!((Test(1)..Test(5)), (Test(1)..Test(5)));
}
// created via FRU and control-flow breaks in the middle of
// construction.
+#![feature(const_fn)]
-use std::sync::atomic::{Ordering, AtomicUsize, ATOMIC_USIZE_INIT};
+use std::sync::atomic::{Ordering, AtomicUsize};
#[derive(Debug)]
struct Noisy(u8);
assert_eq!(0x03_04, event_log());
}
-static LOG: AtomicUsize = ATOMIC_USIZE_INIT;
+static LOG: AtomicUsize = AtomicUsize::new(0);
fn reset_log() {
LOG.store(0, Ordering::SeqCst);
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+
+struct Index;
+
+impl Index {
+ fn new() -> Self { Index }
+}
+
+fn user() {
+ let new = Index::new;
+
+ fn inner() {
+ let index = Index::new();
+ }
+
+ let index2 = new();
+}
+
+fn main() {}
+++ /dev/null
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// ignore-test
-
-// notes on this test case:
-// On Thu, Apr 18, 2013-2014 at 6:30 PM, John Clements <clements@brinckerhoff.org> wrote:
-// the "issue-2185.rs" test was ignored with a ref to #2263. Issue #2263 is now fixed,
-// so I tried it again, and after adding some &self parameters, I got this error:
-//
-// Running /usr/local/bin/rustc:
-// issue-2185.rs:24:0: 26:1 error: conflicting implementations for a trait
-// issue-2185.rs:24 impl iterable<usize> for 'static ||usize|| {
-// issue-2185.rs:25 fn iter(&self, blk: |v: usize|) { self( |i| blk(i) ) }
-// issue-2185.rs:26 }
-// issue-2185.rs:20:0: 22:1 note: note conflicting implementation here
-// issue-2185.rs:20 impl<A> iterable<A> for 'static ||A|| {
-// issue-2185.rs:21 fn iter(&self, blk: |A|) { self(blk); }
-// issue-2185.rs:22 }
-//
-// … so it looks like it's just not possible to implement both
-// the generic iterable<usize> and iterable<A> for the type iterable<usize>.
-// Is it okay if I just remove this test?
-//
-// but Niko responded:
-// think it's fine to remove this test, just because it's old and cruft and not hard to reproduce.
-// *However* it should eventually be possible to implement the same interface for the same type
-// multiple times with different type parameters, it's just that our current trait implementation
-// has accidental limitations.
-
-// so I'm leaving it in.
-// actually, it looks like this is related to bug #3429. I'll rename this bug.
-
-// This test had to do with an outdated version of the iterable trait.
-// However, the condition it was testing seemed complex enough to
-// warrant still having a test, so I inlined the old definitions.
-
-trait iterable<A> {
- fn iter(&self, blk: |A|);
-}
-
-impl<A> iterable<A> for 'static ||A|| {
- fn iter(&self, blk: |A|) { self(blk); }
-}
-
-impl iterable<usize> for 'static ||usize|| {
- fn iter(&self, blk: |v: usize|) { self( |i| blk(i) ) }
-}
-
-fn filter<A,IA:iterable<A>>(self: IA, prd: 'static |A| -> bool, blk: |A|) {
- self.iter(|a| {
- if prd(a) { blk(a) }
- });
-}
-
-fn foldl<A,B,IA:iterable<A>>(self: IA, b0: B, blk: |B, A| -> B) -> B {
- let mut b = b0;
- self.iter(|a| {
- b = blk(b, a);
- });
- b
-}
-
-fn range(lo: usize, hi: usize, it: |usize|) {
- let mut i = lo;
- while i < hi {
- it(i);
- i += 1;
- }
-}
-
-pub fn main() {
- let range: 'static ||usize|| = |a| range(0, 1000, a);
- let filt: 'static ||v: usize|| = |a| filter(
- range,
- |&&n: usize| n % 3 != 0 && n % 5 != 0,
- a);
- let sum = foldl(filt, 0, |accum, &&n: usize| accum + n );
-
- println!("{}", sum);
-}
// pretty-expanded FIXME #23616
-#![feature(std_misc)]
+#![feature(thunk)]
use std::thread::Builder;
use std::thunk::Thunk;
+++ /dev/null
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// ignore-test FIXME #2190
-
-mod a {
- fn foo(f: ||) { f() }
- fn bar() {}
- pub fn main() { foo(||bar()); }
-}
-
-mod b {
- fn foo(f: Option<||>) { f.map(|x|x()); }
- fn bar() {}
- pub fn main() { foo(Some(bar)); }
-}
-
-mod c {
- fn foo(f: Option<||>) { f.map(|x|x()); }
- fn bar() {}
- pub fn main() { foo(Some(||bar())); }
-}
-
-pub fn main() {
-}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub fn main() {
+ struct Fun<F>(F);
+ let f = Fun(|x| 3*x);
+ let Fun(g) = f;
+ println!("{:?}",g(4));
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub fn main() {
+ let f = || || 0;
+ std::thread::spawn(f());
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(core)]
+#![feature(core_simd)]
use std::simd::i32x4;
fn main() {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(core)]
+#![feature(core_intrinsics)]
#![allow(warnings)]
use std::intrinsics;
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::mem;
+
+pub struct X([u8]);
+
+fn _f(x: &X) -> usize { match *x { X(ref x) => { x.len() } } }
+
+fn main() {
+ let b: &[u8] = &[11; 42];
+ let v: &X = unsafe { mem::transmute(b) };
+ assert_eq!(_f(v), 42);
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::collections::HashMap;
+use std::path::{Path, PathBuf};
+
+fn main() {
+ let m: HashMap<PathBuf, ()> = HashMap::new();
+ let k = Path::new("foo");
+ println!("{:?}", m.get(k));
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[derive(PartialEq)]
+struct Slice { slice: [u8] }
+
+fn main() {}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+const U8_MAX_HALF: u8 = !0u8 / 2;
+const U16_MAX_HALF: u16 = !0u16 / 2;
+const U32_MAX_HALF: u32 = !0u32 / 2;
+const U64_MAX_HALF: u64 = !0u64 / 2;
+
+fn main() {
+ assert_eq!(U8_MAX_HALF, 0x7f);
+ assert_eq!(U16_MAX_HALF, 0x7fff);
+ assert_eq!(U32_MAX_HALF, 0x7fff_ffff);
+ assert_eq!(U64_MAX_HALF, 0x7fff_ffff_ffff_ffff);
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Regression test for #24085. Errors were occuring in region
+// inference due to the requirement that `'a:b'`, which was getting
+// incorrectly translated in connection with the closure below.
+
+#[derive(Copy,Clone)]
+struct Path<'a:'b, 'b> {
+ x: &'a i32,
+ tail: Option<&'b Path<'a, 'b>>
+}
+
+#[allow(dead_code, unconditional_recursion)]
+fn foo<'a,'b,F>(p: Path<'a, 'b>, mut f: F)
+ where F: for<'c> FnMut(Path<'a, 'c>) {
+ foo(p, |x| f(x))
+}
+
+fn main() { }
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This resulted in an ICE. Test for future-proofing
+// Issue #24227
+
+#![allow(unused)]
+
+struct Foo<'a> {
+ x: &'a u8
+}
+
+impl<'a> Foo<'a> {
+ fn foo() {
+ let mut tmp: Self;
+ }
+
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -C debug-assertions
+
+#![feature(core_simd)]
+
+use std::simd::u32x4;
+
+// (Work around constant-evaluation)
+fn id<T>(x: T) -> T { x }
+
+fn eq_u32x4(u32x4(x0, x1, x2, x3): u32x4, u32x4(y0, y1, y2, y3): u32x4) -> bool {
+ (x0 == y0) && (x1 == y1) && (x2 == y2) && (x3 == y3)
+}
+
+fn main() {
+ assert!(eq_u32x4(u32x4(1, 1, 1, 1) << id(u32x4(1, 1, 1, 1)), u32x4(2, 2, 2, 2)));
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub trait Foo {
+ fn method1() {}
+ fn method2();
+}
+
+struct Slice<'a, T: 'a>(&'a [T]);
+
+impl<'a, T: 'a> Foo for Slice<'a, T> {
+ fn method2() {
+ <Self as Foo>::method1();
+ }
+}
+
+fn main() {
+ <Slice<()> as Foo>::method2();
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub struct _X([u8]);
+
+impl std::ops::Deref for _X {
+ type Target = [u8];
+
+ fn deref(&self) -> &[u8] {
+ &self.0
+ }
+}
+
+pub fn _g(x: &_X) -> &[u8] {
+ x
+}
+
+fn main() {
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ assert_eq!((||||42)()(), 42);
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+const x: &'static Fn() = &|| println!("ICE here");
+
+fn main() {}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct S<'a>(&'a ());
+
+impl<'a> S<'a> {
+ fn foo(self) -> &'a () {
+ <Self>::bar(self)
+ }
+
+ fn bar(self) -> &'a () {
+ self.0
+ }
+}
+
+fn main() {
+ S(&()).foo();
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(associated_type_defaults)]
+
+use std::marker::PhantomData;
+
+pub trait Routing<I> {
+ type Output;
+ fn resolve(&self, input: I);
+}
+
+pub trait ToRouting {
+ type Input;
+ type Routing : ?Sized = Routing<Self::Input, Output=()>;
+ fn to_routing(self) -> Self::Routing;
+}
+
+pub struct Mount<I, R: Routing<I>> {
+ action: R,
+ _marker: PhantomData<I>
+}
+
+impl<I, R: Routing<I>> Mount<I, R> {
+ pub fn create<T: ToRouting<Routing=R>>(mount: &str, input: T) {
+ input.to_routing();
+ }
+}
+
+fn main() {
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[derive(Debug)]
+struct Row<T>([T]);
+
+fn main() {}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[derive(Clone, Debug, PartialEq)]
+enum Expression {
+ Dummy,
+ Add(Box<Expression>),
+}
+
+use Expression::*;
+
+fn simplify(exp: Expression) -> Expression {
+ match exp {
+ Add(n) => *n.clone(),
+ _ => Dummy
+ }
+}
+
+fn main() {
+ assert_eq!(simplify(Add(Box::new(Dummy))), Dummy);
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::rc::Rc;
+
+struct Foo<'r>(&'r mut i32);
+
+impl<'r> Drop for Foo<'r> {
+ fn drop(&mut self) {
+ *self.0 += 1;
+ }
+}
+
+fn main() {
+ let mut drops = 0;
+
+ {
+ let _: Rc<Send> = Rc::new(Foo(&mut drops));
+ }
+
+ assert_eq!(1, drops);
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct Foo<'r>(&'r mut i32);
+
+impl<'r> Drop for Foo<'r> {
+ fn drop(&mut self) {
+ *self.0 += 1;
+ }
+}
+
+trait Trait {}
+impl<'r> Trait for Foo<'r> {}
+
+struct Holder<T: ?Sized>(T);
+
+fn main() {
+ let mut drops = 0;
+
+ {
+ let y = &Holder([Foo(&mut drops)]) as &Holder<[Foo]>;
+ // this used to cause an extra drop of the Foo instance
+ let x = &y.0;
+ }
+ assert_eq!(1, drops);
+
+ drops = 0;
+ {
+ let y = &Holder(Foo(&mut drops)) as &Holder<Trait>;
+ // this used to cause an extra drop of the Foo instance
+ let x = &y.0;
+ }
+ assert_eq!(1, drops);
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait Device {
+ type Resources;
+}
+struct Foo<D, R>(D, R);
+
+impl<D: Device> Foo<D, D::Resources> {
+ fn present(&self) {}
+}
+
+struct Res;
+struct Dev;
+
+impl Device for Dev { type Resources = Res; }
+
+fn main() {
+ let foo = Foo(Dev, Res);
+ foo.present();
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct S<T: 'static>(Option<&'static T>);
+
+trait Tr { type Out; }
+impl<T> Tr for T { type Out = T; }
+
+impl<T: 'static> Copy for S<T> where S<T>: Tr<Out=T> {}
+impl<T: 'static> Clone for S<T> where S<T>: Tr<Out=T> {
+ fn clone(&self) -> Self { *self }
+}
+fn main() {
+ S::<()>(None);
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub trait Parser {
+ type Input;
+}
+
+pub struct Iter<P: Parser>(P, P::Input);
+
+pub struct Map<P, F>(P, F);
+impl<P, F> Parser for Map<P, F> where F: FnMut(P) {
+ type Input = u8;
+}
+
+trait AstId { type Untyped; }
+impl AstId for u32 { type Untyped = u32; }
+
+fn record_type<Id: AstId>(i: Id::Untyped) -> u8 {
+ Iter(Map(i, |_: Id::Untyped| {}), 42).1
+}
+
+pub fn main() {
+ assert_eq!(record_type::<u32>(3), 42);
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::mem::transmute;
+
+fn main() {
+ unsafe {
+ let _: i8 = transmute(false);
+ let _: i8 = transmute(true);
+ let _: bool = transmute(0u8);
+ let _: bool = transmute(1u8);
+ }
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct Foo {
+ a: u32
+}
+
+impl Foo {
+ fn x(&mut self) {
+ self.a = 5;
+ }
+}
+
+const FUNC: &'static Fn(&mut Foo) -> () = &Foo::x;
+
+fn main() {
+ let mut foo = Foo { a: 137 };
+ FUNC(&mut foo); //~ ERROR bad
+ assert_eq!(foo.a, 5);
+}
}
grid.push(row);
let width = grid[0].len();
- for row in &grid { assert!(row.len() == width) }
+ for row in &grid { assert_eq!(row.len(), width) }
grid
}
mod test {
#[test]
pub fn trivial_to_string() {
- assert!(lambda.to_string() == "\\")
+ assert_eq!(lambda.to_string(), "\\")
}
}
fn id<T>(x: T) -> T { return x; }
-pub fn main() { assert!((quux(10) == 10)); }
+pub fn main() { assert_eq!(quux(10), 10); }
+++ /dev/null
-// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// ignore-test
-
-// ignored due to Valgrind complaining about TLS loss.
-
-pub fn main()
-{
- unsafe {
- libc::exit(0);
- }
- println!("ack");
-}
+++ /dev/null
-// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// ignore-test needs networking
-
-extern crate extra;
-
-use extra::net::tcp::TcpSocketBuf;
-
-use std::io;
-use std::isize;
-
-use std::io::{ReaderUtil,WriterUtil};
-
-enum Result {
- Nil,
- Int(isize),
- Data(Vec<u8>),
- List(Vec<Result>),
- Error(String),
- Status(String)
-}
-
-fn parse_data(len: usize, io: @io::Reader) -> Result {
- let res =
- if (len > 0) {
- let bytes = io.read_bytes(len as usize);
- assert_eq!(bytes.len(), len);
- Data(bytes)
- } else {
- Data(vec![])
- };
- assert_eq!(io.read_char(), '\r');
- assert_eq!(io.read_char(), '\n');
- return res;
-}
-
-fn parse_list(len: usize, io: @io::Reader) -> Result {
- let mut list: Vec<Result> = vec![];
- for _ in 0..len {
- let v = match io.read_char() {
- '$' => parse_bulk(io),
- ':' => parse_int(io),
- _ => panic!()
- };
- list.push(v);
- }
- return List(list);
-}
-
-fn chop(s: String) -> String {
- s.slice(0, s.len() - 1).to_string()
-}
-
-fn parse_bulk(io: @io::Reader) -> Result {
- match from_str::<isize>(chop(io.read_line())) {
- None => panic!(),
- Some(-1) => Nil,
- Some(len) if len >= 0 => parse_data(len as usize, io),
- Some(_) => panic!()
- }
-}
-
-fn parse_multi(io: @io::Reader) -> Result {
- match from_str::<isize>(chop(io.read_line())) {
- None => panic!(),
- Some(-1) => Nil,
- Some(0) => List(vec![]),
- Some(len) if len >= 0 => parse_list(len as usize, io),
- Some(_) => panic!()
- }
-}
-
-fn parse_int(io: @io::Reader) -> Result {
- match from_str::<isize>(chop(io.read_line())) {
- None => panic!(),
- Some(i) => Int(i)
- }
-}
-
-fn parse_response(io: @io::Reader) -> Result {
- match io.read_char() {
- '$' => parse_bulk(io),
- '*' => parse_multi(io),
- '+' => Status(chop(io.read_line())),
- '-' => Error(chop(io.read_line())),
- ':' => parse_int(io),
- _ => panic!()
- }
-}
-
-fn cmd_to_string(cmd: Vec<String>) -> String {
- let mut res = "*".to_string();
- res.push_str(cmd.len().to_string());
- res.push_str("\r\n");
- for s in &cmd {
- res.push_str(["$".to_string(), s.len().to_string(), "\r\n".to_string(),
- (*s).clone(), "\r\n".to_string()].concat() );
- }
- res
-}
-
-fn query(cmd: Vec<String>, sb: TcpSocketBuf) -> Result {
- let cmd = cmd_to_string(cmd);
- //println!("{}", cmd);
- sb.write_str(cmd);
- let res = parse_response(@sb as @io::Reader);
- res
-}
-
-fn query2(cmd: Vec<String>) -> Result {
- let _cmd = cmd_to_string(cmd);
- io::with_str_reader("$3\r\nXXX\r\n".to_string())(|sb| {
- let res = parse_response(@sb as @io::Reader);
- println!("{}", res);
- res
- });
-}
-
-
-pub fn main() {
-}
pub fn main() {
let _f = |ref x: isize| { *x };
let foo = 10;
- assert!(_f(foo) == 10);
+ assert_eq!(_f(foo), 10);
}
// pretty-expanded FIXME #23616
-#![feature(core)]
-
-use std::intrinsics;
+use std::mem;
/// Returns the size of a type
pub fn size_of<T>() -> usize {
impl<T> TypeInfo for T {
/// The size of the type in bytes.
fn size_of(_lame_type_hint: Option<T>) -> usize {
- unsafe { intrinsics::size_of::<T>() }
+ mem::size_of::<T>()
}
/// Returns the size of the type of `self` in bytes.
pub mod baz {
use test1::bar::p;
- pub fn my_main() { assert!(p() == 2); }
+ pub fn my_main() { assert_eq!(p(), 2); }
}
}
pub mod baz {
use test2::bar::p;
- pub fn my_main() { assert!(p() == 2); }
+ pub fn my_main() { assert_eq!(p(), 2); }
}
}
let out = bar("baz", "foo");
let [a, xs.., d] = out;
assert_eq!(a, "baz");
- assert!(xs == ["foo", "foo"]);
+ assert_eq!(xs, ["foo", "foo"]);
assert_eq!(d, "baz");
}
match &[(Box::new(5),Box::new(7))] {
ps => {
let (ref y, _) = ps[0];
- assert!(**y == 5);
+ assert_eq!(**y, 5);
}
}
match Some(&[(Box::new(5),)]) {
Some(ps) => {
let (ref y,) = ps[0];
- assert!(**y == 5);
+ assert_eq!(**y, 5);
}
None => ()
}
match Some(&[(Box::new(5),Box::new(7))]) {
Some(ps) => {
let (ref y, ref z) = ps[0];
- assert!(**y == 5);
- assert!(**z == 7);
+ assert_eq!(**y, 5);
+ assert_eq!(**z, 7);
}
None => ()
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-test #9737
-
macro_rules! f {
(v: $x:expr) => ( println!("{}", $x) )
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait Foo {
+ type T;
+}
+
+// should be able to use a trait with an associated type without specifying it as an argument
+trait Bar<F: Foo> {
+ fn bar(foo: &F);
+}
+
+pub fn main() {
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait Tr { type T; }
+impl Tr for u8 { type T=(); }
+struct S<I: Tr>(I::T);
+
+fn foo<I: Tr>(i: I::T) {
+ S::<I>(i);
+}
+
+fn main() {
+ foo::<u8>(());
+}
let s: String = "a".to_string();
println!("{}", s.clone());
let t: String = "a".to_string();
- assert!(s == t);
+ assert_eq!(s, t);
let u: String = "b".to_string();
assert!((s != u));
}
fn test_heap_assign() {
let s: String = "a big ol' string".to_string();
let t: String = "a big ol' string".to_string();
- assert!(s == t);
+ assert_eq!(s, t);
let u: String = "a bad ol' string".to_string();
assert!((s != u));
}
s.push_str("a");
assert_eq!(s, "a");
- let mut s = String::from_str("a");
+ let mut s = String::from("a");
s.push_str("b");
println!("{}", s.clone());
assert_eq!(s, "ab");
- let mut s = String::from_str("c");
+ let mut s = String::from("c");
s.push_str("offee");
- assert!(s == "coffee");
+ assert_eq!(s, "coffee");
s.push_str("&tea");
- assert!(s == "coffee&tea");
+ assert_eq!(s, "coffee&tea");
}
pub fn main() {
// Test to see that the element type of .cloned() can be inferred
// properly. Previously this would fail to deduce the type of `sum`.
-
-#![feature(core)]
+#![feature(iter_arith)]
fn square_sum(v: &[i64]) -> i64 {
let sum: i64 = v.iter().cloned().sum();
let s = "hello there".to_string();
let mut i: isize = 0;
for c in s.bytes() {
- if i == 0 { assert!((c == 'h' as u8)); }
- if i == 1 { assert!((c == 'e' as u8)); }
- if i == 2 { assert!((c == 'l' as u8)); }
- if i == 3 { assert!((c == 'l' as u8)); }
- if i == 4 { assert!((c == 'o' as u8)); }
+ if i == 0 { assert_eq!(c, 'h' as u8); }
+ if i == 1 { assert_eq!(c, 'e' as u8); }
+ if i == 2 { assert_eq!(c, 'l' as u8); }
+ if i == 3 { assert_eq!(c, 'l' as u8); }
+ if i == 4 { assert_eq!(c, 'o' as u8); }
// ...
i += 1;
// ignore-windows: std::dynamic_lib does not work on Windows well
// ignore-musl
-#![feature(std_misc)]
-
extern crate linkage_visibility as foo;
pub fn main() {
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![deny(dead_code)]
+
+enum Foo {
+ A,
+ B,
+}
+
+pub fn main() {
+ match Foo::A {
+ Foo::A | Foo::B => Foo::B
+ };
+}
impl fmt::Debug for Foo {
fn fmt(&self, _fmt: &mut fmt::Formatter) -> fmt::Result {
let Foo(ref f) = *self;
- assert!(f.get() == 0);
+ assert_eq!(f.get(), 0);
f.set(1);
Ok(())
}
let mut f = Foo(Cell::new(0));
println!("{:?}", f);
let Foo(ref mut f) = f;
- assert!(f.get() == 1);
+ assert_eq!(f.get(), 1);
}).join().ok().unwrap();
}
})
}
- assert!(mylambda_tt!(y, y * 2)(8) == 16);
+ assert_eq!(mylambda_tt!(y, y * 2)(8), 16);
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Regression test for issue #25436: check that things which can be
+// followed by any token also permit X* to come afterwards.
+
+macro_rules! foo {
+ ( $a:tt $($b:tt)* ) => { };
+ ( $a:ident $($b:tt)* ) => { };
+ ( $a:item $($b:tt)* ) => { };
+ ( $a:block $($b:tt)* ) => { };
+ ( $a:meta $($b:tt)* ) => { }
+}
+
+fn main() { }
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+macro_rules! pat_in {
+ ($p:pat in $e:expr) => {{
+ let mut iter = $e.into_iter();
+ while let $p = iter.next() {}
+ }}
+}
+
+macro_rules! pat_if {
+ ($p:pat if $e:expr) => {{
+ match Some(1u8) {
+ $p if $e => {},
+ _ => {}
+ }
+ }}
+}
+
+fn main() {
+ pat_in!(Some(_) in 0..10);
+ pat_if!(Some(x) if x > 0);
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Regression test for issue #25436: permit token-trees to be followed
+// by sequences, enabling more general parsing.
+
+use self::Join::*;
+
+#[derive(Debug)]
+enum Join<A,B> {
+ Keep(A,B),
+ Skip(A,B),
+}
+
+macro_rules! parse_list {
+ ( < $a:expr; > $($b:tt)* ) => { Keep(parse_item!($a),parse_list!($($b)*)) };
+ ( $a:tt $($b:tt)* ) => { Skip(parse_item!($a), parse_list!($($b)*)) };
+ ( ) => { () };
+}
+
+macro_rules! parse_item {
+ ( $x:expr ) => { $x }
+}
+
+fn main() {
+ let list = parse_list!(<1;> 2 <3;> 4);
+ assert_eq!("Keep(1, Skip(2, Keep(3, Skip(4, ()))))",
+ format!("{:?}", list));
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(std_misc)]
-
use std::thread;
macro_rules! expr { ($e: expr) => { $e } }
macro_rules! spawn {
($($code: tt)*) => {
- expr!(thread::spawn(move|| {$($code)*}))
+ expr!(thread::spawn(move|| {$($code)*}).join())
}
}
let x_internal = &mut *x;
match *x_internal {
Pair {a: ref mut a, b: ref mut _b} => {
- assert!(**a == 10); *a = box 30; assert!(**a == 30);
+ assert_eq!(**a, 10);
+ *a = box 30;
+ assert_eq!(**a, 30);
}
}
}
}
}
-pub fn main() { assert!((altlit(10) == 20)); assert!((altlit(11) == 22)); }
+pub fn main() {
+ assert_eq!(altlit(10), 20);
+ assert_eq!(altlit(11), 22);
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that type inference for range patterns works correctly (is bi-directional).
+
+pub fn main() {
+ match 1 {
+ 1 ... 3 => {}
+ _ => panic!("should match range")
+ }
+ match 1 {
+ 1 ... 3u16 => {}
+ _ => panic!("should match range with inferred start type")
+ }
+ match 1 {
+ 1u16 ... 3 => {}
+ _ => panic!("should match range with inferred end type")
+ }
+}
(0, A) => 0,
(x, y) => 1 + x + y,
};
- assert!(r == 1);
+ assert_eq!(r, 1);
let r = match (0,97) {
(0, A) => 0,
(x, y) => 1 + x + y,
};
- assert!(r == 0);
+ assert_eq!(r, 0);
}
mod m {
(0, AHA) => 0,
(x, y) => 1 + x + y,
};
- assert!(r == 1);
+ assert_eq!(r, 1);
let r = match (0,7) {
(0, AHA) => 0,
(x, y) => 1 + x + y,
};
- assert!(r == 0);
+ assert_eq!(r, 0);
}
fn h() {
(0, self::m::aha) => 0,
(x, y) => 1 + x + y,
};
- assert!(r == 1);
+ assert_eq!(r, 1);
let r = match (0,7) {
(0, self::m::aha) => 0,
(x, y) => 1 + x + y,
};
- assert!(r == 0);
+ assert_eq!(r, 0);
}
pub fn main () {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-test #9384
-
// shouldn't affect evaluation of $ex.
macro_rules! bad_macro { ($ex:expr) => (
{match 9 {_x => $ex}}
// temporary. Issue #19147.
-#![feature(core)]
+#![feature(slice_bytes)]
use std::slice;
-pub type IoResult<T> = Result<T, ()>;
-
trait MyWriter {
- fn my_write(&mut self, buf: &[u8]) -> IoResult<()>;
+ fn my_write(&mut self, buf: &[u8]) -> Result<(), ()>;
}
impl<'a> MyWriter for &'a mut [u8] {
- fn my_write(&mut self, buf: &[u8]) -> IoResult<()> {
+ fn my_write(&mut self, buf: &[u8]) -> Result<(), ()> {
slice::bytes::copy_memory(buf, *self);
let write_len = buf.len();
x.foo(&x);
- assert!(method_self_arg1::get_count() == 2*3*3*3*5*5*5*7*7*7);
+ assert_eq!(method_self_arg1::get_count(), 2*3*3*3*5*5*5*7*7*7);
}
x.run_trait();
- assert!(method_self_arg2::get_count() == 2*2*3*3*5*5*7*7*11*11*13*13*17);
+ assert_eq!(method_self_arg2::get_count(), 2*2*3*3*5*5*7*7*11*11*13*13*17);
}
x.baz();
- unsafe { assert!(COUNT == 2*2*3*3*5*5*7*7*11*11*13*13*17); }
+ unsafe { assert_eq!(COUNT, 2*2*3*3*5*5*7*7*11*11*13*13*17); }
}
x.foo(&x);
- unsafe { assert!(COUNT == 2*3*3*3*5*5*5*7*7*7); }
+ unsafe { assert_eq!(COUNT, 2*3*3*3*5*5*5*7*7*7); }
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(core)]
+#![feature(iter_min_max, cmp_partial, iter_cmp)]
+
use std::fmt::Debug;
use std::cmp::{self, PartialOrd, Ordering};
use std::iter::MinMaxResult::MinMax;
fn bind<B, F>(&self, mut f: F) -> Vec<B> where F: FnMut(&A) -> Vec<B> {
let mut r = Vec::new();
for elt in self {
- r.extend(f(elt).into_iter());
+ r.extend(f(elt));
}
r
}
pub fn main() {
let x: Box<_> = box X{x: 1, y: 2, z: 3};
let y = x;
- assert!((y.y == 2));
+ assert_eq!(y.y, 2);
}
struct X { x: isize, y: isize, z: isize }
-pub fn main() { let x: Box<_> = box X {x: 1, y: 2, z: 3}; let y = x; assert!((y.y == 2)); }
+pub fn main() { let x: Box<_> = box X {x: 1, y: 2, z: 3}; let y = x; assert_eq!(y.y, 2); }
pub fn main() {
let x = box Triple{a: 1, b: 2, c: 3};
let y = test(x);
- assert!((y.c == 3));
+ assert_eq!(y.c, 3);
}
#![allow(unknown_features)]
#![feature(box_syntax)]
-fn test(foo: Box<Vec<isize>> ) { assert!(((*foo)[0] == 10)); }
+fn test(foo: Box<Vec<isize>> ) { assert_eq!((*foo)[0], 10); }
pub fn main() {
let x = box vec!(10);
#![allow(unknown_features)]
#![feature(box_syntax)]
-fn test(foo: Box<Vec<isize>>) { assert!(((*foo)[0] == 10)); }
+fn test(foo: Box<Vec<isize>>) { assert_eq!((*foo)[0], 10); }
pub fn main() {
let x = box vec!(10);
// except according to those terms.
-fn test(foo: isize) { assert!((foo == 10)); }
+fn test(foo: isize) { assert_eq!(foo, 10); }
pub fn main() { let x = 10; test(x); }
pub fn main() {
let x = 10;
let y = x;
- assert!((y == 10));
+ assert_eq!(y, 10);
}
}
fn g() {
- let frob = |mut q: Box<isize>| { *q = 2; assert!(*q == 2); };
+ let frob = |mut q: Box<isize>| { *q = 2; assert_eq!(*q, 2); };
let w = box 37;
frob(w);
fn test2() {
let mut ints = [0; 32];
for i in &mut ints { *i += 22; }
- for i in &ints { assert!(*i == 22); }
+ for i in &ints { assert_eq!(*i, 22); }
}
pub fn main() {
// the contents implement Drop and we hit a panic in the middle of
// construction.
+#![feature(const_fn)]
use std::thread;
-use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
+use std::sync::atomic::{AtomicUsize, Ordering};
-static LOG: AtomicUsize = ATOMIC_USIZE_INIT;
+static LOG: AtomicUsize = AtomicUsize::new(0);
struct D(u8);
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
-#![allow(unknown_features)]
-#![feature(box_syntax, alloc)]
+#![allow(warnings)]
+#![feature(box_syntax, box_heap)]
// Tests that the new `box` syntax works with unique pointers.
assert_eq!(s, "⨐⨁⪠");
let s = "\\{20}";
- let mut correct_s = String::from_str("\\");
+ let mut correct_s = String::from("\\");
correct_s.push_str("{20}");
assert_eq!(s, correct_s);
}
+++ /dev/null
-// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// ignore-test #9839
-// aux-build:no_std_crate.rs
-
-// This tests that crates which link to std can also be linked to crates with
-// #[no_std] that have no lang items.
-
-extern crate no_std_crate;
-
-pub fn main() {
- no_std_crate::foo();
-}
+++ /dev/null
-// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// ignore-test: this has weird linking problems on Linux, and it probably needs a
-// solution along the lines of disabling segmented stacks and/or the
-// stack checks.
-// aux-build:no_std_crate.rs
-
-// This tests that libraries built with #[no_std] can be linked to crates with
-// #[no_std] and actually run.
-
-#![feature(no_std)]
-#![no_std]
-
-extern crate no_std_crate;
-
-// This is an unfortunate thing to have to do on Linux :(
-#[cfg(target_os = "linux")]
-#[doc(hidden)]
-pub mod linkhack {
- #[link_args="-lrustrt -lrt"]
- extern {}
-}
-
-#[start]
-pub fn main(_: isize, _: **u8, _: *u8) -> isize {
- no_std_crate::foo();
- 0
-}
macro_rules! check_option {
($e:expr, $T:ty) => {{
- check_option!($e, $T, |ptr| assert!(*ptr == $e));
+ check_option!($e, $T, |ptr| assert_eq!(*ptr, $e));
}};
($e:expr, $T:ty, |$v:ident| $chk:expr) => {{
assert!(option::Option::None::<$T>.is_none());
macro_rules! check_fancy {
($e:expr, $T:ty) => {{
- check_fancy!($e, $T, |ptr| assert!(*ptr == $e));
+ check_fancy!($e, $T, |ptr| assert_eq!(*ptr, $e));
}};
($e:expr, $T:ty, |$v:ident| $chk:expr) => {{
assert!(E::Nothing::<$T>((), ((), ()), [23; 0]).is_none());
check_type!(vec!(20, 22), Vec<isize> );
let mint: usize = unsafe { mem::transmute(main) };
check_type!(main, fn(), |pthing| {
- assert!(mint == unsafe { mem::transmute(*pthing) })
+ assert_eq!(mint, unsafe { mem::transmute(*pthing) })
});
}
// Testcase for issue #130, operator associativity.
-pub fn main() { assert!((3 * 5 / 2 == 7)); }
+pub fn main() { assert_eq!(3 * 5 / 2, 7); }
pub fn main() {
let x: DerefWithHelper<Option<Foo>, Foo> =
DerefWithHelper { helper: Some(Foo {x: 5}), value: Foo { x: 2 } };
- assert!(x.foo() == 5);
+ assert_eq!(x.foo(), 5);
}
let s = Rc::new("foo".to_string());
assert_eq!(&**s, "foo");
- let mut_s = Rc::new(RefCell::new(String::from_str("foo")));
+ let mut_s = Rc::new(RefCell::new(String::from("foo")));
mut_s.borrow_mut().push_str("bar");
// HACK assert_eq! would panic here because it stores the LHS and RHS in two locals.
- assert!(&**mut_s.borrow() == "foobar");
- assert!(&**mut_s.borrow_mut() == "foobar");
+ assert_eq!(&**mut_s.borrow(), "foobar");
+ assert_eq!(&**mut_s.borrow_mut(), "foobar");
let p = Rc::new(RefCell::new(Point {x: 1, y: 2}));
p.borrow_mut().x = 3;
assert_eq!(*s, "foo".to_string());
assert_eq!((*s), "foo");
- let mut_s = Rc::new(RefCell::new(String::from_str("foo")));
+ let mut_s = Rc::new(RefCell::new(String::from("foo")));
(*(*mut_s).borrow_mut()).push_str("bar");
// assert_eq! would panic here because it stores the LHS and RHS in two locals.
- assert!((*(*mut_s).borrow()) == "foobar");
- assert!((*(*mut_s).borrow_mut()) == "foobar");
+ assert_eq!((*(*mut_s).borrow()), "foobar");
+ assert_eq!((*(*mut_s).borrow_mut()), "foobar");
let p = Rc::new(RefCell::new(Point {x: 1, y: 2}));
(*(*p).borrow_mut()).x = 3;
list.push(foo.clone(), 22);
list.push(bar.clone(), 44);
- assert!(list[&foo] == 22);
- assert!(list[&bar] == 44);
+ assert_eq!(list[&foo], 22);
+ assert_eq!(list[&bar], 44);
- assert!(list[&foo] == 22);
- assert!(list[&bar] == 44);
+ assert_eq!(list[&foo], 22);
+ assert_eq!(list[&bar], 44);
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we choose Deref or DerefMut appropriately based on mutability of ref bindings (#15609).
+
+use std::ops::{Deref, DerefMut};
+
+struct DerefOk<T>(T);
+struct DerefMutOk<T>(T);
+
+impl<T> Deref for DerefOk<T> {
+ type Target = T;
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+impl<T> DerefMut for DerefOk<T> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ panic!()
+ }
+}
+
+impl<T> Deref for DerefMutOk<T> {
+ type Target = T;
+ fn deref(&self) -> &Self::Target {
+ panic!()
+ }
+}
+
+impl<T> DerefMut for DerefMutOk<T> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.0
+ }
+}
+
+fn main() {
+ // Check that mutable ref binding in match picks DerefMut
+ let mut b = DerefMutOk(0);
+ match *b {
+ ref mut n => n,
+ };
+
+ // Check that mutable ref binding in let picks DerefMut
+ let mut y = DerefMutOk(1);
+ let ref mut z = *y;
+
+ // Check that immutable ref binding in match picks Deref
+ let mut b = DerefOk(2);
+ match *b {
+ ref n => n,
+ };
+
+ // Check that immutable ref binding in let picks Deref
+ let mut y = DerefOk(3);
+ let ref z = *y;
+
+ // Check that mixed mutable/immutable ref binding in match picks DerefMut
+ let mut b = DerefMutOk((0, 9));
+ match *b {
+ (ref mut n, ref m) => (n, m),
+ };
+
+ let mut b = DerefMutOk((0, 9));
+ match *b {
+ (ref n, ref mut m) => (n, m),
+ };
+
+ // Check that mixed mutable/immutable ref binding in let picks DerefMut
+ let mut y = DerefMutOk((1, 8));
+ let (ref mut z, ref a) = *y;
+
+ let mut y = DerefMutOk((1, 8));
+ let (ref z, ref mut a) = *y;
+
+ // Check that multiple immutable ref bindings in match picks Deref
+ let mut b = DerefOk((2, 7));
+ match *b {
+ (ref n, ref m) => (n, m),
+ };
+
+ // Check that multiple immutable ref bindings in let picks Deref
+ let mut y = DerefOk((3, 6));
+ let (ref z, ref a) = *y;
+
+ // Check that multiple mutable ref bindings in match picks DerefMut
+ let mut b = DerefMutOk((4, 5));
+ match *b {
+ (ref mut n, ref mut m) => (n, m),
+ };
+
+ // Check that multiple mutable ref bindings in let picks DerefMut
+ let mut y = DerefMutOk((5, 4));
+ let (ref mut z, ref mut a) = *y;
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we choose Deref or DerefMut appropriately based on mutability of ref bindings (#15609).
+
+fn main() {
+ use std::cell::RefCell;
+
+ struct S {
+ node: E,
+ }
+
+ enum E {
+ Foo(u32),
+ Bar,
+ }
+
+ // Check match
+ let x = RefCell::new(S { node: E::Foo(0) });
+
+ let mut b = x.borrow_mut();
+ match b.node {
+ E::Foo(ref mut n) => *n += 1,
+ _ => (),
+ }
+
+ // Check let
+ let x = RefCell::new(0);
+ let mut y = x.borrow_mut();
+ let ref mut z = *y;
+
+ fn foo(a: &mut RefCell<Option<String>>) {
+ if let Some(ref mut s) = *a.borrow_mut() {
+ s.push('a')
+ }
+ }
+}
let s = S { a: 0xff_ff_ff_ffu32, b: 1, c: 0xaa_aa_aa_aa as i32 };
let transd : [u8; 9] = mem::transmute(s);
// Don't worry about endianness, the numbers are palindromic.
- assert!(transd ==
+ assert_eq!(transd,
[0xff, 0xff, 0xff, 0xff,
1,
0xaa, 0xaa, 0xaa, 0xaa]);
let s = S { a: 1u8, b: 2u8, c: 0b10000001_10000001 as i16};
let transd : [u8; 4] = mem::transmute(s);
// Again, no endianness problems.
- assert!(transd ==
+ assert_eq!(transd,
[1, 2, 0b10000001, 0b10000001]);
}
}
unsafe {
let s4 = S4 { a: 1, b: [2,3,4] };
let transd : [u8; 4] = mem::transmute(s4);
- assert!(transd == [1, 2, 3, 4]);
+ assert_eq!(transd, [1, 2, 3, 4]);
let s5 = S5 { a: 1, b: 0xff_00_00_ff };
let transd : [u8; 5] = mem::transmute(s5);
// Don't worry about endianness, the u32 is palindromic.
- assert!(transd == [1, 0xff, 0, 0, 0xff]);
+ assert_eq!(transd, [1, 0xff, 0, 0, 0xff]);
}
}
unsafe {
let s4 = S4(1, [2,3,4]);
let transd : [u8; 4] = mem::transmute(s4);
- assert!(transd == [1, 2, 3, 4]);
+ assert_eq!(transd, [1, 2, 3, 4]);
let s5 = S5(1, 0xff_00_00_ff);
let transd : [u8; 5] = mem::transmute(s5);
// Don't worry about endianness, the u32 is palindromic.
- assert!(transd == [1, 0xff, 0, 0, 0xff]);
+ assert_eq!(transd, [1, 0xff, 0, 0, 0xff]);
}
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Tests parallel codegen - this can fail if the symbol for the anonymous
+// closure in `sum` pollutes the second codegen unit from the first.
+
+// compile-flags: -C codegen_units=2
+
+#![feature(core)]
+#![feature(iter_arith)]
+
+mod a {
+ fn foo() {
+ let x = ["a", "bob", "c"];
+ let len: usize = x.iter().map(|s| s.len()).sum();
+ }
+}
+
+mod b {
+ fn bar() {
+ let x = ["a", "bob", "c"];
+ let len: usize = x.iter().map(|s| s.len()).sum();
+ }
+}
+
+fn main() {
+}
+++ /dev/null
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// ignore-test
-// This checks that preemption works.
-
-// note: halfway done porting to modern rust
-use std::comm;
-
-fn starve_main(alive: Receiver<isize>) {
- println!("signalling main");
- alive.recv();
- println!("starving main");
- let mut i: isize = 0;
- loop { i += 1; }
-}
-
-pub fn main() {
- let (port, chan) = stream();
-
- println!("main started");
- spawn(move|| {
- starve_main(port);
- });
- let mut i: isize = 0;
- println!("main waiting for alive signal");
- chan.send(i);
- println!("main got alive signal");
- while i < 50 { println!("main iterated"); i += 1; }
- println!("main completed");
-}
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// ignore-test
-
-// FIXME: this test is being ignored until signals are implemented
-
-// This test ensures that the 'detach' field on processes does the right thing.
-// By detaching the child process, they should be put into a separate process
-// group. We test this by spawning a detached process, then killing our own
-// group with a signal.
-//
-// Note that the first thing we do is put ourselves in our own process group so
-// we don't interfere with other running tests.
-
-extern crate libc;
-
-use std::io::process;
-use std::io::process::Command;
-use std::io::signal::{Listener, Interrupt};
-
-fn main() {
- unsafe { libc::setsid(); }
-
- // we shouldn't die because of an interrupt
- let mut l = Listener::new();
- l.register(Interrupt).unwrap();
-
- // spawn the child
- let mut p = Command::new("/bin/sh").arg("-c").arg("read a").detached().spawn().unwrap();
-
- // send an interrupt to everyone in our process group
- unsafe { libc::funcs::posix88::signal::kill(0, libc::SIGINT); }
-
- // Wait for the child process to die (terminate it's stdin and the read
- // should fail).
- drop(p.stdin.take());
- match p.wait().unwrap() {
- process::ExitStatus(..) => {}
- process::ExitSignal(..) => panic!()
- }
-}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-android since the dynamic linker sets a SIGPIPE handler (to do
+// a crash report) so inheritance is moot on the entire platform
+
+// libstd ignores SIGPIPE, and other libraries may set signal masks.
+// Make sure that these behaviors don't get inherited to children
+// spawned via std::process, since they're needed for traditional UNIX
+// filter behavior. This test checks that `yes | head` terminates
+// (instead of running forever), and that it does not print an error
+// message about a broken pipe.
+
+use std::process;
+use std::thread;
+
+#[cfg(unix)]
+fn main() {
+ // Just in case `yes` doesn't check for EPIPE...
+ thread::spawn(|| {
+ thread::sleep_ms(5000);
+ process::exit(1);
+ });
+ let output = process::Command::new("sh").arg("-c").arg("yes | head").output().unwrap();
+ assert!(output.status.success());
+ assert!(output.stderr.len() == 0);
+}
+
+#[cfg(not(unix))]
+fn main() {
+ // Not worried about signal masks on other platforms
+}
assert!(i >= 0 && i < 10);
count += i;
}
- assert!(count == 45);
+ assert_eq!(count, 45);
let mut count = 0;
let mut range = 0_usize..10;
assert!(i >= 0 && i < 10);
count += i;
}
- assert!(count == 45);
+ assert_eq!(count, 45);
let mut count = 0;
let mut rf = 3_usize..;
assert!(i >= 3 && i < 13);
count += i;
}
- assert!(count == 75);
+ assert_eq!(count, 75);
let _ = 0_usize..4+4-3;
let _ = 0..foo();
fn main() {
let x = 1+3..4+5;
- assert!(x == (4..9));
+ assert_eq!(x, (4..9));
let x = 1..4+5;
- assert!(x == (1..9));
+ assert_eq!(x, (1..9));
let x = 1+3..4;
- assert!(x == (4..4));
+ assert_eq!(x, (4..4));
let a = Foo { foo: 3 };
let x = a.foo..a.bar();
- assert!(x == (3..5));
+ assert_eq!(x, (3..5));
let x = 1+3..;
- assert!(x == (4..));
+ assert_eq!(x, (4..));
let x = ..1+3;
- assert!(x == (..4));
+ assert_eq!(x, (..4));
let a = &[0, 1, 2, 3, 4, 5, 6];
let x = &a[1+1..2+2];
- assert!(x == &a[2..4]);
+ assert_eq!(x, &a[2..4]);
let x = &a[..1+2];
- assert!(x == &a[..3]);
+ assert_eq!(x, &a[..3]);
let x = &a[1+2..];
- assert!(x == &a[3..]);
+ assert_eq!(x, &a[3..]);
for _i in 2+4..10-3 {}
for _ in 1.. { break; }
let x = [1]..[2];
- assert!(x == (([1])..([2])));
+ assert_eq!(x, (([1])..([2])));
let y = ..;
- assert!(y == (..));
+ assert_eq!(y, (..));
}
struct Point {x: isize, y: isize, z: isize}
-fn f(p: Point) { assert!((p.z == 12)); }
+fn f(p: Point) { assert_eq!(p.z, 12); }
pub fn main() { let x: Point = Point {x: 10, y: 11, z: 12}; f(x); }
// Ideally this would be revised to use no_std, but for now it serves
// well enough to reproduce (and illustrate) the bug from #16687.
-#![feature(alloc)]
+#![feature(heap_api, alloc, oom)]
extern crate alloc;
use std::cmp::PartialEq;
-fn f<T:PartialEq>(o: &mut Option<T>) {
- assert!(*o == None);
+fn f<T:PartialEq+std::fmt::Debug>(o: &mut Option<T>) {
+ assert_eq!(*o, None);
}
pub fn main() {
static BAR: [isize; 4] = [32, 32, 32, 32];
pub fn main() {
- assert!(FOO == BAR);
+ assert_eq!(FOO, BAR);
}
const foo: isize = 4 >> 1;
enum bs { thing = foo }
-pub fn main() { assert!((bs::thing as isize == foo)); }
+pub fn main() { assert_eq!(bs::thing as isize, foo); }
pub fn main() {
let my_total = &Cell::new(10);
- { let pt = shrinky_pointer(my_total); assert!((pt.look_at() == 10)); }
+ { let pt = shrinky_pointer(my_total); assert_eq!(pt.look_at(), 10); }
println!("my_total = {}", my_total.get());
assert_eq!(my_total.get(), 9);
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+#![feature(libc)]
+
+extern crate libc;
+
+#[cfg(windows)]
+extern "system" {
+ fn SetStdHandle(nStdHandle: libc::DWORD, nHandle: libc::HANDLE) -> libc::BOOL;
+}
+
+#[cfg(windows)]
+fn close_stdout() {
+ const STD_OUTPUT_HANDLE: libc::DWORD = -11i32 as libc::DWORD;
+ unsafe { SetStdHandle(STD_OUTPUT_HANDLE, 0 as libc::HANDLE); }
+}
+
+#[cfg(windows)]
+fn main() {
+ close_stdout();
+ println!("hello world");
+}
+
+#[cfg(not(windows))]
+fn main() {}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+#![feature(libc)]
+
+extern crate libc;
+
+#[cfg(windows)]
+extern "system" {
+ pub fn GetStdHandle(which: libc::DWORD) -> libc::HANDLE;
+}
+
+#[cfg(windows)]
+fn close_stdout() {
+ const STD_OUTPUT_HANDLE: libc::DWORD = -11i32 as libc::DWORD;
+ unsafe { libc::CloseHandle(GetStdHandle(STD_OUTPUT_HANDLE)); }
+}
+
+#[cfg(not(windows))]
+fn close_stdout() {
+ unsafe { libc::close(libc::STDOUT_FILENO); }
+}
+
+fn main() {
+ close_stdout();
+ println!("hello world");
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(start, std_misc)]
+#![feature(catch_panic, start)]
use std::ffi::CStr;
use std::process::{Command, Output};
-use std::rt::unwind::try;
+use std::thread;
use std::str;
#[start]
match **argv.offset(1) as char {
'1' => {}
'2' => println!("foo"),
- '3' => assert!(try(|| {}).is_ok()),
- '4' => assert!(try(|| panic!()).is_err()),
+ '3' => assert!(thread::catch_panic(|| {}).is_ok()),
+ '4' => assert!(thread::catch_panic(|| panic!()).is_err()),
'5' => assert!(Command::new("test").spawn().is_err()),
_ => panic!()
}
pub fn main() {
let mut x: Box<_> = box 3;
x = x;
- assert!(*x == 3);
+ assert_eq!(*x, 3);
let mut x = Rc::new(3);
x = x;
- assert!(*x == 3);
+ assert_eq!(*x, 3);
}
mod c {
use a::b::a;
- pub fn bar() { assert!((a::foo() == 1)); }
+ pub fn bar() { assert_eq!(a::foo(), 1); }
}
pub fn main() { c::bar(); }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// pretty-expanded FIXME #23616
-
#![feature(core, std_misc, scoped)]
use std::thread;
use std::sync::Mutex;
enum t<T> { none, some(T), }
-pub fn main() { let x = 10; let x = x + 20; assert!((x == 30)); foo(Vec::new()); }
+pub fn main() { let x = 10; let x = x + 20; assert_eq!(x, 30); foo(Vec::new()); }
// except according to those terms.
-#![feature(core)]
+#![feature(core_simd)]
use std::simd::{i32x4, f32x4, u32x4};
// pretty-expanded FIXME #23616
-#![feature(core)]
-#![feature(simd)]
+#![feature(core_simd)]
pub fn main() {
let _o = None::<std::simd::i32x4>;
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -C debug-assertions
+
+// Check that we do *not* overflow on a number of edge cases.
+// (compare with test/run-fail/overflowing-{lsh,rsh}*.rs)
+
+#![feature(core_simd)]
+
+use std::simd::{i8x16, i16x8, i32x4, i64x2, u8x16, u16x8, u32x4, u64x2};
+
+// (Work around constant-evaluation)
+fn id<T>(x: T) -> T { x }
+
+fn single_i8x16(x: i8) -> i8x16 { i8x16(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, x) }
+fn single_u8x16(x: u8) -> u8x16 { u8x16(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, x) }
+fn single_i16x8(x: i16) -> i16x8 { i16x8(0, 0, 0, 0, 0, 0, 0, x) }
+fn single_u16x8(x: u16) -> u16x8 { u16x8(0, 0, 0, 0, 0, 0, 0, x) }
+fn single_i32x4(x: i32) -> i32x4 { i32x4(0, 0, 0, x) }
+fn single_u32x4(x: u32) -> u32x4 { u32x4(0, 0, 0, x) }
+fn single_i64x2(x: i64) -> i64x2 { i64x2(0, x) }
+fn single_u64x2(x: u64) -> u64x2 { u64x2(0, x) }
+
+fn eq_i8x16(i8x16(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15): i8x16,
+ i8x16(y0, y1, y2, y3, y4, y5, y6, y7, y8, y9, y10, y11, y12, y13, y14, y15): i8x16)
+ -> bool {
+ (x0 == y0) && (x1 == y1) && (x2 == y2) && (x3 == y3)
+ && (x4 == y4) && (x5 == y5) && (x6 == y6) && (x7 == y7)
+ && (x8 == y8) && (x9 == y9) && (x10 == y10) && (x11 == y11)
+ && (x12 == y12) && (x13 == y13) && (x14 == y14) && (x15 == y15)
+}
+fn eq_u8x16(u8x16(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15): u8x16,
+ u8x16(y0, y1, y2, y3, y4, y5, y6, y7, y8, y9, y10, y11, y12, y13, y14, y15): u8x16)
+ -> bool {
+ (x0 == y0) && (x1 == y1) && (x2 == y2) && (x3 == y3)
+ && (x4 == y4) && (x5 == y5) && (x6 == y6) && (x7 == y7)
+ && (x8 == y8) && (x9 == y9) && (x10 == y10) && (x11 == y11)
+ && (x12 == y12) && (x13 == y13) && (x14 == y14) && (x15 == y15)
+}
+fn eq_i16x8(i16x8(x0, x1, x2, x3, x4, x5, x6, x7): i16x8,
+ i16x8(y0, y1, y2, y3, y4, y5, y6, y7): i16x8) -> bool {
+ (x0 == y0) && (x1 == y1) && (x2 == y2) && (x3 == y3)
+ && (x4 == y4) && (x5 == y5) && (x6 == y6) && (x7 == y7)
+}
+fn eq_u16x8(u16x8(x0, x1, x2, x3, x4, x5, x6, x7): u16x8,
+ u16x8(y0, y1, y2, y3, y4, y5, y6, y7): u16x8) -> bool {
+ (x0 == y0) && (x1 == y1) && (x2 == y2) && (x3 == y3)
+ && (x4 == y4) && (x5 == y5) && (x6 == y6) && (x7 == y7)
+}
+fn eq_i32x4(i32x4(x0, x1, x2, x3): i32x4, i32x4(y0, y1, y2, y3): i32x4) -> bool {
+ (x0 == y0) && (x1 == y1) && (x2 == y2) && (x3 == y3)
+}
+fn eq_u32x4(u32x4(x0, x1, x2, x3): u32x4, u32x4(y0, y1, y2, y3): u32x4) -> bool {
+ (x0 == y0) && (x1 == y1) && (x2 == y2) && (x3 == y3)
+}
+fn eq_i64x2(i64x2(x0, x1): i64x2, i64x2(y0, y1): i64x2) -> bool {
+ (x0 == y0) && (x1 == y1)
+}
+fn eq_u64x2(u64x2(x0, x1): u64x2, u64x2(y0, y1): u64x2) -> bool {
+ (x0 == y0) && (x1 == y1)
+}
+
+fn main() {
+ test_left_shift();
+ test_right_shift();
+}
+
+fn test_left_shift() {
+ // negative rhs can panic, but values in [0,N-1] are okay for iN
+
+ macro_rules! tests {
+ ($single:ident, $eq:ident, $max_rhs:expr, $expect:expr) => { {
+ let x = $single(1) << id($single(0));
+ assert!($eq(x, $single(1)));
+ let x = $single(1) << id($single($max_rhs));
+ assert!($eq(x, $single($expect)));
+ // high-order bits on LHS are silently discarded without panic.
+ let x = $single(3) << id($single($max_rhs));
+ assert!($eq(x, $single($expect)));
+ } }
+ }
+
+ let x = single_i8x16(1) << id(single_i8x16(0));
+ assert!(eq_i8x16(x, single_i8x16(1)));
+ let x = single_u8x16(1) << id(single_u8x16(0));
+ assert!(eq_u8x16(x, single_u8x16(1)));
+ let x = single_i8x16(1) << id(single_i8x16(7));
+ assert!(eq_i8x16(x, single_i8x16(std::i8::MIN)));
+ let x = single_u8x16(1) << id(single_u8x16(7));
+ assert!(eq_u8x16(x, single_u8x16(0x80)));
+ // high-order bits on LHS are silently discarded without panic.
+ let x = single_i8x16(3) << id(single_i8x16(7));
+ assert!(eq_i8x16(x, single_i8x16(std::i8::MIN)));
+ let x = single_u8x16(3) << id(single_u8x16(7));
+ assert!(eq_u8x16(x, single_u8x16(0x80)));
+
+ // above is (approximately) expanded from:
+ tests!(single_i8x16, eq_i8x16, 7, std::i8::MIN);
+ tests!(single_u8x16, eq_u8x16, 7, 0x80_u8);
+
+ tests!(single_i16x8, eq_i16x8, 15, std::i16::MIN);
+ tests!(single_u16x8, eq_u16x8, 15, 0x8000_u16);
+
+ tests!(single_i32x4, eq_i32x4, 31, std::i32::MIN);
+ tests!(single_u32x4, eq_u32x4, 31, 0x8000_0000_u32);
+
+ tests!(single_i64x2, eq_i64x2, 63, std::i64::MIN);
+ tests!(single_u64x2, eq_u64x2, 63, 0x8000_0000_0000_0000_u64);
+}
+
+fn test_right_shift() {
+ // negative rhs can panic, but values in [0,N-1] are okay for iN
+
+ macro_rules! tests {
+ ($single_i:ident, $eq_i:ident, $single_u:ident, $eq_u:ident,
+ $max_rhs:expr, $signbit_i:expr, $highbit_i:expr, $highbit_u:expr) => { {
+ let x = $single_i(1) >> id($single_i(0));
+ assert!($eq_i(x, $single_i(1)));
+ let x = $single_u(1) >> id($single_u(0));
+ assert!($eq_u(x, $single_u(1)));
+ let x = $single_u($highbit_i) >> id($single_u($max_rhs-1));
+ assert!($eq_u(x, $single_u(1)));
+ let x = $single_u($highbit_u) >> id($single_u($max_rhs));
+ assert!($eq_u(x, $single_u(1)));
+ // sign-bit is carried by arithmetic right shift
+ let x = $single_i($signbit_i) >> id($single_i($max_rhs));
+ assert!($eq_i(x, $single_i(-1)));
+ // low-order bits on LHS are silently discarded without panic.
+ let x = $single_u($highbit_i + 1) >> id($single_u($max_rhs-1));
+ assert!($eq_u(x, $single_u(1)));
+ let x = $single_u($highbit_u + 1) >> id($single_u($max_rhs));
+ assert!($eq_u(x, $single_u(1)));
+ let x = $single_i($signbit_i + 1) >> id($single_i($max_rhs));
+ assert!($eq_i(x, $single_i(-1)));
+ } }
+ }
+
+ tests!(single_i8x16, eq_i8x16, single_u8x16, eq_u8x16,
+ 7, std::i8::MIN, 0x40_u8, 0x80_u8);
+ tests!(single_i16x8, eq_i16x8, single_u16x8, eq_u16x8,
+ 15, std::i16::MIN, 0x4000_u16, 0x8000_u16);
+ tests!(single_i32x4, eq_i32x4, single_u32x4, eq_u32x4,
+ 31, std::i32::MIN, 0x4000_0000_u32, 0x8000_0000_u32);
+ tests!(single_i64x2, eq_i64x2, single_u64x2, eq_u64x2,
+ 63, std::i64::MIN, 0x4000_0000_0000_0000_u64, 0x8000_0000_0000_0000_u64);
+}
fn main() {
let x: &[isize] = &[1, 2, 3, 4, 5];
let cmp: &[isize] = &[1, 2, 3, 4, 5];
- assert!(&x[..] == cmp);
+ assert_eq!(&x[..], cmp);
let cmp: &[isize] = &[3, 4, 5];
- assert!(&x[2..] == cmp);
+ assert_eq!(&x[2..], cmp);
let cmp: &[isize] = &[1, 2, 3];
- assert!(&x[..3] == cmp);
+ assert_eq!(&x[..3], cmp);
let cmp: &[isize] = &[2, 3, 4];
- assert!(&x[1..4] == cmp);
+ assert_eq!(&x[1..4], cmp);
let x: Vec<isize> = vec![1, 2, 3, 4, 5];
let cmp: &[isize] = &[1, 2, 3, 4, 5];
- assert!(&x[..] == cmp);
+ assert_eq!(&x[..], cmp);
let cmp: &[isize] = &[3, 4, 5];
- assert!(&x[2..] == cmp);
+ assert_eq!(&x[2..], cmp);
let cmp: &[isize] = &[1, 2, 3];
- assert!(&x[..3] == cmp);
+ assert_eq!(&x[..3], cmp);
let cmp: &[isize] = &[2, 3, 4];
- assert!(&x[1..4] == cmp);
+ assert_eq!(&x[1..4], cmp);
let x: &mut [isize] = &mut [1, 2, 3, 4, 5];
{
let cmp: &mut [isize] = &mut [1, 2, 3, 4, 5];
- assert!(&mut x[..] == cmp);
+ assert_eq!(&mut x[..], cmp);
}
{
let cmp: &mut [isize] = &mut [3, 4, 5];
- assert!(&mut x[2..] == cmp);
+ assert_eq!(&mut x[2..], cmp);
}
{
let cmp: &mut [isize] = &mut [1, 2, 3];
- assert!(&mut x[..3] == cmp);
+ assert_eq!(&mut x[..3], cmp);
}
{
let cmp: &mut [isize] = &mut [2, 3, 4];
- assert!(&mut x[1..4] == cmp);
+ assert_eq!(&mut x[1..4], cmp);
}
let mut x: Vec<isize> = vec![1, 2, 3, 4, 5];
{
let cmp: &mut [isize] = &mut [1, 2, 3, 4, 5];
- assert!(&mut x[..] == cmp);
+ assert_eq!(&mut x[..], cmp);
}
{
let cmp: &mut [isize] = &mut [3, 4, 5];
- assert!(&mut x[2..] == cmp);
+ assert_eq!(&mut x[2..], cmp);
}
{
let cmp: &mut [isize] = &mut [1, 2, 3];
- assert!(&mut x[..3] == cmp);
+ assert_eq!(&mut x[..3], cmp);
}
{
let cmp: &mut [isize] = &mut [2, 3, 4];
- assert!(&mut x[1..4] == cmp);
+ assert_eq!(&mut x[1..4], cmp);
}
}
// compile-flags: -C debug-assertions
-#![feature(core)]
+#![feature(iter_to_slice)]
use std::slice;
fn main() {
let _ = thread::spawn(move|| foo()).join();
- unsafe { assert!(DTOR_COUNT == 2); }
+ unsafe { assert_eq!(DTOR_COUNT, 2); }
}
fn main() {
let _ = thread::spawn(move|| foo()).join();
- unsafe { assert!(DTOR_COUNT == 2); }
+ unsafe { assert_eq!(DTOR_COUNT, 2); }
}
&mut x[..Foo];
&mut x[Foo..Foo];
unsafe {
- assert!(COUNT == 8);
+ assert_eq!(COUNT, 8);
}
}
thread::spawn(move|| child(10)).join().ok().unwrap();
}
-fn child(i: isize) { println!("{}", i); assert!((i == 10)); }
+fn child(i: isize) { println!("{}", i); assert_eq!(i, 10); }
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// pretty-expanded FIXME #23616
-
-#![feature(static_assert)]
-
-#[static_assert]
-static b: bool = true;
-
-#[static_assert]
-static c: bool = 1 == 1;
-
-#[static_assert]
-static d: bool = 1 != 2;
-
-#[static_assert]
-static f: bool = (4/2) == 2;
-
-pub fn main() {
-}
}
unsafe fn run() {
- assert!(rust_dbg_static_mut == 3);
+ assert_eq!(rust_dbg_static_mut, 3);
rust_dbg_static_mut = 4;
- assert!(rust_dbg_static_mut == 4);
+ assert_eq!(rust_dbg_static_mut, 4);
rust_dbg_static_mut_check_four();
rust_dbg_static_mut += 1;
- assert!(rust_dbg_static_mut == 5);
+ assert_eq!(rust_dbg_static_mut, 5);
rust_dbg_static_mut *= 3;
- assert!(rust_dbg_static_mut == 15);
+ assert_eq!(rust_dbg_static_mut, 15);
rust_dbg_static_mut = -3;
- assert!(rust_dbg_static_mut == -3);
+ assert_eq!(rust_dbg_static_mut, -3);
static_bound(&rust_dbg_static_mut);
static_bound_set(&mut rust_dbg_static_mut);
}
}
unsafe fn run() {
- assert!(static_mut_xc::a == 3);
+ assert_eq!(static_mut_xc::a, 3);
static_mut_xc::a = 4;
- assert!(static_mut_xc::a == 4);
+ assert_eq!(static_mut_xc::a, 4);
static_mut_xc::a += 1;
- assert!(static_mut_xc::a == 5);
+ assert_eq!(static_mut_xc::a, 5);
static_mut_xc::a *= 3;
- assert!(static_mut_xc::a == 15);
+ assert_eq!(static_mut_xc::a, 15);
static_mut_xc::a = -3;
- assert!(static_mut_xc::a == -3);
+ assert_eq!(static_mut_xc::a, -3);
static_bound(&static_mut_xc::a);
static_bound_set(&mut static_mut_xc::a);
}
// pretty-expanded FIXME #23616
-#![feature(std_misc, alloc, static_condvar)]
+#![feature(static_mutex, static_rwlock, static_condvar)]
+#![feature(arc_weak, semaphore)]
use std::sync;
fn main() {
let x = "\\\\\
";
- assert!(x == r"\\"); // extraneous whitespace stripped
+ assert_eq!(x, r"\\"); // extraneous whitespace stripped
}
// Checks that functional-record-update order-of-eval is as expected
// even when no Drop-implementations are involved.
+#![feature(const_fn)]
-use std::sync::atomic::{Ordering, AtomicUsize, ATOMIC_USIZE_INIT};
+use std::sync::atomic::{Ordering, AtomicUsize};
struct W { wrapped: u32 }
struct S { f0: W, _f1: i32 }
"expect: 0x{:x} actual: 0x{:x}", expect, actual);
}
-static LOG: AtomicUsize = ATOMIC_USIZE_INIT;
+static LOG: AtomicUsize = AtomicUsize::new(0);
fn event_log() -> usize {
LOG.load(Ordering::SeqCst)
// Checks that struct-literal expression order-of-eval is as expected
// even when no Drop-implementations are involved.
+#![feature(const_fn)]
-use std::sync::atomic::{Ordering, AtomicUsize, ATOMIC_USIZE_INIT};
+use std::sync::atomic::{Ordering, AtomicUsize};
struct W { wrapped: u32 }
struct S { f0: W, _f1: i32 }
"expect: 0x{:x} actual: 0x{:x}", expect, actual);
}
-static LOG: AtomicUsize = ATOMIC_USIZE_INIT;
+static LOG: AtomicUsize = AtomicUsize::new(0);
fn event_log() -> usize {
LOG.load(Ordering::SeqCst)
println!("{:?}", true as isize);
println!("{:?}", true as usize);
- println!("{:?}", true as *const libc::FILE);
println!("{:?}", true as i8);
println!("{:?}", true as i16);
println!("{:?}", true as i32);
println!("{:?}", true as u16);
println!("{:?}", true as u32);
println!("{:?}", true as u64);
- println!("{:?}", true as f32);
- println!("{:?}", true as f64);
println!("{:?}", 1f32 as isize);
println!("{:?}", 1f32 as usize);
pub fn main() {
let mut x = 3; let mut y = 7;
swap(&mut x, &mut y);
- assert!((x == 7)); assert!((y == 3));
+ assert_eq!(x, 7);
+ assert_eq!(y, 3);
}
// pretty-expanded FIXME #23616
-#![allow(unused_mut)]
+#![allow(warnings)]
#![feature(collections)]
-#![feature(collections_drain)]
+#![feature(drain, enumset, collections_bound, btree_range, vecmap)]
extern crate collections;
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// pretty-expanded FIXME #23616
+
+#![allow(warnings)]
+#![feature(iter_empty)]
+#![feature(iter_once)]
+#![feature(iter_unfold)]
+#![feature(range_inclusive)]
+#![feature(step_by)]
+#![feature(str_escape)]
+
+use std::iter::{empty, once, range_inclusive, repeat, Unfold};
+
+fn is_sync<T>(_: T) where T: Sync {}
+fn is_send<T>(_: T) where T: Send {}
+
+macro_rules! all_sync_send {
+ ($ctor:expr, $iter:ident) => ({
+ let mut x = $ctor;
+ is_sync(x.$iter());
+ let mut y = $ctor;
+ is_send(y.$iter());
+ });
+ ($ctor:expr, $iter:ident($($param:expr),+)) => ({
+ let mut x = $ctor;
+ is_sync(x.$iter($( $param ),+));
+ let mut y = $ctor;
+ is_send(y.$iter($( $param ),+));
+ });
+ ($ctor:expr, $iter:ident, $($rest:tt)*) => ({
+ all_sync_send!($ctor, $iter);
+ all_sync_send!($ctor, $($rest)*);
+ });
+ ($ctor:expr, $iter:ident($($param:expr),+), $($rest:tt)*) => ({
+ all_sync_send!($ctor, $iter($( $param ),+));
+ all_sync_send!($ctor, $($rest)*);
+ });
+}
+
+macro_rules! all_sync_send_mutable_ref {
+ ($ctor:expr, $($iter:ident),+) => ({
+ $(
+ let mut x = $ctor;
+ is_sync((&mut x).$iter());
+ let mut y = $ctor;
+ is_send((&mut y).$iter());
+ )+
+ })
+}
+
+macro_rules! is_sync_send {
+ ($ctor:expr) => ({
+ let x = $ctor;
+ is_sync(x);
+ let y = $ctor;
+ is_send(y);
+ })
+}
+
+fn main() {
+ // for char.rs
+ all_sync_send!("Я", escape_default, escape_unicode);
+
+ // for iter.rs
+ all_sync_send_mutable_ref!([1], iter);
+
+ // Bytes implements DoubleEndedIterator
+ all_sync_send!("a".bytes(), rev);
+
+ let a = [1];
+ let b = [2];
+ all_sync_send!(a.iter(),
+ cloned,
+ cycle,
+ chain([2].iter()),
+ zip([2].iter()),
+ map(|_| 1),
+ filter(|_| true),
+ filter_map(|_| Some(1)),
+ enumerate,
+ peekable,
+ skip_while(|_| true),
+ take_while(|_| true),
+ skip(1),
+ take(1),
+ scan(1, |_, _| Some(1)),
+ flat_map(|_| b.iter()),
+ fuse,
+ inspect(|_| ()));
+
+ is_sync_send!(Unfold::new(Some(1), |&mut v| v));
+ is_sync_send!((1..).step_by(2));
+ is_sync_send!(range_inclusive(1, 1));
+ is_sync_send!((1..2).step_by(2));
+ is_sync_send!((1..2));
+ is_sync_send!((1..));
+ is_sync_send!(repeat(1));
+ is_sync_send!(empty::<usize>());
+ is_sync_send!(once(1));
+
+ // for option.rs
+ // FIXME
+
+ // for result.rs
+ // FIXME
+
+ // for slice.rs
+ // FIXME
+
+ // for str/mod.rs
+ // FIXME
+}
{
assert!(file!().ends_with("includeme.fragment"));
- assert!(line!() == 5u32);
+ assert_eq!(line!(), 5u32);
format!("victory robot {}", line!())
}
pub fn main() {
assert_eq!(line!(), 27);
- assert!((column!() == 4));
+ assert_eq!(column!(), 4);
assert_eq!(indirect_line!(), 29);
assert!((file!().ends_with("syntax-extension-source-utils.rs")));
assert_eq!(stringify!((2*3) + 5).to_string(), "( 2 * 3 ) + 5".to_string());
}
fn test_color(color: color, val: isize, name: String) {
- //assert!(unsafe::transmute(color) == val);
+ //assert_eq!(unsafe::transmute(color), val);
assert_eq!(color as isize, val);
- assert!(get_color_alt(color) == name);
- assert!(get_color_if(color) == name);
+ assert_eq!(get_color_alt(color), name);
+ assert_eq!(get_color_if(color), name);
}
fn get_color_alt(color: color) -> String {
let mut a;
let mut b;
a = rx.recv().unwrap();
- assert!(a == "A".to_string());
+ assert_eq!(a, "A".to_string());
println!("{}", a);
b = rx.recv().unwrap();
- assert!(b == "B".to_string());
+ assert_eq!(b, "B".to_string());
println!("{}", b);
}
fn check_legs(arc: Arc<Vec<Box<Pet+Sync+Send>>>) {
let mut legs = 0;
- for pet in &*arc {
+ for pet in arc.iter() {
legs += pet.num_legs();
}
assert!(legs == 12);
}
fn check_names(arc: Arc<Vec<Box<Pet+Sync+Send>>>) {
- for pet in &*arc {
+ for pet in arc.iter() {
// FIXME (#22405): Replace `Box::new` with `box` here when/if possible.
pet.name(Box::new(|name| {
assert!(name.as_bytes()[0] == 'a' as u8 && name.as_bytes()[1] == 'l' as u8);
}
}
fn check_pedigree(arc: Arc<Vec<Box<Pet+Sync+Send>>>) {
- for pet in &*arc {
+ for pet in arc.iter() {
assert!(pet.of_good_pedigree());
}
}
+++ /dev/null
-// ignore-test
-
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// This is an interesting test case. We have a trait (Bar) that is
-// implemented for a `Box<Foo>` object (note: no bounds). And then we
-// have a `Box<Foo+Send>` object. The impl for `Box<Foo>` is applicable
-// to `Box<Foo+Send>` because:
-//
-// 1. The trait Bar is contravariant w/r/t Self because `Self` appears
-// only in argument position.
-// 2. The impl provides `Bar for Box<Foo>`
-// 3. The fn `wants_bar()` requires `Bar for Box<Foo:Send>`.
-// 4. `Bar for Box<Foo> <: Bar for Box<Foo:Send>` because
-// `Box<Foo:Send> <: Box<Foo>`.
-
-#![allow(unknown_features)]
-#![feature(box_syntax)]
-
-trait Foo { }
-struct SFoo;
-impl Foo for SFoo { }
-
-trait Bar { fn dummy(&self); }
-impl Bar for Box<Foo> { fn dummy(&self) { } }
-
-fn wants_bar<B:Bar>(b: &B) { }
-
-fn main() {
- let x: Box<Foo+Send> = (box SFoo);
- wants_bar(&x);
-}
T::foo(x);
T::bar();
- unsafe { assert!(COUNT == 12); }
+ unsafe { assert_eq!(COUNT, 12); }
// Cross-crait case
let x: &Bar = &Foo;
pub fn main() {
let (x, y) = (mi(3), mi(5));
let z = f(x, y);
- assert!(z.val == 8)
+ assert_eq!(z.val, 8)
}
}
pub fn main() {
- assert!(1.to_string_() == "1".to_string());
- assert!((vec!(2, 3, 4)).to_string_() == "[2, 3, 4]".to_string());
+ assert_eq!(1.to_string_(), "1".to_string());
+ assert_eq!((vec!(2, 3, 4)).to_string_(), "[2, 3, 4]".to_string());
fn indirect<T:to_str>(x: T) -> String {
format!("{}!", x.to_string_())
}
- assert!(indirect(vec!(10, 20)) == "[10, 20]!".to_string());
+ assert_eq!(indirect(vec!(10, 20)), "[10, 20]!".to_string());
fn indirect2<T:to_str>(x: T) -> String {
indirect(x)
}
- assert!(indirect2(vec!(1)) == "[1]!".to_string());
+ assert_eq!(indirect2(vec!(1)), "[1]!".to_string());
}
//
pub trait Clone2 {
- /// Returns a copy of the value. The contents of owned pointers
+ /// Returns a copy of the value. The contents of boxes
/// are copied to maintain uniqueness, while the contents of
/// managed pointers are not copied.
fn clone(&self) -> Self;
// except according to those terms.
-#![feature(core)]
+#![feature(core_intrinsics)]
use std::intrinsics::type_name;
fn a(a: A) -> isize { return a.a; }
-pub fn main() { let x: A = A {a: 1}; assert!((a(x) == 1)); }
+pub fn main() { let x: A = A {a: 1}; assert_eq!(a(x), 1); }
assert_eq!(size_of::<u>(), 3 as usize);
// Alignment causes padding before the char and the u32.
- assert!(size_of::<v>() ==
+ assert_eq!(size_of::<v>(),
16 as usize);
assert_eq!(size_of::<isize>(), size_of::<usize>());
assert_eq!(size_of::<w>(), size_of::<isize>());
// aux-build:typeid-intrinsic2.rs
-#![feature(hash, core)]
+#![feature(hash_default, core_intrinsics)]
extern crate typeid_intrinsic as other1;
extern crate typeid_intrinsic2 as other2;
pub fn main() {
let (x, y) = (10, 20);
let z = x + y;
- assert!((z == 30));
+ assert_eq!(z, 30);
}
// except according to those terms.
-#![feature(collections, rand, into_cow)]
+#![feature(collections, rand, into_cow, map_in_place, bitvec)]
+#![allow(warnings)]
use std::borrow::{Cow, IntoCow};
use std::collections::BitVec;
fn main() {
let x = call_it(S, 1);
let y = call_box(&mut S, 1);
- assert!(x == 4);
- assert!(y == 4);
+ assert_eq!(x, 4);
+ assert_eq!(y, 4);
}
//
// error: internal compiler error: get_unique_type_id_of_type() -
// unexpected type: closure,
-// ty_closure(syntax::ast::DefId{krate: 0, node: 66},
+// TyClosure(syntax::ast::DefId{krate: 0, node: 66},
// ReScope(63))
//
// This is a regression test for issue #17021.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(core)]
+#![feature(iter_unfold)]
use std::iter::Unfold;
pub fn main() {
let i: Box<_> = box 100;
- assert!(i == box 100);
+ assert_eq!(i, box 100);
assert!(i < box 101);
assert!(i <= box 100);
assert!(i > box 99);
pub fn main() {
let vect : Vec<Box<_>> = vec!(box 100);
- assert!(vect[0] == box 100);
+ assert_eq!(vect[0], box 100);
}
#![feature(box_syntax)]
use std::cmp::PartialEq;
+use std::fmt::Debug;
fn sendable() {
- fn f<T:Send + PartialEq>(i: T, j: T) {
- assert!(i == j);
+ fn f<T:Send + PartialEq + Debug>(i: T, j: T) {
+ assert_eq!(i, j);
}
fn g<T:Send + PartialEq>(i: T, j: T) {
fn copyable() {
- fn f<T:PartialEq>(i: T, j: T) {
- assert!(i == j);
+ fn f<T:PartialEq + Debug>(i: T, j: T) {
+ assert_eq!(i, j);
}
fn g<T:PartialEq>(i: T, j: T) {
fn noncopyable() {
- fn f<T:PartialEq>(i: T, j: T) {
- assert!(i == j);
+ fn f<T:PartialEq + Debug>(i: T, j: T) {
+ assert_eq!(i, j);
}
fn g<T:PartialEq>(i: T, j: T) {
// Test structs with always-unsized fields.
-#![allow(unknown_features)]
-#![feature(box_syntax, core)]
+#![allow(warnings)]
+#![feature(box_syntax, unsize, raw)]
use std::mem;
use std::raw;
let data: Box<Foo_<i32>> = box Foo_{f: [1, 2, 3] };
let x: &Foo<i32> = mem::transmute(slice::from_raw_parts(&*data, 3));
- assert!(x.f.len() == 3);
- assert!(x.f[0] == 1);
+ assert_eq!(x.f.len(), 3);
+ assert_eq!(x.f[0], 1);
struct Baz_ {
f1: usize,
let data: Box<_> = box Baz_ {
f1: 42, f2: ['a' as u8, 'b' as u8, 'c' as u8, 'd' as u8, 'e' as u8] };
let x: &Baz = mem::transmute(slice::from_raw_parts(&*data, 5));
- assert!(x.f1 == 42);
+ assert_eq!(x.f1, 42);
let chs: Vec<char> = x.f2.chars().collect();
- assert!(chs.len() == 5);
- assert!(chs[0] == 'a');
- assert!(chs[1] == 'b');
- assert!(chs[2] == 'c');
- assert!(chs[3] == 'd');
- assert!(chs[4] == 'e');
+ assert_eq!(chs.len(), 5);
+ assert_eq!(chs[0], 'a');
+ assert_eq!(chs[1], 'b');
+ assert_eq!(chs[2], 'c');
+ assert_eq!(chs[3], 'd');
+ assert_eq!(chs[4], 'e');
struct Qux_ {
f: St
let data: Box<_> = box Qux_{ f: St { f: 234 } };
let x: &Qux = mem::transmute(raw::TraitObject { vtable: obj.vtable,
data: mem::transmute(&*data) });
- assert!(x.f.foo() == 234);
+ assert_eq!(x.f.foo(), 234);
}
}
let s: String = chs.iter().cloned().collect();
let schs: Vec<char> = s.chars().collect();
- assert!(s.len() == 10);
- assert!(s.chars().count() == 4);
- assert!(schs.len() == 4);
- assert!(schs.iter().cloned().collect::<String>() == s);
- assert!(s.char_at(0) == 'e');
- assert!(s.char_at(1) == 'é');
+ assert_eq!(s.len(), 10);
+ assert_eq!(s.chars().count(), 4);
+ assert_eq!(schs.len(), 4);
+ assert_eq!(schs.iter().cloned().collect::<String>(), s);
+ assert_eq!(s.char_at(0), 'e');
+ assert_eq!(s.char_at(1), 'é');
assert!((str::from_utf8(s.as_bytes()).is_ok()));
// invalid prefix
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(collections)]
+#![feature(vec_push_all)]
use std::vec;
// Tests for indexing into box/& [T; n]
let x: [isize; 3] = [1, 2, 3];
let mut x: Box<[isize; 3]> = box x;
- assert!(x[0] == 1);
- assert!(x[1] == 2);
- assert!(x[2] == 3);
+ assert_eq!(x[0], 1);
+ assert_eq!(x[1], 2);
+ assert_eq!(x[2], 3);
x[1] = 45;
- assert!(x[0] == 1);
- assert!(x[1] == 45);
- assert!(x[2] == 3);
+ assert_eq!(x[0], 1);
+ assert_eq!(x[1], 45);
+ assert_eq!(x[2], 3);
let mut x: [isize; 3] = [1, 2, 3];
let x: &mut [isize; 3] = &mut x;
- assert!(x[0] == 1);
- assert!(x[1] == 2);
- assert!(x[2] == 3);
+ assert_eq!(x[0], 1);
+ assert_eq!(x[1], 2);
+ assert_eq!(x[2], 3);
x[1] = 45;
- assert!(x[0] == 1);
- assert!(x[1] == 45);
- assert!(x[2] == 3);
+ assert_eq!(x[0], 1);
+ assert_eq!(x[1], 45);
+ assert_eq!(x[2], 3);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// pretty-expanded FIXME #23616
-
-#![feature(lang_items, start, no_std, core, libc, collections)]
+#![feature(lang_items, start, no_std, core, core_slice_ext, libc, collections)]
#![no_std]
extern crate std as other;
match x {
[2, _, _] => panic!(),
[1, a, b] => {
- assert!([a, b] == [2, 3]);
+ assert_eq!([a, b], [2, 3]);
}
[_, _, _] => panic!(),
}
];
match x {
[ref first, tail..] => {
- assert!(first.string == "foo".to_string());
+ assert_eq!(first.string, "foo".to_string());
assert_eq!(tail.len(), 2);
- assert!(tail[0].string == "bar".to_string());
- assert!(tail[1].string == "baz".to_string());
+ assert_eq!(tail[0].string, "bar".to_string());
+ assert_eq!(tail[1].string, "baz".to_string());
match tail {
[Foo { .. }, _, Foo { .. }, _tail..] => {
// except according to those terms.
-#![feature(rand, core)]
+#![feature(rand, num_bits_bytes)]
+#![feature(const_fn)]
-use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
+use std::sync::atomic::{AtomicUsize, Ordering};
use std::__rand::{thread_rng, Rng};
use std::thread;
static drop_counts: [AtomicUsize; MAX_LEN] =
// FIXME #5244: AtomicUsize is not Copy.
[
- ATOMIC_USIZE_INIT, ATOMIC_USIZE_INIT, ATOMIC_USIZE_INIT,
- ATOMIC_USIZE_INIT, ATOMIC_USIZE_INIT, ATOMIC_USIZE_INIT,
- ATOMIC_USIZE_INIT, ATOMIC_USIZE_INIT, ATOMIC_USIZE_INIT,
- ATOMIC_USIZE_INIT, ATOMIC_USIZE_INIT, ATOMIC_USIZE_INIT,
- ATOMIC_USIZE_INIT, ATOMIC_USIZE_INIT, ATOMIC_USIZE_INIT,
- ATOMIC_USIZE_INIT, ATOMIC_USIZE_INIT, ATOMIC_USIZE_INIT,
- ATOMIC_USIZE_INIT, ATOMIC_USIZE_INIT, ATOMIC_USIZE_INIT,
- ATOMIC_USIZE_INIT, ATOMIC_USIZE_INIT, ATOMIC_USIZE_INIT,
- ATOMIC_USIZE_INIT, ATOMIC_USIZE_INIT, ATOMIC_USIZE_INIT,
- ATOMIC_USIZE_INIT, ATOMIC_USIZE_INIT, ATOMIC_USIZE_INIT,
- ATOMIC_USIZE_INIT, ATOMIC_USIZE_INIT,
+ AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
+ AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
+ AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
+ AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
+ AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
+ AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
+ AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
+ AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
+ AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
+ AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
+ AtomicUsize::new(0), AtomicUsize::new(0),
];
-static creation_count: AtomicUsize = ATOMIC_USIZE_INIT;
+static creation_count: AtomicUsize = AtomicUsize::new(0);
#[derive(Clone, PartialEq, PartialOrd, Eq, Ord)]
struct DropCounter { x: u32, creation_id: usize }
foo1(&x);
foo2(&x);
unsafe {
- assert!(COUNT == 12);
+ assert_eq!(COUNT, 12);
}
}
fn make(i: isize) -> t {
if i > 10 { return t::a; }
- let mut s = String::from_str("hello");
+ let mut s = String::from("hello");
// Ensure s is non-const.
s.push_str("there");
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(core)]
+#![feature(num_wrapping)]
// Test inherent wrapping_* methods for {i,u}{size,8,16,32,64}.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// pretty-expanded FIXME #23616
-
#![feature(std_misc)]
pub type HANDLE = u32;
pub fn main() {
foo();
- assert!((unsafe { destructions } == 0));
+ assert_eq!(unsafe { destructions }, 0);
}
// "fn index<'a>(&'a self, index: I) -> &'a Self::Output"
fn index<'a>(&'a self, index: I) -> &'a Self::Output;
}
+
+// @has assoc_types/fn.use_output.html
+// @has - '//*[@class="rust fn"]' '-> &T::Output'
+pub fn use_output<T: Index<usize>>(obj: &T, index: usize) -> &T::Output {
+ obj.index(index)
+}
+
+pub trait Feed {
+ type Input;
+}
+
+// @has assoc_types/fn.use_input.html
+// @has - '//*[@class="rust fn"]' 'T::Input'
+pub fn use_input<T: Feed>(_feed: &T, _element: T::Input) { }
+
+// @has assoc_types/fn.cmp_input.html
+// @has - '//*[@class="rust fn"]' 'where T::Input: PartialEq<U::Input>'
+pub fn cmp_input<T: Feed, U: Feed>(a: &T::Input, b: &U::Input) -> bool
+ where T::Input: PartialEq<U::Input>
+{
+ a == b
+}
///
/// fn test() {
/// let x = Bar(Foo);
-/// assert!(x == x); // check that the derivings worked
+/// assert_eq!(x, x); // check that the derivings worked
/// }
///
/// }
// @has issue_19190_2/struct.Bar.html
// @has - '//*[@id="method.count_ones"]' 'fn count_ones(self) -> u32'
-
+// @!has - '//*[@id="method.min_value"]' 'fn min_value() -> i32'
// @has issue_19190_3/struct.Foo.html
// @has - '//*[@id="method.count_ones"]' 'fn count_ones(self) -> u32'
+// @!has - '//*[@id="method.min_value"]' 'fn min_value() -> i32'
pub use issue_19190_3::Foo;
// @has issue_19190_3/struct.Bar.html
// @has - '//*[@id="method.baz"]' 'fn baz(&self)'
+// @!has - '//*[@id="method.static_baz"]' 'fn static_baz()'
pub use issue_19190_3::Bar;
// @has issue_19190_3/struct.MyBar.html
// @has - '//*[@id="method.baz"]' 'fn baz(&self)'
+// @!has - '//*[@id="method.static_baz"]' 'fn static_baz()'
pub struct MyBar;
impl Deref for MyBar {
impl Foo {
pub fn foo(&self) {}
+ pub fn static_foo() {}
}
impl Deref for Bar {
// @has issue_19190/struct.Bar.html
// @has - '//*[@id="method.foo"]' 'fn foo(&self)'
+// @!has - '//*[@id="method.static_foo"]' 'fn static_foo()'
#![crate_name = "rustdoc_test"]
+use std::ops::Deref;
+
// @has search-index.js Foo
pub use private::Foo;
fn trait_method(&self) {} // @!has - priv_method
}
}
+
+pub struct Bar;
+
+impl Deref for Bar {
+ // @!has search-index.js Target
+ type Target = Bar;
+ fn deref(&self) -> &Bar { self }
+}
// @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//code' \
// "impl<F> MyTrait for Foxtrot<F> where F: MyTrait"
impl<F> MyTrait for Foxtrot<F> where F: MyTrait {}
+
+// @has foo/type.Golf.html '//pre[@class="rust typedef"]' \
+// "type Golf<T> where T: Clone = (T, T)"
+pub type Golf<T> where T: Clone = (T, T);