diff options
| author | Nick Cameron <ncameron@mozilla.com> | 2015-05-13 15:09:17 +1200 |
|---|---|---|
| committer | Nick Cameron <ncameron@mozilla.com> | 2015-05-13 15:09:17 +1200 |
| commit | 103e52b1db92b9ac57dcebf5c5738ad5a45155ad (patch) | |
| tree | f25dde7fb14152c900f89c7b9c85e63b1439c828 | |
| parent | 5d16772ecb93270ac64b44b429a157f397a3e41d (diff) | |
| parent | c2b30b86df6b34ba19e87e63402e43d9e81a64fb (diff) | |
| download | rust-103e52b1db92b9ac57dcebf5c5738ad5a45155ad.tar.gz rust-103e52b1db92b9ac57dcebf5c5738ad5a45155ad.zip | |
Merge branch 'master' into mulit-decor
85 files changed, 2401 insertions, 900 deletions
diff --git a/AUTHORS.txt b/AUTHORS.txt index 0f20e510adc..e342a3de55a 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -8,6 +8,7 @@ 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> Adam Bozanich <adam.boz@gmail.com> Adam Jacob <adam@opscode.com> Adam Roben <adam@roben.org> @@ -28,6 +29,7 @@ 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 Bliskovsky <alexander.bliskovsky@gmail.com> @@ -41,7 +43,6 @@ Alexandros Tasos <sdi1100085@di.uoa.gr> Alexei Sholik <alcosholik@gmail.com> Alexis Beingessner <a.beingessner@gmail.com> Alfie John <alfie@alfie.wtf> -Alfie John <alfiej@fastmail.fm> Ali Smesseim <smesseim.ali@gmail.com> Alisdair Owens <awo101@zepler.net> Aljaž "g5pw" Srebrnič <a2piratesoft@gmail.com> @@ -64,10 +65,13 @@ Andrew Gallant <jamslam@gmail.com> Andrew Hobden <andrew@hoverbear.org> Andrew Paseltiner <apaseltiner@gmail.com> Andrew Poelstra <asp11@sfu.ca> +Andrew Seidl <dev@aas.io> Andrew Wagner <drewm1980@gmail.com> 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> Ariel Ben-Yehuda <arielb1@mail.tau.ac.il> Arjan Topolovec <arjan.top@gmail.com> @@ -78,6 +82,7 @@ Arpad Borsos <arpad.borsos@googlemail.com> Artem <artemciy@gmail.com> Arthur Liao <arthurtw8@gmail.com> Ashok Gautham <ScriptDevil@gmail.com> +Augusto Hack <hack.augusto@gmail.com> Austin Bonander <austin.bonander@gmail.com> Austin King <shout@ozten.com> Austin Seipp <mad.one@gmail.com> @@ -85,13 +90,14 @@ Axel Viala <axel.viala@darnuria.eu> Aydin Kim <ladinjin@hanmail.net> Barosl Lee <vcs@barosl.com> Ben Alpert <ben@benalpert.com> +Ben Ashford <ben@bcash.org> Ben Blum <bblum@andrew.cmu.edu> Ben Foppa <benjamin.foppa@gmail.com> Ben Gamari <bgamari.foss@gmail.com> Ben Harris <mail@bharr.is> Ben Kelly <ben@wanderview.com> Ben Noordhuis <info@bnoordhuis.nl> -Ben S <ogham@users.noreply.github.com> +Ben Sago <ogham@users.noreply.github.com> Ben Striegel <ben.striegel@gmail.com> Benjamin Adamson <adamson.benjamin@gmail.com> Benjamin Herr <ben@0x539.de> @@ -112,6 +118,7 @@ Brandon Waskiewicz <brandon.waskiewicz@gmail.com> Branimir <branimir@volomp.com> Brendan Cully <brendan@kublai.com> Brendan Eich <brendan@mozilla.org> +Brendan Graetz <github@bguiz.com> Brendan McLoughlin <btmcloughlin@gmail.com> Brendan Zabarauskas <bjzaba@yahoo.com.au> Brett Cannon <brett@python.org> @@ -135,8 +142,8 @@ Camille TJHOA <camille.tjhoa@outlook.com> CarVac <c.lo.to.da.down.lo@gmail.com> Carl Lerche <me@carllerche.com> Carl-Anton Ingmarsson <mail@carlanton.se> -Carlos <toqueteos@gmail.com> -Carol Nichols <carol.nichols@gmail.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> @@ -151,10 +158,11 @@ Chris Peterson <cpeterson@mozilla.com> Chris Pressey <cpressey@gmail.com> Chris Sainty <csainty@hotmail.com> Chris Shea <cmshea@gmail.com> -Chris Thorn <thorn@thoughtbot.com> +Chris Thorn <chris@thorn.co> Chris Wong <lambda.fairy@gmail.com> Christoph Burgdorf <christoph.burgdorf@bvsn.org> Christopher Bergqvist <spambox0@digitalpoetry.se> +Christopher Chambers <chris.chambers@peanutcode.com> Christopher Kendell <ckendell@outlook.com> Chuck Ries <chuck.ries@gmail.com> Clark Gaebel <cg.wowus.cg@gmail.com> @@ -172,13 +180,14 @@ Corey Richardson <corey@octayn.net> Cristi Burcă <scribu@gmail.com> Cristian Kubis <cristian.kubis@tsunix.de> DJUrsus <colinvh@divitu.com> -Dabo Ross <daboross@daboross.net> +David Ross <daboross@daboross.net> Damian Gryski <damian@gryski.com> Damien Grassart <damien@grassart.com> Damien Radtke <dradtke@channeliq.com> Damien Schoof <damien.schoof@gmail.com> Dan Albert <danalbert@google.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> @@ -234,6 +243,8 @@ 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> Dominik Inführ <dominik.infuehr@gmail.com> Donovan Preston <donovanpreston@gmail.com> Douglas Young <rcxdude@gmail.com> @@ -287,11 +298,10 @@ Felix S. Klock II <pnkfelix@pnkfx.org> Fenhl <fenhl@fenhl.net> Filip Szczepański <jazz2rulez@gmail.com> Flaper Fesp <flaper87@gmail.com> -Flavio Percoco <flaper87@gmail.com> Florian Gilcher <florian.gilcher@asquera.de> Florian Hahn <flo@fhahn.com> Florian Hartwig <florian.j.hartwig@gmail.com> -Florian Wilkens <floya@live.de> +Florian Wilkens <mrfloya_github@outlook.com> Florian Zeitz <florob@babelmonkeys.de> Francisco Souza <f@souza.cc> Franklin Chen <franklinchen@franklinchen.com> @@ -310,13 +320,12 @@ Georges Dubus <georges.dubus@gmail.com> Germano Gabbianelli <tyrion@users.noreply.github.com> Gil Cottle <rc@redtown.org> Gioele Barabucci <gioele@svario.it> -GlacJAY <glacjay@gmail.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> -Graydon Hoare <graydon@mozilla.com> +Graydon Hoare <graydon@pobox.com> Greg Chapple <gregchapple1@gmail.com> Grigoriy <ohaistarlight@gmail.com> Guillaume Gomez <guillaume1.gomez@gmail.com> @@ -325,11 +334,13 @@ 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> Harry Marr <harry.marr@gmail.com> Heather <heather@cynede.net> +Heejong Ahn <heejongahn@gmail.com Henrik Schopmans <h.schopmans@googlemail.com> -Herman J. Radtke III <hermanradtke@gmail.com> +Herman J. Radtke III <herman@hermanradtke.com> HeroesGrave <heroesgrave@gmail.com> Hong Chulju <ang0123dev@gmail.com> Honza Strnad <hanny.strnad@gmail.com> @@ -343,6 +354,7 @@ Ian D. Bollinger <ian.bollinger@gmail.com> Ian Daniher <it.daniher@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> @@ -390,7 +402,7 @@ Jashank Jeremy <jashank@rulingia.com> Jason Fager <jfager@gmail.com> Jason Orendorff <jorendorff@mozilla.com> Jason Thompson <jason@jthompson.ca> -Jason Toffaletti <jason@topsy.com> +Jason Toffaletti <toffaletti@gmail.com> Jauhien Piatlicki <jauhien@gentoo.org> Jay Anderson <jayanderson0@gmail.com> Jay True <glacjay@gmail.com> @@ -421,8 +433,10 @@ Jimmie Elvenmark <flugsio@gmail.com> Jimmy Lu <jimmy.lu.2011@gmail.com> Jimmy Zelinskie <jimmyzelinskie@gmail.com> Jiří Stránský <jistr@jistr.com> +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> @@ -436,10 +450,10 @@ John Gallagher <jgallagher@bignerdranch.com> John Hodge <acessdev@gmail.com> John Kåre Alsaker <john.kare.alsaker@gmail.com> John Kleint <jk@hinge.co> -John Kåre Alsaker <john.kare.alsaker@gmail.com> John Louis Walker <injyuw@gmail.com> John Schmidt <john.schmidt.h@gmail.com> John Simon <john@johnsoft.com> +John Talling <inrustwetrust@users.noreply.github.com> John Zhang <john@zhang.io> Jon Haddad <jon@jonhaddad.com> Jon Morton <jonanin@gmail.com> @@ -462,6 +476,7 @@ Joseph Rushton Wakeling <joe@webdrake.net> Josh Haberman <jhaberman@gmail.com> Josh Matthews <josh@joshmatthews.net> Josh Stone <cuviper@gmail.com> +Josh Triplett <josh@joshtriplett.org> Joshua Clark <joshua.clark@txstate.edu> Joshua Wise <joshua@joshuawise.com> Joshua Yanovski <pythonesque@gmail.com> @@ -492,6 +507,7 @@ Kevin Walter <kevin.walter.private@googlemail.com> Kevin Yap <me@kevinyap.ca> Kiet Tran <ktt3ja@gmail.com> Kim Røen <kim@pam.no> +KokaKiwi <kokakiwi+rust@kokakiwi.net> Kostas Karachalios <vrinek@me.com> Kyeongwoon Lee <kyeongwoon.lee@samsung.com> Lai Jiangshan <laijs@cn.fujitsu.com> @@ -515,6 +531,7 @@ Loïc Damien <loic.damien@dzamlo.ch> Luca Bruno <lucab@debian.org> Luis de Bethencourt <luis@debethencourt.com> Luke Francl <look@recursion.org> +Luke Gallagher <luke@hypergeometric.net> Luke Metz <luke.metz@students.olin.edu> Luke Steensen <luke.steensen@gmail.com> Luqman Aden <me@luqman.ca> @@ -523,10 +540,12 @@ Magnus Auvinen <magnus.auvinen@gmail.com> Mahmut Bulut <mahmutbulut0@gmail.com> Makoto Nakashima <makoto.nksm+github@gmail.com> Manish Goregaokar <manishsmail@gmail.com> +Manuel Hoffmann <manuel@polythematik.de> Marcel Rodrigues <marcelgmr@gmail.com> Margaret Meyerhofer <mmeyerho@andrew.cmu.edu> Marijn Haverbeke <marijnh@gmail.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> @@ -563,6 +582,7 @@ Maximilian Haack <mxhaack@gmail.com> Maya Nitu <maya_nitu@yahoo.com> Meyer S. Jacobs <meyermagic@gmail.com> Micah Chalmer <micah@micahchalmer.net> +Michael Alexander <beefsack@gmail.com> Michael Arntzenius <daekharel@gmail.com> Michael Bebenita <mbebenita@mozilla.com> Michael Budde <mbudde@gmail.com> @@ -582,9 +602,12 @@ Michael Sullivan <sully@msully.net> Michael Williams <m.t.williams@live.com> Michael Woerister <michaelwoerister@posteo> 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> Mihnea Dobrescu-Balaur <mihnea@linux.com> Mike Boutin <mike.boutin@gmail.com> Mike Dilger <mike@efx.co.nz> @@ -595,28 +618,28 @@ Mikhail Zabaluev <mikhail.zabaluev@gmail.com> Mikko Perttunen <cyndis@kapsi.fi> Ms2ger <ms2ger@gmail.com> Mukilan Thiagarajan <mukilanthiagarajan@gmail.com> -Mukilan Thiyagarajan <mukilanthiagarajan@gmail.com> Murarth <murarth@gmail.com> Mátyás Mustoha <mmatyas@inf.u-szeged.hu> -NAKASHIMA, Makoto <makoto.nksm+github@gmail.com> NODA, Kai <nodakai@gmail.com> Nafis <nhoss2@gmail.com> Nathan Froyd <froydnj@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@college.harvard.edu> +Nathaniel Herman <nherman@post.harvard.edu> Nathaniel Theis <nttheis@gmail.com> Neil Pankey <npankey@gmail.com> Nelson Chen <crazysim@gmail.com> NiccosSystem <niccossystem@gmail.com> -Nicholas <npmazzuca@gmail.com> Nicholas Bishop <nicholasbishop@gmail.com> Nicholas Mazzuca <npmazzuca@gmail.com> Nick Cameron <ncameron@mozilla.com> Nick Desaulniers <ndesaulniers@mozilla.com> +Nick Hamann <nick@wabbo.org> Nick Howell <howellnick@gmail.com> Nick Sarten <gen.battle@gmail.com> +Nick Platt <platt.nicholas@gmail.com> Nicolas Silva <nical.silva@gmail.com> Niels Egberts <git@nielsegberts.nl> Niels langager Ellegaard <niels.ellegaard@gmail.com> @@ -626,9 +649,10 @@ Niklas Koep <niklas.koep@gmail.com> Niko Matsakis <niko@alum.mit.edu> Noam Yorav-Raphael <noamraph@gmail.com> Noufal Ibrahim <noufal@nibrahim.net.in> +Oak <White-Oak@users.noreply.github.com> O S K Chaitanya <osk@medhas.org> OGINO Masanori <masanori.ogino@gmail.com> -Oliver Schneider <oliver.schneider@kit.edu> +Oliver Schneider <github6541940@oli-obk.de> Olivier Saut <osaut@airpost.net> Olle Jonsson <olle.jonsson@gmail.com> Or Brostovski <tohava@gmail.com> @@ -636,6 +660,7 @@ Or Neeman <oneeman@gmail.com> Oren Hazi <oren.hazi@gmail.com> Orpheus Lummis <o@orpheuslummis.com> Orphée Lafond-Lummis <o@orftz.com> +Ožbolt Menegatti <ozbolt.menegatti@gmail.com> P1start <rewi-github@whanau.org> Pablo Brasero <pablo@pablobm.com> Palmer Cox <p@lmercox.com> @@ -650,6 +675,7 @@ Paul Collier <paul@paulcollier.ca> Paul Collins <paul@ondioline.org> Paul Crowley <paulcrowley@google.com> Paul Osborne <osbpau@gmail.com> +Paul Quint <DrKwint@gmail.com> Paul Stansifer <paul.stansifer@gmail.com> Paul Woolcock <pwoolcoc+github@gmail.com> Pavel Panchekha <me@pavpanchekha.com> @@ -657,7 +683,7 @@ Pawel Olzacki <p.olzacki2@samsung.com> Pedro Larroy <pedro.larroy@here.com> Peer Aramillo Irizar <peer.aramillo.irizar@gmail.com> Peter Atashian <retep998@gmail.com> -Peter Elmers <peter.elmers@yahoo.com> +Peter Elmers <peter.elmers@rice.edu> Peter Hull <peterhull90@gmail.com> Peter Marheine <peter@taricorp.net> Peter Minten <peter@pminten.nl> @@ -675,12 +701,12 @@ 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> Potpourri <pot_pourri@mail.ru> -Pradeep Kumar <gohanpra@gmail.com> Prudhvi Krishna Surapaneni <me@prudhvi.net> +Przemek Wesołek <jest@go.art.pl> Pyfisch <pyfisch@gmail.com> Pyry Kontio <pyry.kontio@drasa.eu> -Pythoner6 <pythoner6@gmail.com> Q.P.Liu <qpliu@yahoo.com> Rafael Ávila de Espíndola <respindola@mozilla.com> Rahul Horé <hore.rahul@gmail.com> @@ -694,9 +720,9 @@ Raphael Speyer <rspeyer@gmail.com> Raul Gutierrez S <rgs@itevenworks.net> Ray Clanan <rclanan@utopianconcept.com> Reilly Watson <reillywatson@gmail.com> +Remi Rampin <remirampin@gmail.com> Renato Alves <alves.rjc@gmail.com> Renato Riccieri Santos Zannon <renato@rrsz.com.br> -Renato Zannon <renato@rrsz.com.br> Reuben Morais <reuben.morais@gmail.com> Ricardo M. Correia <rcorreia@wizy.org> Ricardo Martins <ricardo@scarybox.net> @@ -714,6 +740,7 @@ Robert Irelan <rirelan@gmail.com> Robert Knight <robertknight@gmail.com> Robert Millar <robert.millar@cantab.net> Robin Gloster <robin@loc-com.de> +Robin Kruppe <robin.kruppe@gmail.com> Robin Stocker <robin@nibor.org> Rohit Joshi <rohitjoshi@users.noreply.github.com> Roland Tanglao <roland@rolandtanglao.com> @@ -722,14 +749,13 @@ Rolf van de Krol <info@rolfvandekrol.nl> Ron Dahlgren <ronald.dahlgren@gmail.com> Roy Crihfield <rscrihf@gmail.com> Roy Frostig <rfrostig@mozilla.com> -Russell <rpjohnst@gmail.com> +Russell Johnston <rpjohnst@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> -Ryman <haqkrs@gmail.com> Rüdiger Sonderfeld <ruediger@c-plusplus.de> S Pradeep Kumar <gohanpra@gmail.com> Sae-bom Kim <sae-bom.kim@samsung.com> @@ -745,6 +771,7 @@ Saurabh Anand <saurabhanandiit@gmail.com> Scott Jenkins <scottdjwales@gmail.com> Scott Lawrence <bytbox@gmail.com> Scott Olson <scott@scott-olson.org> +Sean Bowe <ewillbefull@gmail.com> Sean Chalmers <sclhiannan@gmail.com> Sean Collins <sean@cllns.com> Sean Gillespie <sean.william.g@gmail.com> @@ -799,16 +826,18 @@ Taylor Hutchison <seanthutchison@gmail.com> Ted Horst <ted.horst@earthlink.net> Tero Hänninen <lgvz@users.noreply.github.com> Thad Guidry <thadguidry@gmail.com> +Theo Belaire <theo.belaire@gmail.com> Thiago Carvalho <thiago.carvalho@westwing.de> Thiago Pontes <email@thiago.me> Thomas Backman <serenity@exscape.org> +Thomas Bracht Laumann Jespersen <laumann.thomas@gmail.com> Thomas Daede <daede003@umn.edu> Tiago Nobrega <tigarmo@gmail.com> +Tibor Benke <ihrwein@gmail.com> Till Hoeppner <till@hoeppner.ws> Tim Brooks <brooks@cern.ch> Tim Chevalier <chevalier@alum.wellesley.edu> Tim Cuthbertson <tim@gfxmonk.net> -Tim Dumol <tim@timdumol.com> Tim Joseph Dumol <tim@timdumol.com> Tim Kuehn <tkuehn@cmu.edu> Tim Parenti <timparenti@gmail.com> @@ -836,7 +865,7 @@ Trinick <slicksilver555@mac.com> Tristan Storch <tstorch@math.uni-bielefeld.de> Tshepang Lekhonkhobe <tshepang@gmail.com> Tuncer Ayaz <tuncer.ayaz@gmail.com> -TyOverby <ty@pre-alpha.com> +Ty Overby <ty@pre-alpha.com> Tycho Sci <tychosci@gmail.com> Tyler Bindon <martica@martica.org> Tyler Thrailkill <tylerbthrailkill@gmail.com> @@ -870,8 +899,10 @@ WebeWizard <webewizard@gmail.com> Wendell Smith <wendell.smith@yale.edu> Wesley Wiser <wwiser@gmail.com> Will <will@glozer.net> +Will Hipschman <whipsch@gmail.com> William Ting <io@williamting.com> Willson Mock <willson.mock@gmail.com> +Xue Fuqiao <xfq.free@gmail.com> Yasuhiro Fujii <y-fujii@mimosa-pudica.net> YawarRaza7349 <YawarRaza7349@gmail.com> Yazhong Liu <yorkiefixer@gmail.com> @@ -889,27 +920,21 @@ Zack Slayton <zack.slayton@gmail.com> Zbigniew Siciarz <zbigniew@siciarz.net> Ziad Hatahet <hatahet@gmail.com> Zooko Wilcox-O'Hearn <zooko@zooko.com> -adridu59 <adri-from-59@hotmail.fr> -aochagavia <aochagavia92@gmail.com> -areski <areski@gmail.com> arturo <arturo@openframeworks.cc> auREAX <mark@xn--hwg34fba.ws> awlnx <alecweber1994@gmail.com> aydin.kim <aydin.kim@samsung.com> -b1nd <clint.ryan3@gmail.com> bachm <Ab@vapor.com> bcoopers <coopersmithbrian@gmail.com> -blackbeam <aikorsky@gmail.com> +Anatoly Ikorsky <aikorsky@gmail.com> blake2-ppc <ulrik.sverdrup@gmail.com> bluss <bluss> -bombless <bombless@126.com> bors <bors@rust-lang.org> -caipre <platt.nicholas@gmail.com> chitra chromatic <chromatic@wgz.org> comex <comexk@gmail.com> crhino <piraino.chris@gmail.com> -dan@daramos.com <dan@daramos.com> +Daniel Ramos <dan@daramos.com> darkf <lw9k123@gmail.com> defuz <defuz.net@gmail.com> dgoon <dgoon@dgoon.net> @@ -917,6 +942,7 @@ 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> @@ -924,17 +950,13 @@ g3xzh <g3xzh@yahoo.com> gamazeps <gamaz3ps@gmail.com> gareth <gareth@gareth-N56VM.(none)> gentlefolk <cemacken@gmail.com> -gifnksm <makoto.nksm@gmail.com> +github-monoculture <eocene@gmx.com> hansjorg <hansjorg@gmail.com> -iancormac84 <wilnathan@gmail.com> -inrustwetrust <inrustwetrust@users.noreply.github.com> jamesluke <jamesluke@users.noreply.github.com> jatinn <jatinn@users.noreply.github.com> jbranchaud <jbranchaud@gmail.com> -jfager <jfager@gmail.com> jmgrosen <jmgrosen@gmail.com> jmu303 <muj@bc.edu> -joaoxsouls <joaoxsouls@gmail.com> jrincayc <jrincayc@users.noreply.github.com> juxiliary <juxiliary@gmail.com> jxv <joevargas@hush.com> @@ -942,15 +964,12 @@ kgv <mail@kgv.name> kjpgit <kjpgit@users.noreply.github.com> klutzy <klutzytheklutzy@gmail.com> korenchkin <korenchkin2@gmail.com> -kud1ing <github@kudling.de> kulakowski <george.kulakowski@gmail.com> -kvark <kvarkus@gmail.com> kwantam <kwantam@gmail.com> lpy <pylaurent1314@gmail.com> lucy <ne.tetewi@gmail.com> lummax <luogpg@googlemail.com> lyuts <dioxinu@gmail.com> -m-r-r <raybaudroigm@gmail.com> madmalik <matthias.tellen@googlemail.com> maikklein <maikklein@googlemail.com> masklinn <github.com@masklinn.net> @@ -962,21 +981,20 @@ mr.Shu <mr@shu.io> mrec <mike.capp@gmail.com> musitdev <philippe.delrieu@free.fr> nathan dotz <nathan.dotz@gmail.com> -nham <hamann.nick@gmail.com> -niftynif <nif.ward@gmail.com> +Nils Winter <nils.winter@gmail.com> noam <noam@clusterfoo.com> novalis <novalis@novalis.org> nsf <no.smile.face@gmail.com> -nwin <nwin@users.noreply.github.com> -oli-obk <github6541940@oli-obk.de> 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> @@ -990,12 +1008,9 @@ tinaun <tinagma@gmail.com> tshakah <tshakah@gmail.com> ville-h <ville3.14159@gmail.com> visualfc <visualfc@gmail.com> -we <vadim.petrochenkov@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> -zslayton <zack.slayton@gmail.com> -zzmp <zmp@umich.edu> 克雷 <geekcraik@users.noreply.github.com> diff --git a/RELEASES.md b/RELEASES.md index 7da73afb411..3219449edd8 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,79 +1,142 @@ -Version 1.0.0-beta (April 2015) -------------------------------------- - -* ~1100 changes, numerous bugfixes - -* Highlights - - * The big news is that the vast majority of the standard library - is now `#[stable]` -- 75% of the non-deprecated API surface at - last count. Numerous crates are now running on stable - Rust. Starting with this release, it is not possible to use - unstable features on a stable build. - * Arithmetic on basic integer types now - [checks for overflow in debug builds][overflow]. - -* Language - - * [`Send` no longer implies `'static`][send-rfc], which made - possible the [`thread::scoped` API][scoped]. Scoped threads can - borrow data from their parent's stack frame -- safely! - * [UFCS now supports trait-less associated paths][moar-ufcs] like - `MyType::default()`. - * Primitive types [now have inherent methods][prim-inherent], - obviating the need for extension traits like `SliceExt`. - * Methods with `Self: Sized` in their `where` clause are - [considered object-safe][self-sized], allowing many extension - traits like `IteratorExt` to be merged into the traits they - extended. - * You can now [refer to associated types][assoc-where] whose - corresponding trait bounds appear only in a `where` clause. - * The final bits of [OIBIT landed][oibit-final], meaning that - traits like `Send` and `Sync` are now library-defined. - * A [Reflect trait][reflect] was introduced, which means that - downcasting via the `Any` trait is effectively limited to - concrete types. This helps retain the potentially-important - "parametricity" property: generic code cannot behave differently - for different type arguments except in minor ways. - * The `unsafe_destructor` feature is now deprecated in favor of - the [new `dropck`][dropck]. This change is a major reduction in - unsafe code. - * Trait coherence was [revised again][fundamental], this time with - an eye toward API evolution over time. - -* Libraries - - * The new path and IO modules are complete and `#[stable]`. This - was the major library focus for this cycle. - * The path API was [revised][path-normalize] to normalize `.`, - adjusting the tradeoffs in favor of the most common usage. - * A large number of remaining APIs in `std` were also stabilized - during this cycle; about 75% of the non-deprecated API surface - is now stable. - * The new [string pattern API][string-pattern] landed, which makes - the string slice API much more internally consistent and flexible. - * A shiny [framework for Debug implementations][debug-builder] landed. - This makes it possible to opt in to "pretty-printed" debugging output. - * A new set of [generic conversion traits][conversion] replaced - many existing ad hoc traits. - * Generic numeric traits were - [completely removed][num-traits]. This was made possible thanks - to inherent methods for primitive types, and the removal gives - maximal flexibility for designing a numeric hierarchy in the future. - * The `Fn` traits are now related via [inheritance][fn-inherit] - and provide ergonomic [blanket implementations][fn-blanket]. - * The `Index` and `IndexMut` traits were changed to - [take the index by value][index-value], enabling code like - `hash_map["string"]` to work. - * `Copy` now [inherits][copy-clone] from `Clone`, meaning that all - `Copy` data is known to be `Clone` as well. - -* Infrastructure - - * Metadata was tuned, shrinking binaries [by 27%][metadata-shrink]. - * Much headway was made on ecosystem-wide CI, making it possible - to [compare builds for breakage][ci-compare]. - +Version 1.0.0 (May 2015) +======================== + +* ~1500 changes, numerous bugfixes + +Highlights +---------- + +* The vast majority of the standard library is now `#[stable]`. It is + no longer possible to use unstable features with a stable build of + the compiler. +* Many popular crates on [crates.io] now work on the stable release + channel. +* Arithmetic on basic integer types now [checks for overflow in debug + builds][overflow]. + +Language +-------- + +* 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. +* 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 + the `PhantomFn` and `MarkerTrait` lang items, which have been + removed. +* ["-" is no longer a valid character in crate names][cr], the `extern crate + "foo" as bar` syntax has been replaced with `extern crate foo as + bar`, and Cargo now automatically translates "-" in *package* names + to underscore for the crate name. +* [Lifetime shadowing is an error][lt]. +* [`Send` no longer implies `'static`][send-rfc]. +* [UFCS now supports trait-less associated paths][moar-ufcs] like + `MyType::default()`. +* Primitive types [now have inherent methods][prim-inherent], + obviating the need for extension traits like `SliceExt`. +* Methods with `Self: Sized` in their `where` clause are [considered + object-safe][self-sized], allowing many extension traits like + `IteratorExt` to be merged into the traits they extended. +* You can now [refer to associated types][assoc-where] whose + corresponding trait bounds appear only in a `where` clause. +* The final bits of [OIBIT landed][oibit-final], meaning that traits + like `Send` and `Sync` are now library-defined. +* A [Reflect trait][reflect] was introduced, which means that + downcasting via the `Any` trait is effectively limited to concrete + types. This helps retain the potentially-important "parametricity" + property: generic code cannot behave differently for different type + arguments except in minor ways. +* The `unsafe_destructor` feature is now deprecated in favor of the + [new `dropck`][dropck]. This change is a major reduction in unsafe + code. + +Libraries +--------- + +* The `thread_local` module [has been renamed to `std::thread`][th]. +* The methods of `IteratorExt` [have been moved to the `Iterator` + trait itself][ie]. +* Several traits that implement Rust's conventions for type + conversions, `AsMut`, `AsRef`, `From`, and `Into` have been + [centralized in the `std::convert` module][con]. +* The `FromError` trait [was removed in favor of `From`][fe]. +* The basic sleep function [has moved to + `std::thread::sleep_ms`][slp]. +* The `splitn` function now takes an `n` parameter that represents the + number of items yielded by the returned iterator [instead of the + number of 'splits'][spl]. +* [On Unix, all file descriptors are `CLOEXEC` by default][clo]. +* [Derived implementations of `PartialOrd` now order enums according + to their explicitly-assigned discriminants][po]. +* [Methods for searching strings are generic over `Pattern`s][pat], + implemented presently by `&char`, `&str`, `FnMut(char) -> bool` and + some others. +* [In method resolution, object methods are resolved before inherent + methods][meth]. +* [`String::from_str` has been deprecated in favor of the `From` impl, + `String::from`][sf]. +* [`io::Error` implements `Sync`][ios]. +* [The `words` method on `&str` has been replaced with + `split_whitespace`][sw], to avoid answering the tricky question, 'what is + a word?' +* The new path and IO modules are complete and `#[stable]`. This + was the major library focus for this cycle. +* The path API was [revised][path-normalize] to normalize `.`, + adjusting the tradeoffs in favor of the most common usage. +* A large number of remaining APIs in `std` were also stabilized + during this cycle; about 75% of the non-deprecated API surface + is now stable. +* The new [string pattern API][string-pattern] landed, which makes + the string slice API much more internally consistent and flexible. +* A new set of [generic conversion traits][conversion] replaced + many existing ad hoc traits. +* Generic numeric traits were [completely removed][num-traits]. This + was made possible thanks to inherent methods for primitive types, + and the removal gives maximal flexibility for designing a numeric + hierarchy in the future. +* The `Fn` traits are now related via [inheritance][fn-inherit] + and provide ergonomic [blanket implementations][fn-blanket]. +* The `Index` and `IndexMut` traits were changed to + [take the index by value][index-value], enabling code like + `hash_map["string"]` to work. +* `Copy` now [inherits][copy-clone] from `Clone`, meaning that all + `Copy` data is known to be `Clone` as well. + +Misc +---- + +* Many errors now have extended explanations that can be accessed with + the `--explain` flag to `rustc`. +* Many new examples have been added to the standard library + documentation. +* rustdoc has received a number of improvements focused on completion + and polish. +* Metadata was tuned, shrinking binaries [by 27%][metadata-shrink]. +* Much headway was made on ecosystem-wide CI, making it possible + to [compare builds for breakage][ci-compare]. + + +[crates.io]: http://crates.io +[clo]: https://github.com/rust-lang/rust/pull/24034 +[coh]: https://github.com/rust-lang/rfcs/blob/master/text/1023-rebalancing-coherence.md +[con]: https://github.com/rust-lang/rust/pull/23875 +[cr]: https://github.com/rust-lang/rust/pull/23419 +[fe]: https://github.com/rust-lang/rust/pull/23879 +[ie]: https://github.com/rust-lang/rust/pull/23300 +[inv]: https://github.com/rust-lang/rust/pull/23938 +[ios]: https://github.com/rust-lang/rust/pull/24133 +[lex]: https://github.com/rust-lang/rfcs/blob/master/text/0879-small-base-lexing.md +[lt]: https://github.com/rust-lang/rust/pull/24057 +[meth]: https://github.com/rust-lang/rust/pull/24056 +[pat]: https://github.com/rust-lang/rfcs/blob/master/text/0528-string-patterns.md +[po]: https://github.com/rust-lang/rust/pull/24270 +[sf]: https://github.com/rust-lang/rust/pull/24517 +[slp]: https://github.com/rust-lang/rust/pull/23949 +[spl]: https://github.com/rust-lang/rfcs/blob/master/text/0979-align-splitn-with-other-languages.md +[sw]: https://github.com/rust-lang/rfcs/blob/master/text/1054-str-words.md +[th]: https://github.com/rust-lang/rfcs/blob/master/text/0909-move-thread-local-to-std-thread.md [send-rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0458-send-improvements.md [scoped]: http://static.rust-lang.org/doc/master/std/thread/fn.scoped.html [moar-ufcs]: https://github.com/rust-lang/rust/pull/22172 @@ -97,6 +160,7 @@ Version 1.0.0-beta (April 2015) [copy-clone]: https://github.com/rust-lang/rust/pull/23860 [path-normalize]: https://github.com/rust-lang/rust/pull/23229 + Version 1.0.0-alpha.2 (February 2015) ------------------------------------- diff --git a/src/doc/grammar.md b/src/doc/grammar.md index 4897b27dec3..fb7562e7bdf 100644 --- a/src/doc/grammar.md +++ b/src/doc/grammar.md @@ -253,7 +253,7 @@ The two values of the boolean type are written `true` and `false`. ### Symbols ```antlr -symbol : "::" "->" +symbol : "::" | "->" | '#' | '[' | ']' | '(' | ')' | '{' | '}' | ',' | ';' ; ``` @@ -304,7 +304,7 @@ transcriber : '(' transcriber * ')' | '[' transcriber * ']' ## Items ```antlr -item : mod_item | fn_item | type_item | struct_item | enum_item +item : vis ? mod_item | fn_item | type_item | struct_item | enum_item | const_item | static_item | trait_item | impl_item | extern_block ; ``` @@ -322,7 +322,7 @@ mod : [ view_item | item ] * ; #### View items ```antlr -view_item : extern_crate_decl | use_decl ; +view_item : extern_crate_decl | use_decl ';' ; ``` ##### Extern crate declarations @@ -335,14 +335,14 @@ crate_name: ident | ( ident "as" ident ) ##### Use declarations ```antlr -use_decl : "pub" ? "use" [ path "as" ident - | path_glob ] ; +use_decl : vis ? "use" [ path "as" ident + | path_glob ] ; path_glob : ident [ "::" [ path_glob | '*' ] ] ? | '{' path_item [ ',' path_item ] * '}' ; -path_item : ident | "mod" ; +path_item : ident | "self" ; ``` ### Functions @@ -414,16 +414,17 @@ extern_block : [ foreign_fn ] * ; ## Visibility and Privacy -**FIXME:** grammar? - +```antlr +vis : "pub" ; +``` ### Re-exporting and Visibility -**FIXME:** grammar? +See [Use declarations](#use-declarations). ## Attributes ```antlr -attribute : "#!" ? '[' meta_item ']' ; +attribute : '#' '!' ? '[' meta_item ']' ; meta_item : ident [ '=' literal | '(' meta_seq ')' ] ? ; meta_seq : meta_item [ ',' meta_seq ] ? ; @@ -433,26 +434,19 @@ meta_seq : meta_item [ ',' meta_seq ] ? ; ## Statements -**FIXME:** grammar? +```antlr +stmt : decl_stmt | expr_stmt ; +``` ### Declaration statements -**FIXME:** grammar? - -A _declaration statement_ is one that introduces one or more *names* into the -enclosing statement block. The declared names may denote new variables or new -items. +```antlr +decl_stmt : item | let_decl ; +``` #### Item declarations -**FIXME:** grammar? - -An _item declaration statement_ has a syntactic form identical to an -[item](#items) declaration within a module. Declaring an item — a -function, enumeration, structure, type, static, trait, implementation or module -— locally within a statement block is simply a way of restricting its -scope to a narrow region containing all of its uses; it is otherwise identical -in meaning to declaring the item outside the statement block. +See [Items](#items). #### Variable declarations @@ -463,11 +457,21 @@ init : [ '=' ] expr ; ### Expression statements -**FIXME:** grammar? +```antlr +expr_stmt : expr ';' ; +``` ## Expressions -**FIXME:** grammar? +```antlr +expr : literal | path | tuple_expr | unit_expr | struct_expr + | block_expr | method_call_expr | field_expr | array_expr + | idx_expr | range_expr | unop_expr | binop_expr + | paren_expr | call_expr | lambda_expr | while_expr + | loop_expr | break_expr | continue_expr | for_expr + | if_expr | match_expr | if_let_expr | while_let_expr + | return_expr ; +``` #### Lvalues, rvalues and temporaries @@ -479,19 +483,23 @@ init : [ '=' ] expr ; ### Literal expressions -**FIXME:** grammar? +See [Literals](#literals). ### Path expressions -**FIXME:** grammar? +See [Paths](#paths). ### Tuple expressions -**FIXME:** grammar? +```antlr +tuple_expr : '(' [ expr [ ',' expr ] * | expr ',' ] ? ')' ; +``` ### Unit expressions -**FIXME:** grammar? +```antlr +unit_expr : "()" ; +``` ### Structure expressions @@ -507,8 +515,7 @@ struct_expr : expr_path '{' ident ':' expr ### Block expressions ```antlr -block_expr : '{' [ view_item ] * - [ stmt ';' | item ] * +block_expr : '{' [ stmt ';' | item ] * [ expr ] '}' ; ``` @@ -529,7 +536,7 @@ field_expr : expr '.' ident ; ```antlr array_expr : '[' "mut" ? array_elems? ']' ; -array_elems : [expr [',' expr]*] | [expr ',' ".." expr] ; +array_elems : [expr [',' expr]*] | [expr ';' expr] ; ``` ### Index expressions @@ -549,65 +556,60 @@ range_expr : expr ".." expr | ### Unary operator expressions -**FIXME:** grammar? +```antlr +unop_expr : unop expr ; +unop : '-' | '*' | '!' ; +``` ### Binary operator expressions ```antlr -binop_expr : expr binop expr ; +binop_expr : expr binop expr | type_cast_expr + | assignment_expr | compound_assignment_expr ; +binop : arith_op | bitwise_op | lazy_bool_op | comp_op ``` #### Arithmetic operators -**FIXME:** grammar? +```antlr +arith_op : '+' | '-' | '*' | '/' | '%' ; +``` #### Bitwise operators -**FIXME:** grammar? +```antlr +bitwise_op : '&' | '|' | '^' | "<<" | ">>" ; +``` #### Lazy boolean operators -**FIXME:** grammar? +```antlr +lazy_bool_op : "&&" | "||" ; +``` #### Comparison operators -**FIXME:** grammar? +```antlr +comp_op : "==" | "!=" | '<' | '>' | "<=" | ">=" ; +``` #### Type cast expressions -**FIXME:** grammar? +```antlr +type_cast_expr : value "as" type ; +``` #### Assignment expressions -**FIXME:** grammar? +```antlr +assignment_expr : expr '=' expr ; +``` #### Compound assignment expressions -**FIXME:** grammar? - -#### Operator precedence - -The precedence of Rust binary operators is ordered as follows, going from -strong to weak: - -```text -* / % -as -+ - -<< >> -& -^ -| -< > <= >= -== != -&& -|| -= -``` - -Operators at the same precedence level are evaluated left-to-right. [Unary -operators](#unary-operator-expressions) have the same precedence level and it -is stronger than any of the binary operators'. +```antlr +compound_assignment_expr : expr [ arith_op | bitwise_op ] '=' expr ; +``` ### Grouped expressions diff --git a/src/doc/index.md b/src/doc/index.md index 5a437e959b7..c4725c26e46 100644 --- a/src/doc/index.md +++ b/src/doc/index.md @@ -5,15 +5,14 @@ to jump to any particular section. # Getting Started -If you haven't seen Rust at all yet, the first thing you should read is the [30 -minute intro](intro.html). It will give you an overview of the basic ideas of Rust -at a high level. +If you haven't seen Rust at all yet, the first thing you should read is the +introduction to [The Rust Programming Language](book/index.html). It'll give +you a good idea of what Rust is like. -Once you know you really want to learn Rust, the next step is reading [The -Rust Programming Language](book/index.html). It is a lengthy explanation of -Rust, its syntax, and its concepts. Upon completing the book, you'll be an -intermediate Rust developer, and will have a good grasp of the fundamental -ideas behind Rust. +The book provides a lengthy explanation of Rust, its syntax, and its +concepts. Upon completing the book, you'll be an intermediate Rust +developer, and will have a good grasp of the fundamental ideas behind +Rust. [Rust By Example][rbe] was originally a community resource, but was then donated to the Rust project. As the name implies, it teaches you Rust through a @@ -24,7 +23,7 @@ series of small examples. # Community & Getting Help If you need help with something, or just want to talk about Rust with others, -there's a few places you can do that: +there are a few places you can do that: The Rust IRC channels on [irc.mozilla.org](http://irc.mozilla.org/) are the fastest way to get help. @@ -59,7 +58,7 @@ the language in as much detail as possible is in [the reference](reference.html) # Tools -Rust's still a young language, so there isn't a ton of tooling yet, but the +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 @@ -69,16 +68,21 @@ lots of good documentation. # FAQs -There are questions that are asked quite often, and so we've made FAQs for them: +There are questions that are asked quite often, so we've made FAQs for them: * [Language Design FAQ](complement-design-faq.html) * [Language FAQ](complement-lang-faq.html) * [Project FAQ](complement-project-faq.html) * [How to submit a bug report](https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#bug-reports) -# The standard library +# The Standard Library We have [API documentation for the entire standard library](std/index.html). There's a list of crates on the left with more specific sections, or you can use the search bar at the top to search for something if you know its name. + +# The Error Index + +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). diff --git a/src/doc/reference.md b/src/doc/reference.md index 16fdcfa3013..2ddec9ba424 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -31,23 +31,27 @@ You may also be interested in the [grammar]. ## Unicode productions -A few productions in Rust's grammar permit Unicode code points outside the ASCII -range. We define these productions in terms of character properties specified -in the Unicode standard, rather than in terms of ASCII-range code points. The -section [Special Unicode Productions](#special-unicode-productions) lists these -productions. +A few productions in Rust's grammar permit Unicode code points outside the +ASCII range. We define these productions in terms of character properties +specified in the Unicode standard, rather than in terms of ASCII-range code +points. The grammar has a [Special Unicode Productions][unicodeproductions] +section that lists these productions. + +[unicodeproductions]: grammar.html#special-unicode-productions ## String table productions Some rules in the grammar — notably [unary operators](#unary-operator-expressions), [binary -operators](#binary-operator-expressions), and [keywords](#keywords) — are +operators](#binary-operator-expressions), and [keywords][keywords] — are given in a simplified form: as a listing of a table of unquoted, printable whitespace-separated strings. These cases form a subset of the rules regarding the [token](#tokens) rule, and are assumed to be the result of a lexical-analysis phase feeding the parser, driven by a DFA, operating over the disjunction of all such string table entries. +[keywords]: grammar.html#keywords + When such a string enclosed in double-quotes (`"`) occurs inside the grammar, it is an implicit reference to a single member of such a string table production. See [tokens](#tokens) for more information. @@ -75,7 +79,7 @@ An identifier is any nonempty Unicode[^non_ascii_idents] string of the following - The first character has property `XID_start` - The remaining characters have property `XID_continue` -that does _not_ occur in the set of [keywords](#keywords). +that does _not_ occur in the set of [keywords][keywords]. > **Note**: `XID_start` and `XID_continue` as character properties cover the > character ranges used to form the more familiar C and Java language-family @@ -401,7 +405,7 @@ Symbols are a general class of printable [token](#tokens) that play structural roles in a variety of grammar productions. They are catalogued here for completeness as the set of remaining miscellaneous printable tokens that do not otherwise appear as [unary operators](#unary-operator-expressions), [binary -operators](#binary-operator-expressions), or [keywords](#keywords). +operators](#binary-operator-expressions), or [keywords][keywords]. ## Paths @@ -422,12 +426,12 @@ x; x::y::z; ``` -Path components are usually [identifiers](#identifiers), but the trailing -component of a path may be an angle-bracket-enclosed list of type arguments. In -[expression](#expressions) context, the type argument list is given after a -final (`::`) namespace qualifier in order to disambiguate it from a relational -expression involving the less-than symbol (`<`). In type expression context, -the final namespace qualifier is omitted. +Path components are usually [identifiers](#identifiers), but they may +also include angle-bracket-enclosed lists of type arguments. In +[expression](#expressions) context, the type argument list is given +after a `::` namespace qualifier in order to disambiguate it from a +relational expression involving the less-than symbol (`<`). In type +expression context, the final namespace qualifier is omitted. Two examples of paths with type arguments: @@ -493,8 +497,9 @@ names, and invoked through a consistent syntax: `some_extension!(...)`. Users of `rustc` can define new syntax extensions in two ways: -* [Compiler plugins][plugin] can include arbitrary - Rust code that manipulates syntax trees at compile time. +* [Compiler plugins][plugin] can include arbitrary Rust code that + manipulates syntax trees at compile time. Note that the interface + for compiler plugins is considered highly unstable. * [Macros](book/macros.html) define new syntax in a higher-level, declarative way. @@ -547,7 +552,7 @@ _name_ s that occur in its body. At the "current layer", they all must repeat the same number of times, so ` ( $( $i:ident ),* ; $( $j:ident ),* ) => ( $( ($i,$j) ),* )` is valid if given the argument `(a,b,c ; d,e,f)`, but not `(a,b,c ; d,e)`. The repetition walks through the choices at that layer in -lockstep, so the former input transcribes to `( (a,d), (b,e), (c,f) )`. +lockstep, so the former input transcribes to `(a,d), (b,e), (c,f)`. Nested repetitions are allowed. @@ -556,14 +561,18 @@ Nested repetitions are allowed. The parser used by the macro system is reasonably powerful, but the parsing of Rust syntax is restricted in two ways: -1. The parser will always parse as much as possible. If it attempts to match - `$i:expr [ , ]` against `8 [ , ]`, it will attempt to parse `i` as an array - index operation and fail. Adding a separator can solve this problem. +1. Macro definitions are required to include suitable separators after parsing + expressions and other bits of the Rust grammar. This implies that + a macro definition like `$i:expr [ , ]` is not legal, because `[` could be part + of an expression. A macro definition like `$i:expr,` or `$i:expr;` would be legal, + however, because `,` and `;` are legal separators. See [RFC 550] for more information. 2. The parser must have eliminated all ambiguity by the time it reaches a `$` _name_ `:` _designator_. This requirement most often affects name-designator pairs when they occur at the beginning of, or immediately after, a `$(...)*`; requiring a distinctive token in front can solve the problem. +[RFC 550]: https://github.com/rust-lang/rfcs/blob/master/text/0550-macro-future-proofing.md + # Crates and source files Although Rust, like any other language, can be implemented by an interpreter as @@ -611,7 +620,7 @@ module needs its own source file: [module definitions](#modules) can be nested within one file. Each source file contains a sequence of zero or more `item` definitions, and -may optionally begin with any number of [attributes](#Items and attributes) +may optionally begin with any number of [attributes](#items-and-attributes) that apply to the containing module, most of which influence the behavior of the compiler. The anonymous crate module can have additional attributes that apply to the crate as a whole. @@ -653,9 +662,10 @@ There are several kinds of item: * [`use` declarations](#use-declarations) * [modules](#modules) * [functions](#functions) -* [type definitions](#type-definitions) +* [type definitions](grammar.html#type-definitions) * [structures](#structures) * [enumerations](#enumerations) +* [constant items](#constant-items) * [static items](#static-items) * [traits](#traits) * [implementations](#implementations) @@ -672,16 +682,17 @@ which sub-item declarations may appear. ### Type Parameters -All items except modules may be *parameterized* by type. Type parameters are -given as a comma-separated list of identifiers enclosed in angle brackets -(`<...>`), after the name of the item and before its definition. The type -parameters of an item are considered "part of the name", not part of the type -of the item. A referencing [path](#paths) must (in principle) provide type -arguments as a list of comma-separated types enclosed within angle brackets, in -order to refer to the type-parameterized item. In practice, the type-inference -system can usually infer such argument types from context. There are no -general type-parametric types, only type-parametric items. That is, Rust has -no notion of type abstraction: there are no first-class "forall" types. +All items except modules, constants and statics may be *parameterized* by type. +Type parameters are given as a comma-separated list of identifiers enclosed in +angle brackets (`<...>`), after the name of the item and before its definition. +The type parameters of an item are considered "part of the name", not part of +the type of the item. A referencing [path](#paths) must (in principle) provide +type arguments as a list of comma-separated types enclosed within angle +brackets, in order to refer to the type-parameterized item. In practice, the +type-inference system can usually infer such argument types from context. There +are no general type-parametric types, only type-parametric items. That is, Rust +has no notion of type abstraction: there are no higher-ranked (or "forall") types +abstracted over other types, though higher-ranked types do exist for lifetimes. ### Modules @@ -727,6 +738,7 @@ mod vec; mod thread { // Load the `local_data` module from `thread/local_data.rs` + // or `thread/local_data/mod.rs`. mod local_data; } ``` @@ -743,7 +755,7 @@ mod thread { } ``` -##### Extern crate declarations +#### Extern crate declarations An _`extern crate` declaration_ specifies a dependency on an external crate. The external crate is then bound into the declaring scope as the `ident` @@ -767,12 +779,12 @@ extern crate std; // equivalent to: extern crate std as std; extern crate std as ruststd; // linking to 'std' under another name ``` -##### Use declarations +#### Use declarations A _use declaration_ creates one or more local name bindings synonymous with some other [path](#paths). Usually a `use` declaration is used to shorten the path required to refer to a module item. These declarations may appear at the -top of [modules](#modules) and [blocks](#blocks). +top of [modules](#modules) and [blocks](grammar.html#block-expressions). > **Note**: Unlike in many languages, > `use` declarations in Rust do *not* declare linkage dependency with external crates. @@ -842,7 +854,7 @@ module declarations should be at the crate root if direct usage of the declared modules within `use` items is desired. It is also possible to use `self` and `super` at the beginning of a `use` item to refer to the current and direct parent modules respectively. All rules regarding accessing declared modules in -`use` declarations applies to both module declarations and `extern crate` +`use` declarations apply to both module declarations and `extern crate` declarations. An example of what will and will not work for `use` items: @@ -999,7 +1011,8 @@ the guarantee that these issues are never caused by safe code. * `&mut` and `&` follow LLVM’s scoped [noalias] model, except if the `&T` contains an `UnsafeCell<U>`. Unsafe code must not violate these aliasing guarantees. -* Mutating an immutable value/reference without `UnsafeCell<U>` +* Mutating non-mutable data (that is, data reached through a shared reference or + data owned by a `let` binding), unless that data is contained within an `UnsafeCell<U>`. * Invoking undefined behavior via compiler intrinsics: * Indexing outside of the bounds of an object with `std::ptr::offset` (`offset` intrinsic), with @@ -1029,9 +1042,13 @@ be undesired. * Exiting without calling destructors * Sending signals * Accessing/modifying the file system -* Unsigned integer overflow (well-defined as wrapping) -* Signed integer overflow (well-defined as two’s complement representation - wrapping) +* Integer overflow + - Overflow is considered "unexpected" behavior and is always user-error, + unless the `wrapping` primitives are used. In non-optimized builds, the compiler + will insert debug checks that panic on overflow, but in optimized builds overflow + instead results in wrapped values. See [RFC 560] for the rationale and more details. + +[RFC 560]: https://github.com/rust-lang/rfcs/blob/master/text/0560-integer-overflow.md #### Diverging functions @@ -1143,9 +1160,7 @@ let px: i32 = match p { Point(x, _) => x }; ``` A _unit-like struct_ is a structure without any fields, defined by leaving off -the list of fields entirely. Such types will have a single value, just like -the [unit value `()`](#unit-and-boolean-literals) of the unit type. For -example: +the list of fields entirely. Such types will have a single value. For example: ``` struct Cookie; @@ -1307,11 +1322,26 @@ type of the value is not required to ascribe to `Sync`. ### Traits -A _trait_ describes a set of method types. +A _trait_ describes an abstract interface that types can +implement. This interface consists of associated items, which come in +three varieties: -Traits can include default implementations of methods, written in terms of some -unknown [`self` type](#self-types); the `self` type may either be completely -unspecified, or constrained by some other trait. +- functions +- constants +- types + +Associated functions whose first parameter is named `self` are called +methods and may be invoked using `.` notation (e.g., `x.foo()`). + +All traits define an implicit type parameter `Self` that refers to +"the type that is implementing this interface". Traits may also +contain additional type parameters. These type parameters (including +`Self`) may be constrained by other traits and so forth as usual. + +Trait bounds on `Self` are considered "supertraits". These are +required to be acyclic. Supertraits are somewhat different from other +constraints in that they affect what methods are available in the +vtable when the trait is used as a [trait object](#trait-objects). Traits are implemented for specific types through separate [implementations](#implementations). @@ -1356,15 +1386,18 @@ fn draw_twice<T: Shape>(surface: Surface, sh: T) { } ``` -Traits also define an [trait object](#trait-objects) with the same name as the -trait. Values of this type are created by [casting](#type-cast-expressions) -pointer values (pointing to a type for which an implementation of the given -trait is in scope) to pointers to the trait name, used as a type. +Traits also define an [trait object](#trait-objects) with the same +name as the trait. Values of this type are created by coercing from a +pointer of some specific type to a pointer of trait type. For example, +`&T` could be coerced to `&Shape` if `T: Shape` holds (and similarly +for `Box<T>`). This coercion can either be implicit or +[explicit](#type-cast-expressions). Here is an example of an explicit +coercion: ``` -# trait Shape { fn dummy(&self) { } } -# impl Shape for i32 { } -# let mycircle = 0i32; +trait Shape { } +impl Shape for i32 { } +let mycircle = 0i32; let myshape: Box<Shape> = Box::new(mycircle) as Box<Shape>; ``` @@ -2038,7 +2071,8 @@ The name `str_eq` has a special meaning to the Rust compiler, and the presence of this definition means that it will use this definition when generating calls to the string equality function. -A complete list of the built-in language items will be added in the future. +The set of language items is currently considered unstable. A complete +list of the built-in language items will be added in the future. ### Inline attributes @@ -2050,11 +2084,6 @@ The compiler automatically inlines functions based on internal heuristics. Incorrectly inlining functions can actually make the program slower, so it should be used with care. -Immutable statics are always considered inlineable unless marked with -`#[inline(never)]`. It is undefined whether two different inlineable statics -have the same memory address. In other words, the compiler is free to collapse -duplicate inlineable statics together. - `#[inline]` and `#[inline(always)]` always cause the function to be serialized into the crate metadata to allow cross-crate inlining. @@ -2256,10 +2285,6 @@ The currently implemented features of the reference compiler are: * `unboxed_closures` - Rust's new closure design, which is currently a work in progress feature with many known bugs. -* `unsafe_destructor` - Allows use of the `#[unsafe_destructor]` attribute, - which is considered wildly unsafe and will be - obsoleted by language improvements. - * `unsafe_no_drop_flag` - Allows use of the `#[unsafe_no_drop_flag]` attribute, which removes hidden flag added to a type that implements the `Drop` trait. The design for the @@ -2379,18 +2404,54 @@ expressions](#index-expressions) (`expr[expr]`), and [field references](#field-expressions) (`expr.f`). All other expressions are rvalues. The left operand of an [assignment](#assignment-expressions) or -[compound-assignment](#compound-assignment-expressions) expression is an lvalue -context, as is the single operand of a unary -[borrow](#unary-operator-expressions). All other expression contexts are -rvalue contexts. +[compound-assignment](#compound-assignment-expressions) expression is +an lvalue context, as is the single operand of a unary +[borrow](#unary-operator-expressions). The discriminant or subject of +a [match expression](#match-expressions) may be an lvalue context, if +ref bindings are made, but is otherwise an rvalue context. All other +expression contexts are rvalue contexts. When an lvalue is evaluated in an _lvalue context_, it denotes a memory location; when evaluated in an _rvalue context_, it denotes the value held _in_ that memory location. -When an rvalue is used in an lvalue context, a temporary un-named lvalue is -created and used instead. A temporary's lifetime equals the largest lifetime -of any reference that points to it. +##### Temporary lifetimes + +When an rvalue is used in an lvalue context, a temporary un-named +lvalue is created and used instead. The lifetime of temporary values +is typically the innermost enclosing statement; the tail expression of +a block is considered part of the statement that encloses the block. + +When a temporary rvalue is being created that is assigned into a `let` +declaration, however, the temporary is created with the lifetime of +the enclosing block instead, as using the enclosing statement (the +`let` declaration) would be a guaranteed error (since a pointer to the +temporary would be stored into a variable, but the temporary would be +freed before the variable could be used). The compiler uses simple +syntactic rules to decide which values are being assigned into a `let` +binding, and therefore deserve a longer temporary lifetime. + +Here are some examples: + +- `let x = foo(&temp())`. The expression `temp()` is an rvalue. As it + is being borrowed, a temporary is created which will be freed after + the innermost enclosing statement (the `let` declaration, in this case). +- `let x = temp().foo()`. This is the same as the previous example, + except that the value of `temp()` is being borrowed via autoref on a + method-call. Here we are assuming that `foo()` is an `&self` method + defined in some trait, say `Foo`. In other words, the expression + `temp().foo()` is equivalent to `Foo::foo(&temp())`. +- `let x = &temp()`. Here, the same temporary is being assigned into + `x`, rather than being passed as a parameter, and hence the + temporary's lifetime is considered to be the enclosing block. +- `let x = SomeStruct { foo: &temp() }`. As in the previous case, the + temporary is assigned into a struct which is then assigned into a + binding, and hence it is given the lifetime of the enclosing block. +- `let x = [ &temp() ]`. As in the previous case, the + temporary is assigned into an array which is then assigned into a + binding, and hence it is given the lifetime of the enclosing block. +- `let ref x = temp()`. In this case, the temporary is created using a ref binding, + but the result is the same: the lifetime is extended to the enclosing block. #### Moved and copied types @@ -2435,11 +2496,6 @@ comma: (0); // zero in parentheses ``` -### Unit expressions - -The expression `()` denotes the _unit value_, the only value of the type with -the same name. - ### Structure expressions There are several forms of structure expressions. A _structure expression_ @@ -2537,8 +2593,10 @@ A field access is an [lvalue](#lvalues,-rvalues-and-temporaries) referring to the value of that field. When the type providing the field inherits mutability, it can be [assigned](#assignment-expressions) to. -Also, if the type of the expression to the left of the dot is a pointer, it is -automatically dereferenced to make the field access possible. +Also, if the type of the expression to the left of the dot is a +pointer, it is automatically dereferenced as many times as necessary +to make the field access possible. In cases of ambiguity, we prefer +fewer autoderefs to more. ### Array expressions @@ -2564,14 +2622,26 @@ array is mutable, the resulting [lvalue](#lvalues,-rvalues-and-temporaries) can be assigned to. Indices are zero-based, and may be of any integral type. Vector access is -bounds-checked at run-time. When the check fails, it will put the thread in a -_panicked state_. +bounds-checked at compile-time for constant arrays being accessed with a constant index value. +Otherwise a check will be performed at run-time that will put the thread in a _panicked state_ if it fails. ```{should-fail} ([1, 2, 3, 4])[0]; -(["a", "b"])[10]; // panics + +let x = (["a", "b"])[10]; // compiler error: const index-expr is out of bounds + +let n = 10; +let y = (["a", "b"])[n]; // panics + +let arr = ["a", "b"]; +arr[10]; // panics ``` +Also, if the type of the expression to the left of the brackets is a +pointer, it is automatically dereferenced as many times as necessary +to make the indexing possible. In cases of ambiguity, we prefer fewer +autoderefs to more. + ### Range expressions The `..` operator will construct an object of one of the `std::ops::Range` variants. @@ -2594,7 +2664,7 @@ assert_eq!(x,y); ### Unary operator expressions -Rust defines three unary operators. They are all written as prefix operators, +Rust defines the following unary operators. They are all written as prefix operators, before the expression they apply to. * `-` @@ -2608,11 +2678,20 @@ before the expression they apply to. implemented by the type and required for an outer expression that will or could mutate the dereference), and produces the result of dereferencing the `&` or `&mut` borrowed pointer returned from the overload method. - * `!` : Logical negation. On the boolean type, this flips between `true` and `false`. On integer types, this inverts the individual bits in the two's complement representation of the value. +* `&` and `&mut` + : Borrowing. When applied to an lvalue, these operators produce a + reference (pointer) to the lvalue. The lvalue is also placed into + a borrowed state for the duration of the reference. For a shared + borrow (`&`), this implies that the lvalue may not be mutated, but + it may be read or shared again. For a mutable borrow (`&mut`), the + lvalue may not be accessed in any way until the borrow expires. + If the `&` or `&mut` operators are applied to an rvalue, a + temporary value is created; the lifetime of this temporary value + is defined by [syntactic rules](#temporary-lifetimes). ### Binary operator expressions @@ -2722,6 +2801,13 @@ fn avg(v: &[f64]) -> f64 { } ``` +Some of the conversions which can be done through the `as` operator +can also be done implicitly at various points in the program, such as +argument passing and assignment to a `let` binding with an explicit +type. Implicit conversions are limited to "harmless" conversions that +do not lose information and which have minimal or no risk of +surprising side-effects on the dynamic execution semantics. + #### Assignment expressions An _assignment expression_ consists of an @@ -3064,6 +3150,20 @@ of a condition expression it expects a refutable let statement. If the value of expression on the right hand side of the let statement matches the pattern, the corresponding block will execute, otherwise flow proceeds to the first `else` block that follows. +``` +let dish = ("Ham", "Eggs"); + +// this body will be skipped because the pattern is refuted +if let ("Bacon", b) = dish { + println!("Bacon is served with {}", b); +} + +// this body will execute +if let ("Ham", b) = dish { + println!("Ham is served with {}", b); +} +``` + ### While let loops A `while let` loop is semantically identical to a `while` loop but in place of a @@ -3259,7 +3359,7 @@ constructor or `struct` field may refer, directly or indirectly, to the enclosing `enum` or `struct` type itself. Such recursion has restrictions: * Recursive types must include a nominal type in the recursion - (not mere [type definitions](#type-definitions), + (not mere [type definitions](grammar.html#type-definitions), or other structural types such as [arrays](#array,-and-slice-types) or [tuples](#tuple-types)). * A recursive `enum` item must have at least one non-recursive constructor (in order to give the recursion a basis case). @@ -3329,6 +3429,22 @@ let bo: Binop = add; x = bo(5,7); ``` +#### Function types for specific items + +Internally to the compiler, there are also function types that are specific to a particular +function item. In the following snippet, for example, the internal types of the functions +`foo` and `bar` are different, despite the fact that they have the same signature: + +``` +fn foo() { } +fn bar() { } +``` + +The types of `foo` and `bar` can both be implicitly coerced to the fn +pointer type `fn()`. There is currently no syntax for unique fn types, +though the compiler will emit a type like `fn() {foo}` in error +messages to indicate "the unique fn type for the function `foo`". + ### Closure types A [lambda expression](#lambda-expressions) produces a closure value with @@ -3413,8 +3529,9 @@ has type `Vec<A>`, a vector with element type `A`. ### Self types -The special type `self` has a meaning within methods inside an impl item. It -refers to the type of the implicit `self` argument. For example, in: +The special type `Self` has a meaning within traits and impls. In a trait definition, it refers +to an implicit type parameter representing the "implementing" type. In an impl, +it is an alias for the implementing type. For example, in: ``` trait Printable { @@ -3428,8 +3545,9 @@ impl Printable for String { } ``` -`self` refers to the value of type `String` that is the receiver for a call to -the method `make_string`. +The notation `&self` is a shorthand for `self: &Self`. In this case, +in the impl, `Self` refers to the value of type `String` that is the +receiver for a call to the method `make_string`. # Special traits diff --git a/src/doc/trpl/SUMMARY.md b/src/doc/trpl/SUMMARY.md index de7ded76280..3f97928a56e 100644 --- a/src/doc/trpl/SUMMARY.md +++ b/src/doc/trpl/SUMMARY.md @@ -15,6 +15,7 @@ * [Concurrency](concurrency.md) * [Error Handling](error-handling.md) * [FFI](ffi.md) + * [Borrow and AsRef](borrow-and-asref.md) * [Syntax and Semantics](syntax-and-semantics.md) * [Variable Bindings](variable-bindings.md) * [Functions](functions.md) diff --git a/src/doc/trpl/borrow-and-asref.md b/src/doc/trpl/borrow-and-asref.md new file mode 100644 index 00000000000..f5f314f1c21 --- /dev/null +++ b/src/doc/trpl/borrow-and-asref.md @@ -0,0 +1,93 @@ +% Borrow and AsRef + +The [`Borrow`][borrow] and [`AsRef`][asref] traits are very similar, but +different. Here’s a quick refresher on what these two traits mean. + +[borrow]: ../std/borrow/trait.Borrow.html +[asref]: ../std/convert/trait.AsRef.html + +# Borrow + +The `Borrow` trait is used when you’re writing a datastructure, and you want to +use either an owned or borrowed type as synonymous for some purpose. + +For example, [`HashMap`][hashmap] has a [`get` method][get] which uses `Borrow`: + +```rust,ignore +fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V> + where K: Borrow<Q>, + Q: Hash + Eq +``` + +[hashmap]: ../std/collections/struct.HashMap.html +[get]: ../std/collections/struct.HashMap.html#method.get + +This signature is pretty complicated. The `K` parameter is what we’re interested +in here. It refers to a parameter of the `HashMap` itself: + +```rust,ignore +struct HashMap<K, V, S = RandomState> { +``` + +The `K` parameter is the type of _key_ the `HashMap` uses. So, looking at +the signature of `get()` again, we can use `get()` when the key implements +`Borrow<Q>`. That way, we can make a `HashMap` which uses `String` keys, +but use `&str`s when we’re searching: + +```rust +use std::collections::HashMap; + +let mut map = HashMap::new(); +map.insert("Foo".to_string(), 42); + +assert_eq!(map.get("Foo"), Some(&42)); +``` + +This is because the standard library has `impl Borrow<str> for String`. + +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: + +``` +use std::borrow::Borrow; +use std::fmt::Display; + +fn foo<T: Borrow<i32> + Display>(a: T) { + println!("a is borrowed: {}", a); +} + +let mut i = 5; + +foo(&i); +foo(&mut i); +``` + +This will print out `a is borrowed: 5` twice. + +# AsRef + +The `AsRef` trait is a conversion trait. It’s used for converting some value to +a reference in generic code. Like this: + +```rust +let s = "Hello".to_string(); + +fn foo<T: AsRef<str>>(s: T) { + let slice = s.as_ref(); +} +``` + +# Which should I use? + +We can see how they’re kind of the same: they both deal with owned and borrowed +versions of some type. However, they’re a bit different. + +Choose `Borrow` when you want to abstract over different kinds of borrowing, or +when you’re building a datastructure that treats owned and borrowed values in +equivalent ways, such as hashing and comparison. + +Choose `AsRef` when you want to convert something to a reference directly, and +you’re writing generic code. diff --git a/src/doc/trpl/compiler-plugins.md b/src/doc/trpl/compiler-plugins.md index 9eb22a7f698..127e097c34f 100644 --- a/src/doc/trpl/compiler-plugins.md +++ b/src/doc/trpl/compiler-plugins.md @@ -176,7 +176,7 @@ for a full example, the core of which is reproduced here: ```ignore declare_lint!(TEST_LINT, Warn, - "Warn about items named 'lintme'") + "Warn about items named 'lintme'"); struct Pass; diff --git a/src/doc/trpl/guessing-game.md b/src/doc/trpl/guessing-game.md index 50767b603c4..e5702ed1635 100644 --- a/src/doc/trpl/guessing-game.md +++ b/src/doc/trpl/guessing-game.md @@ -273,7 +273,7 @@ information’. Why throw it away? Well, for a basic program, we just want to print a generic error, as basically any issue means we can’t continue. The [`ok()` method][ok] returns a value which has another method defined on it: `expect()`. The [`expect()` method][expect] takes a value it’s called on, and -if it isn’t a successful one, [`panic!`][panic]s with a message you passed you +if it isn’t a successful one, [`panic!`][panic]s with a message you passed it. A `panic!` like this will cause our program to crash, displaying the message. @@ -713,7 +713,7 @@ variety of numbers, we need to give Rust a hint as to the exact type of number we want. Hence, `let guess: u32`. The colon (`:`) after `guess` tells Rust we’re going to annotate its type. `u32` is an unsigned, thirty-two bit integer. Rust has [a number of built-in number types][number], but we’ve -chosen `u32`. It’s a good default choice for a small positive numer. +chosen `u32`. It’s a good default choice for a small positive number. [parse]: ../std/primitive.str.html#method.parse [number]: primitive-types.html#numeric-types @@ -922,7 +922,7 @@ failure. Each contains more information: the successful parsed integer, or an error type. In this case, we `match` on `Ok(num)`, which sets the inner value of the `Ok` to the name `num`, and then we just return it on the right-hand side. In the `Err` case, we don’t care what kind of error it is, so we just -use `_` intead of a name. This ignores the error, and `continue` causes us +use `_` instead of a name. This ignores the error, and `continue` causes us to go to the next iteration of the `loop`. Now we should be good! Let’s try: diff --git a/src/doc/trpl/lifetimes.md b/src/doc/trpl/lifetimes.md index 86164a08a43..25d5122b4e4 100644 --- a/src/doc/trpl/lifetimes.md +++ b/src/doc/trpl/lifetimes.md @@ -5,7 +5,7 @@ Rust’s most unique and compelling features, with which Rust developers should become quite acquainted. Ownership is how Rust achieves its largest goal, memory safety. There are a few distinct concepts, each with its own chapter: -* [ownership][ownership], ownership, the key concept +* [ownership][ownership], the key concept * [borrowing][borrowing], and their associated feature ‘references’ * lifetimes, which you’re reading now diff --git a/src/doc/trpl/match.md b/src/doc/trpl/match.md index 2c0c8ea73c0..86b94453389 100644 --- a/src/doc/trpl/match.md +++ b/src/doc/trpl/match.md @@ -50,7 +50,7 @@ side of a `let` binding or directly where an expression is used: ```rust let x = 5; -let numer = match x { +let number = match x { 1 => "one", 2 => "two", 3 => "three", diff --git a/src/doc/trpl/method-syntax.md b/src/doc/trpl/method-syntax.md index c5dd25516f3..1527d9cf978 100644 --- a/src/doc/trpl/method-syntax.md +++ b/src/doc/trpl/method-syntax.md @@ -127,12 +127,12 @@ fn grow(&self) -> Circle { We just say we’re returning a `Circle`. With this method, we can grow a new circle to any arbitrary size. -# Static methods +# Associated functions -You can also define static methods that do not take a `self` parameter. Here’s a -pattern that’s very common in Rust code: +You can also define associated functions that do not take a `self` parameter. +Here’s a pattern that’s very common in Rust code: -``` +```rust struct Circle { x: f64, y: f64, diff --git a/src/doc/trpl/mutability.md b/src/doc/trpl/mutability.md index 435407a8a96..674d6597449 100644 --- a/src/doc/trpl/mutability.md +++ b/src/doc/trpl/mutability.md @@ -78,8 +78,8 @@ When we call `clone()`, the `Arc<T>` needs to update the reference count. Yet we’ve not used any `mut`s here, `x` is an immutable binding, and we didn’t take `&mut 5` or anything. So what gives? -To this, we have to go back to the core of Rust’s guiding philosophy, memory -safety, and the mechanism by which Rust guarantees it, the +To understand this, we have to go back to the core of Rust’s guiding +philosophy, memory safety, and the mechanism by which Rust guarantees it, the [ownership][ownership] system, and more specifically, [borrowing][borrowing]: > You may have one or the other of these two kinds of borrows, but not both at @@ -169,7 +169,7 @@ struct Point { y: Cell<i32>, } -let mut point = Point { x: 5, y: Cell::new(6) }; +let point = Point { x: 5, y: Cell::new(6) }; point.y.set(7); diff --git a/src/doc/trpl/ownership.md b/src/doc/trpl/ownership.md index fba5226ca2e..b210f1c643f 100644 --- a/src/doc/trpl/ownership.md +++ b/src/doc/trpl/ownership.md @@ -6,7 +6,7 @@ become quite acquainted. Ownership is how Rust achieves its largest goal, memory safety. There are a few distinct concepts, each with its own chapter: -* ownership, which you’re reading now. +* ownership, which you’re reading now * [borrowing][borrowing], and their associated feature ‘references’ * [lifetimes][lifetimes], an advanced concept of borrowing @@ -23,7 +23,7 @@ Before we get to the details, two important notes about the ownership system. Rust has a focus on safety and speed. It accomplishes these goals through many ‘zero-cost abstractions’, which means that in Rust, abstractions cost as little as possible in order to make them work. The ownership system is a prime example -of a zero cost abstraction. All of the analysis we’ll talk about in this guide +of a zero-cost abstraction. All of the analysis we’ll talk about in this guide is _done at compile time_. You do not pay any run-time cost for any of these features. @@ -41,7 +41,7 @@ With that in mind, let’s learn about ownership. # Ownership -[`Variable bindings`][bindings] have a property in Rust: they ‘have ownership’ +[Variable bindings][bindings] have a property in Rust: they ‘have ownership’ of what they’re bound to. This means that when a binding goes out of scope, the resource that they’re bound to are freed. For example: @@ -106,8 +106,8 @@ take(v); println!("v[0] is: {}", v[0]); ``` -Same error: “use of moved value.” When we transfer ownership to something else, -we say that we’ve ‘moved’ the thing we refer to. You don’t need some sort of +Same error: ‘use of moved value’. When we transfer ownership to something else, +we say that we’ve ‘moved’ the thing we refer to. You don’t need any sort of special annotation here, it’s the default thing that Rust does. ## The details @@ -121,19 +121,19 @@ let v = vec![1, 2, 3]; let v2 = v; ``` -The first line creates some data for the vector on the [stack][sh], `v`. The -vector’s data, however, is stored on the [heap][sh], and so it contains a -pointer to that data. When we move `v` to `v2`, it creates a copy of that pointer, -for `v2`. Which would mean two pointers to the contents of the vector on the -heap. That would be a problem: it would violate Rust’s safety guarantees by -introducing a data race. Therefore, Rust forbids using `v` after we’ve done the -move. +The first line allocates memory for the vector object, `v`, and for the data it +contains. The vector object is stored on the [stack][sh] and contains a pointer +to the content (`[1, 2, 3]`) stored on the [heap][sh]. When we move `v` to `v2`, +it creates a copy of that pointer, for `v2`. Which means that there would be two +pointers to the content of the vector on the heap. It would violate Rust’s +safety guarantees by introducing a data race. Therefore, Rust forbids using `v` +after we’ve done the move. [sh]: the-stack-and-the-heap.html It’s also important to note that optimizations may remove the actual copy of -the bytes, depending on circumstances. So it may not be as inefficient as it -initially seems. +the bytes on the stack, depending on circumstances. So it may not be as +inefficient as it initially seems. ## `Copy` types @@ -174,7 +174,7 @@ fn foo(v: Vec<i32>) -> Vec<i32> { } ``` -This would get very tedius. It gets worse the more things we want to take ownership of: +This would get very tedious. It gets worse the more things we want to take ownership of: ```rust fn foo(v1: Vec<i32>, v2: Vec<i32>) -> (Vec<i32>, Vec<i32>, i32) { diff --git a/src/doc/trpl/primitive-types.md b/src/doc/trpl/primitive-types.md index e017e222c74..22483816769 100644 --- a/src/doc/trpl/primitive-types.md +++ b/src/doc/trpl/primitive-types.md @@ -15,7 +15,7 @@ let x = true; let y: bool = false; ``` -A common use of booleans is in [`if` statements][if]. +A common use of booleans is in [`if` conditionals][if]. [if]: if.html @@ -176,7 +176,7 @@ Slices have type `&[T]`. We’ll talk about that `T` when we cover [generics]: generics.html -You can find more documentation for `slices`s [in the standard library +You can find more documentation for slices [in the standard library documentation][slice]. [slice]: ../std/primitive.slice.html diff --git a/src/doc/trpl/references-and-borrowing.md b/src/doc/trpl/references-and-borrowing.md index 8bb3f94760b..c434371ce59 100644 --- a/src/doc/trpl/references-and-borrowing.md +++ b/src/doc/trpl/references-and-borrowing.md @@ -6,7 +6,7 @@ become quite acquainted. Ownership is how Rust achieves its largest goal, memory safety. There are a few distinct concepts, each with its own chapter: -* [ownership][ownership], ownership, the key concept +* [ownership][ownership], the key concept * borrowing, which you’re reading now * [lifetimes][lifetimes], an advanced concept of borrowing @@ -312,6 +312,7 @@ println!("{}", y); We get this error: +```text error: `x` does not live long enough y = &x; ^ @@ -334,3 +335,37 @@ In other words, `y` is only valid for the scope where `x` exists. As soon as `x` goes away, it becomes invalid to refer to it. As such, the error says that the borrow ‘doesn’t live long enough’ because it’s not valid for the right amount of time. + +The same problem occurs when the reference is declared _before_ the variable it refers to: + +```rust,ignore +let y: &i32; +let x = 5; +y = &x; + +println!("{}", y); +``` + +We get this error: + +```text +error: `x` does not live long enough +y = &x; + ^ +note: reference must be valid for the block suffix following statement 0 at +2:16... + let y: &i32; + let x = 5; + y = &x; + + println!("{}", y); +} + +note: ...but borrowed value is only valid for the block suffix following +statement 1 at 3:14 + let x = 5; + y = &x; + + println!("{}", y); +} +``` diff --git a/src/doc/trpl/the-stack-and-the-heap.md b/src/doc/trpl/the-stack-and-the-heap.md index cc0941bc025..7b1cd7dc809 100644 --- a/src/doc/trpl/the-stack-and-the-heap.md +++ b/src/doc/trpl/the-stack-and-the-heap.md @@ -1,3 +1,570 @@ % The Stack and the Heap -Coming Soon +As a systems language, Rust operates at a low level. If you’re coming from a +high-level language, there are some aspects of systems programming that you may +not be familiar with. The most important one is how memory works, with a stack +and a heap. If you’re familiar with how C-like languages use stack allocation, +this chapter will be a refresher. If you’re not, you’ll learn about this more +general concept, but with a Rust-y focus. + +# Memory management + +These two terms are about memory management. The stack and the heap are +abstractions that help you determine when to allocate and deallocate memory. + +Here’s a high-level comparison: + +The stack is very fast, and is where memory is allocated in Rust by default. +But the allocation is local to a function call, and is limited in size. The +heap, on the other hand, is slower, and is explicitly allocated by your +program. But it’s effectively unlimited in size, and is globally accessible. + +# The Stack + +Let’s talk about this Rust program: + +```rust +fn main() { + let x = 42; +} +``` + +This program has one variable binding, `x`. This memory needs to be allocated +from somewhere. Rust ‘stack allocates’ by default, which means that basic +values ‘go on the stack’. What does that mean? + +Well, when a function gets called, some memory gets allocated for all of its +local variables and some other information. This is called a ‘stack frame’, and +for the purpose of this tutorial, we’re going to ignore the extra information +and just consider the local variables we’re allocating. So in this case, when +`main()` is run, we’ll allocate a single 32-bit integer for our stack frame. +This is automatically handled for you, as you can see, we didn’t have to write +any special Rust code or anything. + +When the function is over, its stack frame gets deallocated. This happens +automatically, we didn’t have to do anything special here. + +That’s all there is for this simple program. The key thing to understand here +is that stack allocation is very, very fast. Since we know all the local +variables we have ahead of time, we can grab the memory all at once. And since +we’ll throw them all away at the same time as well, we can get rid of it very +fast too. + +The downside is that we can’t keep values around if we need them for longer +than a single function. We also haven’t talked about what that name, ‘stack’ +means. To do that, we need a slightly more complicated example: + +```rust +fn foo() { + let y = 5; + let z = 100; +} + +fn main() { + let x = 42; + + foo(); +} +``` + +This program has three variables total: two in `foo()`, one in `main()`. Just +as before, when `main()` is called, a single integer is allocated for its stack +frame. But before we can show what happens when `foo()` is called, we need to +visualize what’s going on with memory. Your operating system presents a view of +memory to your program that’s pretty simple: a huge list of addresses, from 0 +to a large number, representing how much RAM your computer has. For example, if +you have a gigabyte of RAM, your addresses go from `0` to `1,073,741,824`. That +number comes from 2<sup>30</sup>, the number of bytes in a gigabyte. + +This memory is kind of like a giant array: addresses start at zero and go +up to the final number. So here’s a diagram of our first stack frame: + +| Address | Name | Value | ++---------+------+-------+ +| 0 | x | 42 | + +We’ve got `x` located at address `0`, with the value `42`. + +When `foo()` is called, a new stack frame is allocated: + +| Address | Name | Value | ++---------+------+-------+ +| 2 | z | 100 | +| 1 | y | 5 | +| 0 | x | 42 | + +Because `0` was taken by the first frame, `1` and `2` are used for `foo()`’s +stack frame. It grows upward, the more functions we call. + + +There’s some important things we have to take note of here. The numbers 0, 1, +and 2 are all solely for illustrative purposes, and bear no relationship to the +actual numbers the computer will actually use. In particular, the series of +addresses are in reality going to be separated by some number of bytes that +separate each address, and that separation may even exceed the size of the +value being stored. + +After `foo()` is over, its frame is deallocated: + +| Address | Name | Value | ++---------+------+-------+ +| 0 | x | 42 | + +And then, after `main()`, even this last value goes away. Easy! + +It’s called a ‘stack’ because it works like a stack of dinner plates: the first +plate you put down is the last plate to pick back up. Stacks are sometimes +called ‘last in, first out queues’ for this reason, as the last value you put +on the stack is the first one you retrieve from it. + +Let’s try a three-deep example: + +```rust +fn bar() { + let i = 6; +} + +fn foo() { + let a = 5; + let b = 100; + let c = 1; + + bar(); +} + +fn main() { + let x = 42; + + foo(); +} +``` + +Okay, first, we call `main()`: + +| Address | Name | Value | ++---------+------+-------+ +| 0 | x | 42 | + +Next up, `main()` calls `foo()`: + +| Address | Name | Value | ++---------+------+-------+ +| 3 | c | 1 | +| 2 | b | 100 | +| 1 | a | 5 | +| 0 | x | 42 | + +And then `foo()` calls `bar()`: + +| Address | Name | Value | ++---------+------+-------+ +| 4 | i | 6 | +| 3 | c | 1 | +| 2 | b | 100 | +| 1 | a | 5 | +| 0 | x | 42 | + +Whew! Our stack is growing tall. + +After `bar()` is over, its frame is deallocated, leaving just `foo()` and +`main()`: + +| Address | Name | Value | ++---------+------+-------+ +| 3 | c | 1 | +| 2 | b | 100 | +| 1 | a | 5 | +| 0 | x | 42 | + +And then `foo()` ends, leaving just `main()` + +| Address | Name | Value | ++---------+------+-------+ +| 0 | x | 42 | + +And then we’re done. Getting the hang of it? It’s like piling up dishes: you +add to the top, you take away from the top. + +# The Heap + +Now, this works pretty well, but not everything can work like this. Sometimes, +you need to pass some memory between different functions, or keep it alive for +longer than a single function’s execution. For this, we can use the heap. + +In Rust, you can allocate memory on the heap with the [`Box<T>` type][box]. +Here’s an example: + +```rust +fn main() { + let x = Box::new(5); + let y = 42; +} +``` + +[box]: ../std/boxed/index.html + +Here’s what happens in memory when `main()` is called: + +| Address | Name | Value | ++---------+------+--------+ +| 1 | y | 42 | +| 0 | x | ?????? | + +We allocate space for two variables on the stack. `y` is `42`, as it always has +been, but what about `x`? Well, `x` is a `Box<i32>`, and boxes allocate memory +on the heap. The actual value of the box is a structure which has a pointer to +‘the heap’. When we start executing the function, and `Box::new()` is called, +it allocates some memory for the heap, and puts `5` there. The memory now looks +like this: + +| Address | Name | Value | ++-----------------+------+----------------+ +| 2<sup>30</sup> | | 5 | +| ... | ... | ... | +| 1 | y | 42 | +| 0 | x | 2<sup>30</sup> | + +We have 2<sup>30</sup> in our hypothetical computer with 1GB of RAM. And since +our stack grows from zero, the easiest place to allocate memory is from the +other end. So our first value is at the highest place in memory. And the value +of the struct at `x` has a [raw pointer][rawpointer] to the place we’ve +allocated on the heap, so the value of `x` is 2<sup>30</sup>, the memory +location we’ve asked for. + +[rawpointer]: raw-pointers.html + +We haven’t really talked too much about what it actually means to allocate and +deallocate memory in these contexts. Getting into very deep detail is out of +the scope of this tutorial, but what’s important to point out here is that +the heap isn’t just a stack that grows from the opposite end. We’ll have an +example of this later in the book, but because the heap can be allocated and +freed in any order, it can end up with ‘holes’. Here’s a diagram of the memory +layout of a program which has been running for a while now: + + +| Address | Name | Value | ++----------------------+------+----------------------+ +| 2<sup>30</sup> | | 5 | +| (2<sup>30</sup>) - 1 | | | +| (2<sup>30</sup>) - 2 | | | +| (2<sup>30</sup>) - 3 | | 42 | +| ... | ... | ... | +| 3 | y | (2<sup>30</sup>) - 3 | +| 2 | y | 42 | +| 1 | y | 42 | +| 0 | x | 2<sup>30</sup> | + +In this case, we’ve allocated four things on the heap, but deallocated two of +them. There’s a gap between 2<sup>30</sup> and (2<sup>30</sup>) - 3 which isn’t +currently being used. The specific details of how and why this happens depends +on what kind of strategy you use to manage the heap. Different programs can use +different ‘memory allocators’, which are libraries that manage this for you. +Rust programs use [jemalloc][jemalloc] for this purpose. + +[jemalloc]: http://www.canonware.com/jemalloc/ + +Anyway, back to our example. Since this memory is on the heap, it can stay +alive longer than the function which allocates the box. In this case, however, +it doesn’t.[^moving] When the function is over, we need to free the stack frame +for `main()`. `Box<T>`, though, has a trick up its sleve: [Drop][drop]. The +implementation of `Drop` for `Box` deallocates the memory that was allocated +when it was created. Great! So when `x` goes away, it first frees the memory +allocated on the heap: + +| Address | Name | Value | ++---------+------+--------+ +| 1 | y | 42 | +| 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. + + +And then the stack frame goes away, freeing all of our memory. + +# Arguments and borrowing + +We’ve got some basic examples with the stack and the heap going, but what about +function arguments and borrowing? Here’s a small Rust program: + +```rust +fn foo(i: &i32) { + let z = 42; +} + +fn main() { + let x = 5; + let y = &x; + + foo(y); +} +``` + +When we enter `main()`, memory looks like this: + +| Address | Name | Value | ++---------+------+-------+ +| 1 | y | 0 | +| 0 | x | 5 | + +`x` is a plain old `5`, and `y` is a reference to `x`. So its value is the +memory location that `x` lives at, which in this case is `0`. + +What about when we call `foo()`, passing `y` as an argument? + +| Address | Name | Value | ++---------+------+-------+ +| 3 | z | 42 | +| 2 | i | 0 | +| 1 | y | 0 | +| 0 | x | 5 | + +Stack frames aren’t just for local bindings, they’re for arguments too. So in +this case, we need to have both `i`, our argument, and `z`, our local variable +binding. `i` is a copy of the argument, `y`. Since `y`’s value is `0`, so is +`i`’s. + +This is one reason why borrowing a variable doesn’t deallocate any memory: the +value of a reference is just a pointer to a memory location. If we got rid of +the underlying memory, things wouldn’t work very well. + +# A complex example + +Okay, let’s go through this complex program step-by-step: + +```rust +fn foo(x: &i32) { + let y = 10; + let z = &y; + + baz(z); + bar(x, z); +} + +fn bar(a: &i32, b: &i32) { + let c = 5; + let d = Box::new(5); + let e = &d; + + baz(e); +} + +fn baz(f: &i32) { + let g = 100; +} + +fn main() { + let h = 3; + let i = Box::new(20); + let j = &h; + + foo(j); +} +``` + +First, we call `main()`: + +| Address | Name | Value | ++-----------------+------+----------------+ +| 2<sup>30</sup> | | 20 | +| ... | ... | ... | +| 2 | j | 0 | +| 1 | i | 2<sup>30</sup> | +| 0 | h | 3 | + +We allocate memory for `j`, `i`, and `h`. `i` is on the heap, and so has a +value pointing there. + +Next, at the end of `main()`, `foo()` gets called: + +| Address | Name | Value | ++-----------------+------+----------------+ +| 2<sup>30</sup> | | 20 | +| ... | ... | ... | +| 5 | z | 4 | +| 4 | y | 10 | +| 3 | x | 0 | +| 2 | j | 0 | +| 1 | i | 2<sup>30</sup> | +| 0 | h | 3 | + +Space gets allocated for `x`, `y`, and `z`. The argument `x` has the same value +as `j`, since that’s what we passed it in. It’s a pointer to the `0` address, +since `j` points at `h`. + +Next, `foo()` calls `baz()`, passing `z`: + +| Address | Name | Value | ++-----------------+------+----------------+ +| 2<sup>30</sup> | | 20 | +| ... | ... | ... | +| 7 | g | 100 | +| 6 | f | 4 | +| 5 | z | 4 | +| 4 | y | 10 | +| 3 | x | 0 | +| 2 | j | 0 | +| 1 | i | 2<sup>30</sup> | +| 0 | h | 3 | + +We’ve allocated memory for `f` and `g`. `baz()` is very short, so when it’s +over, we get rid of its stack frame: + +| Address | Name | Value | ++-----------------+------+----------------+ +| 2<sup>30</sup> | | 20 | +| ... | ... | ... | +| 5 | z | 4 | +| 4 | y | 10 | +| 3 | x | 0 | +| 2 | j | 0 | +| 1 | i | 2<sup>30</sup> | +| 0 | h | 3 | + +Next, `foo()` calls `bar()` with `x` and `z`: + +| Address | Name | Value | ++----------------------+------+----------------------+ +| 2<sup>30</sup> | | 20 | +| (2<sup>30</sup>) - 1 | | 5 | +| ... | ... | ... | +| 10 | e | 4 | +| 9 | d | (2<sup>30</sup>) - 1 | +| 8 | c | 5 | +| 7 | b | 4 | +| 6 | a | 0 | +| 5 | z | 4 | +| 4 | y | 10 | +| 3 | x | 0 | +| 2 | j | 0 | +| 1 | i | 2<sup>30</sup> | +| 0 | h | 3 | + +We end up allocating another value on the heap, and so we have to subtract one +from 2<sup>30</sup>. It’s easier to just write that than `1,073,741,823`. In any +case, we set up the variables as usual. + +At the end of `bar()`, it calls `baz()`: + +| Address | Name | Value | ++----------------------+------+----------------------+ +| 2<sup>30</sup> | | 20 | +| (2<sup>30</sup>) - 1 | | 5 | +| ... | ... | ... | +| 12 | g | 100 | +| 11 | f | 4 | +| 10 | e | 4 | +| 9 | d | (2<sup>30</sup>) - 1 | +| 8 | c | 5 | +| 7 | b | 4 | +| 6 | a | 0 | +| 5 | z | 4 | +| 4 | y | 10 | +| 3 | x | 0 | +| 2 | j | 0 | +| 1 | i | 2<sup>30</sup> | +| 0 | h | 3 | + +With this, we’re at our deepest point! Whew! Congrats for following along this +far. + +After `baz()` is over, we get rid of `f` and `g`: + +| Address | Name | Value | ++----------------------+------+----------------------+ +| 2<sup>30</sup> | | 20 | +| (2<sup>30</sup>) - 1 | | 5 | +| ... | ... | ... | +| 10 | e | 4 | +| 9 | d | (2<sup>30</sup>) - 1 | +| 8 | c | 5 | +| 7 | b | 4 | +| 6 | a | 0 | +| 5 | z | 4 | +| 4 | y | 10 | +| 3 | x | 0 | +| 2 | j | 0 | +| 1 | i | 2<sup>30</sup> | +| 0 | h | 3 | + +Next, we return from `bar()`. `d` in this case is a `Box<T>`, so it also frees +what it points to: (2<sup>30</sup>) - 1. + +| Address | Name | Value | ++-----------------+------+----------------+ +| 2<sup>30</sup> | | 20 | +| ... | ... | ... | +| 5 | z | 4 | +| 4 | y | 10 | +| 3 | x | 0 | +| 2 | j | 0 | +| 1 | i | 2<sup>30</sup> | +| 0 | h | 3 | + +And after that, `foo()` returns: + +| Address | Name | Value | ++-----------------+------+----------------+ +| 2<sup>30</sup> | | 20 | +| ... | ... | ... | +| 2 | j | 0 | +| 1 | i | 2<sup>30</sup> | +| 0 | h | 3 | + +And then, finally, `main()`, which cleans the rest up. When `i` is `Drop`ped, +it will clean up the last of the heap too. + +# What do other languages do? + +Most languages with a garbage collector heap-allocate by default. This means +that every value is boxed. There are a number of reasons why this is done, but +they’re out of scope for this tutorial. There are some possible optimizations +that don’t make it true 100% of the time, too. Rather than relying on the stack +and `Drop` to clean up memory, the garbage collector deals with the heap +instead. + +# Which to use? + +So if the stack is faster and easier to manage, why do we need the heap? A big +reason is that Stack-allocation alone means you only have LIFO semantics for +reclaiming storage. Heap-allocation is strictly more general, allowing storage +to be taken from and returned to the pool in arbitrary order, but at a +complexity cost. + +Generally, you should prefer stack allocation, and so, Rust stack-allocates by +default. The LIFO model of the stack is simpler, at a fundamental level. This +has two big impacts: runtime efficiency and semantic impact. + +## Runtime Efficiency. + +Managing the memory for the stack is trivial: The machine just +increments or decrements a single value, the so-called “stack pointer”. +Managing memory for the heap is non-trivial: heap-allocated memory is freed at +arbitrary points, and each block of heap-allocated memory can be of arbitrary +size, the memory manager must generally work much harder to identify memory for +reuse. + +If you’d like to dive into this topic in greater detail, [this paper][wilson] +is a great introduction. + +[wilson]: http://www.cs.northwestern.edu/~pdinda/icsclass/doc/dsa.pdf + +## Semantic impact + +Stack-allocation impacts the Rust language itself, and thus the developer’s +mental model. The LIFO semantics is what drives how the Rust language handles +automatic memory management. Even the deallocation of a uniquely-owned +heap-allocated box can be driven by the stack-based LIFO semantics, as +discussed throughout this chapter. The flexibility (i.e. expressiveness) of non +LIFO-semantics means that in general the compiler cannot automatically infer at +compile-time where memory should be freed; it has to rely on dynamic protocols, +potentially from outside the language itself, to drive deallocation (reference +counting, as used by `Rc<T>` and `Arc<T>`, is one example of this). + +When taken to the extreme, the increased expressive power of heap allocation +comes at the cost of either significant runtime support (e.g. in the form of a +garbage collector) or significant programmer effort (in the form of explicit +memory management calls that require verification not provided by the Rust +compiler). diff --git a/src/doc/trpl/while-loops.md b/src/doc/trpl/while-loops.md index f2e2f6b6f49..e71d2033f49 100644 --- a/src/doc/trpl/while-loops.md +++ b/src/doc/trpl/while-loops.md @@ -1,4 +1,4 @@ -% while loops +% while Loops Rust also has a `while` loop. It looks like this: diff --git a/src/etc/CONFIGS.md b/src/etc/CONFIGS.md index 036a2f7d436..74837a06fae 100644 --- a/src/etc/CONFIGS.md +++ b/src/etc/CONFIGS.md @@ -1,6 +1,8 @@ # Configs -Here are some links to repos with configs which ease the use of rust: +These are some links to repos with configs which ease the use of rust. + +## Officially Maintained Configs * [rust.vim](https://github.com/rust-lang/rust.vim) * [emacs rust-mode](https://github.com/rust-lang/rust-mode) @@ -8,3 +10,7 @@ Here are some links to repos with configs which ease the use of rust: * [kate-config](https://github.com/rust-lang/kate-config) * [nano-config](https://github.com/rust-lang/nano-config) * [zsh-config](https://github.com/rust-lang/zsh-config) + +## Community-maintained Configs + +* [.editorconfig](https://gist.github.com/derhuerst/c9d1b9309e308d9851fa) ([what is this?](http://editorconfig.org/)) diff --git a/src/etc/check-sanitycheck.py b/src/etc/check-sanitycheck.py index 0d9c430ec3a..fc8ed7b383e 100644 --- a/src/etc/check-sanitycheck.py +++ b/src/etc/check-sanitycheck.py @@ -13,7 +13,6 @@ import os import sys import functools -import resource STATUS = 0 @@ -37,6 +36,7 @@ def only_on(platforms): @only_on(('linux', 'darwin', 'freebsd', 'openbsd')) def check_rlimit_core(): + import resource soft, hard = resource.getrlimit(resource.RLIMIT_CORE) if soft > 0: error_unless_permitted('ALLOW_NONZERO_RLIMIT_CORE', """\ diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index 83795a24c81..e155dc86f32 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -8,6 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use core::{isize, usize}; + +#[inline(always)] +fn check_size_and_alignment(size: usize, align: usize) { + debug_assert!(size != 0); + debug_assert!(size <= isize::MAX as usize, "Tried to allocate too much: {} bytes", size); + debug_assert!(usize::is_power_of_two(align), "Invalid alignment of allocation: {}", align); +} + // FIXME: #13996: mark the `allocate` and `reallocate` return value as `noalias` /// Return a pointer to `size` bytes of memory aligned to `align`. @@ -19,6 +28,7 @@ /// size on the platform. #[inline] pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 { + check_size_and_alignment(size, align); imp::allocate(size, align) } @@ -38,6 +48,7 @@ pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 { /// any value in range_inclusive(requested_size, usable_size). #[inline] pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8 { + check_size_and_alignment(size, align); imp::reallocate(ptr, old_size, size, align) } @@ -56,6 +67,7 @@ pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usiz #[inline] pub unsafe fn reallocate_inplace(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> usize { + check_size_and_alignment(size, align); imp::reallocate_inplace(ptr, old_size, size, align) } diff --git a/src/libcollections/bit.rs b/src/libcollections/bit.rs index 17e937c5af2..8ec4a68f2b1 100644 --- a/src/libcollections/bit.rs +++ b/src/libcollections/bit.rs @@ -1537,7 +1537,7 @@ impl BitSet { bit_vec.nbits = trunc_len * u32::BITS; } - /// Iterator over each u32 stored in the `BitSet`. + /// Iterator over each usize stored in the `BitSet`. /// /// # Examples /// @@ -1558,7 +1558,7 @@ impl BitSet { SetIter {set: self, next_idx: 0} } - /// Iterator over each u32 stored in `self` union `other`. + /// Iterator over each usize stored in `self` union `other`. /// See [union_with](#method.union_with) for an efficient in-place version. /// /// # Examples @@ -1658,7 +1658,7 @@ impl BitSet { }) } - /// Iterator over each u32 stored in the symmetric difference of `self` and `other`. + /// 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. /// @@ -1796,6 +1796,89 @@ impl BitSet { self.other_op(other, |w1, w2| w1 ^ w2); } + /// Moves all elements from `other` into `Self`, leaving `other` empty. + /// + /// # Examples + /// + /// ``` + /// # #![feature(collections, bit_set_append_split_off)] + /// use std::collections::{BitVec, BitSet}; + /// + /// let mut a = BitSet::new(); + /// a.insert(2); + /// a.insert(6); + /// + /// let mut b = BitSet::new(); + /// b.insert(1); + /// b.insert(3); + /// b.insert(6); + /// + /// a.append(&mut b); + /// + /// assert_eq!(a.len(), 4); + /// assert_eq!(b.len(), 0); + /// assert_eq!(a, BitSet::from_bit_vec(BitVec::from_bytes(&[0b01110010]))); + /// ``` + #[unstable(feature = "bit_set_append_split_off", + reason = "recently added as part of collections reform 2")] + pub fn append(&mut self, other: &mut Self) { + self.union_with(other); + other.clear(); + } + + /// Splits the `BitSet` into two at the given key including the key. + /// Retains the first part in-place while returning the second part. + /// + /// # Examples + /// + /// ``` + /// # #![feature(collections, bit_set_append_split_off)] + /// use std::collections::{BitSet, BitVec}; + /// let mut a = BitSet::new(); + /// a.insert(2); + /// a.insert(6); + /// a.insert(1); + /// a.insert(3); + /// + /// let b = a.split_off(3); + /// + /// assert_eq!(a.len(), 2); + /// assert_eq!(b.len(), 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", + reason = "recently added as part of collections reform 2")] + pub fn split_off(&mut self, at: usize) -> Self { + let mut other = BitSet::new(); + + if at == 0 { + swap(self, &mut other); + return other; + } else if at >= self.bit_vec.len() { + return other; + } + + // Calculate block and bit at which to split + let w = at / u32::BITS; + let b = at % u32::BITS; + + // Pad `other` with `w` zero blocks, + // append `self`'s blocks in the range from `w` to the end to `other` + other.bit_vec.storage.extend(repeat(0u32).take(w) + .chain(self.bit_vec.storage[w..].iter().cloned())); + other.bit_vec.nbits = self.bit_vec.nbits; + + if b > 0 { + other.bit_vec.storage[w] &= !0 << b; + } + + // Sets `bit_vec.len()` and fixes the last block as well + self.bit_vec.truncate(at); + + other + } + /// Returns the number of set bits in this set. #[inline] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcollections/borrow.rs b/src/libcollections/borrow.rs index 7332bf4670a..a86a4b4215f 100644 --- a/src/libcollections/borrow.rs +++ b/src/libcollections/borrow.rs @@ -37,6 +37,11 @@ use self::Cow::*; /// trait: if `T: Borrow<U>`, then `&U` can be borrowed from `&T`. A given /// type can be borrowed as multiple different types. In particular, `Vec<T>: /// Borrow<Vec<T>>` and `Vec<T>: Borrow<[T]>`. +/// +/// `Borrow` is very similar to, but different than, `AsRef`. See +/// [the book][book] for more. +/// +/// [book]: ../../book/borrow-and-asref.html #[stable(feature = "rust1", since = "1.0.0")] pub trait Borrow<Borrowed: ?Sized> { /// Immutably borrows from an owned value. diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index b9e9800f7a0..d5a069b194a 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -1002,7 +1002,7 @@ pub trait SliceConcatExt<T: ?Sized> { /// The resulting type after concatenation type Output; - /// Flattens a slice of `T` into a single value `U`. + /// Flattens a slice of `T` into a single value `Self::Output`. /// /// # Examples /// @@ -1012,7 +1012,8 @@ pub trait SliceConcatExt<T: ?Sized> { #[stable(feature = "rust1", since = "1.0.0")] fn concat(&self) -> Self::Output; - /// Flattens a slice of `T` into a single value `U`, placing a given separator between each. + /// Flattens a slice of `T` into a single value `Self::Output`, placing a given separator + /// between each. /// /// # Examples /// diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 52d72501b4a..28e47674291 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -1052,6 +1052,7 @@ impl<T: fmt::Display + ?Sized> ToString for T { #[stable(feature = "rust1", since = "1.0.0")] impl AsRef<str> for String { + #[inline] fn as_ref(&self) -> &str { self } diff --git a/src/libcollections/vec_map.rs b/src/libcollections/vec_map.rs index 6ff819fc87c..aa0ab41b745 100644 --- a/src/libcollections/vec_map.rs +++ b/src/libcollections/vec_map.rs @@ -367,7 +367,7 @@ impl<V> VecMap<V> { // Move all elements to other swap(self, &mut other); return other - } else if at > self.v.len() { + } else if at >= self.v.len() { // No elements to copy return other; } diff --git a/src/libcollectionstest/bit/set.rs b/src/libcollectionstest/bit/set.rs index d020f551dd5..e6aa15608f0 100644 --- a/src/libcollectionstest/bit/set.rs +++ b/src/libcollectionstest/bit/set.rs @@ -387,6 +387,67 @@ fn test_bit_vec_clone() { assert!(b.contains(&1000)); } +#[test] +fn test_bit_set_append() { + let mut a = BitSet::new(); + a.insert(2); + a.insert(6); + + let mut b = BitSet::new(); + b.insert(1); + b.insert(3); + b.insert(6); + + a.append(&mut b); + + assert_eq!(a.len(), 4); + assert_eq!(b.len(), 0); + assert!(b.capacity() >= 6); + + assert_eq!(a, BitSet::from_bit_vec(BitVec::from_bytes(&[0b01110010]))); +} + +#[test] +fn test_bit_set_split_off() { + // Split at 0 + let mut a = BitSet::from_bit_vec(BitVec::from_bytes(&[0b10100000, 0b00010010, 0b10010010, + 0b00110011, 0b01101011, 0b10101101])); + + let b = a.split_off(0); + + assert_eq!(a.len(), 0); + assert_eq!(b.len(), 21); + + assert_eq!(b, BitSet::from_bit_vec(BitVec::from_bytes(&[0b10100000, 0b00010010, 0b10010010, + 0b00110011, 0b01101011, 0b10101101]))); + + // Split behind last element + let mut a = BitSet::from_bit_vec(BitVec::from_bytes(&[0b10100000, 0b00010010, 0b10010010, + 0b00110011, 0b01101011, 0b10101101])); + + let b = a.split_off(50); + + assert_eq!(a.len(), 21); + assert_eq!(b.len(), 0); + + assert_eq!(a, BitSet::from_bit_vec(BitVec::from_bytes(&[0b10100000, 0b00010010, 0b10010010, + 0b00110011, 0b01101011, 0b10101101]))); + + // Split at arbitrary element + let mut a = BitSet::from_bit_vec(BitVec::from_bytes(&[0b10100000, 0b00010010, 0b10010010, + 0b00110011, 0b01101011, 0b10101101])); + + let b = a.split_off(34); + + assert_eq!(a.len(), 12); + assert_eq!(b.len(), 9); + + assert_eq!(a, BitSet::from_bit_vec(BitVec::from_bytes(&[0b10100000, 0b00010010, 0b10010010, + 0b00110011, 0b01000000]))); + assert_eq!(b, BitSet::from_bit_vec(BitVec::from_bytes(&[0, 0, 0, 0, + 0b00101011, 0b10101101]))); +} + mod bench { use std::collections::{BitSet, BitVec}; use std::__rand::{Rng, thread_rng, ThreadRng}; diff --git a/src/libcollectionstest/lib.rs b/src/libcollectionstest/lib.rs index 154bdd56c5a..9b50478472f 100644 --- a/src/libcollectionstest/lib.rs +++ b/src/libcollectionstest/lib.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(bit_set_append_split_off)] #![feature(bit_vec_append_split_off)] #![feature(box_syntax)] #![feature(collections)] diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index d3de77a9241..f6987c19664 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -24,6 +24,11 @@ use marker::Sized; /// A cheap, reference-to-reference conversion. /// +/// `AsRef` is very similar to, but different than, `Borrow`. See +/// [the book][book] for more. +/// +/// [book]: ../../book/borrow-and-asref.html +/// /// # Examples /// /// Both `String` and `&str` implement `AsRef<str>`: @@ -173,6 +178,7 @@ impl<T> AsMut<[T]> for [T] { #[stable(feature = "rust1", since = "1.0.0")] impl AsRef<str> for str { + #[inline] fn as_ref(&self) -> &str { self } diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index e4d2ab19863..cab79d938c3 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -137,7 +137,7 @@ pub trait Iterator { /// /// ``` /// let a = [1, 2, 3, 4, 5]; - /// assert_eq!(a.iter().last().unwrap(), &5); + /// assert_eq!(a.iter().last(), Some(&5)); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -155,7 +155,7 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3, 4, 5]; /// let mut it = a.iter(); - /// assert_eq!(it.nth(2).unwrap(), &3); + /// assert_eq!(it.nth(2), Some(&3)); /// assert_eq!(it.nth(2), None); /// ``` #[inline] @@ -178,8 +178,8 @@ pub trait Iterator { /// let a = [0]; /// let b = [1]; /// let mut it = a.iter().chain(b.iter()); - /// assert_eq!(it.next().unwrap(), &0); - /// assert_eq!(it.next().unwrap(), &1); + /// assert_eq!(it.next(), Some(&0)); + /// assert_eq!(it.next(), Some(&1)); /// assert!(it.next().is_none()); /// ``` #[inline] @@ -201,7 +201,7 @@ pub trait Iterator { /// let a = [0]; /// let b = [1]; /// let mut it = a.iter().zip(b.iter()); - /// assert_eq!(it.next().unwrap(), (&0, &1)); + /// assert_eq!(it.next(), Some((&0, &1))); /// assert!(it.next().is_none()); /// ``` /// @@ -234,8 +234,8 @@ pub trait Iterator { /// ``` /// let a = [1, 2]; /// let mut it = a.iter().map(|&x| 2 * x); - /// assert_eq!(it.next().unwrap(), 2); - /// assert_eq!(it.next().unwrap(), 4); + /// assert_eq!(it.next(), Some(2)); + /// assert_eq!(it.next(), Some(4)); /// assert!(it.next().is_none()); /// ``` #[inline] @@ -255,7 +255,7 @@ pub trait Iterator { /// ``` /// let a = [1, 2]; /// let mut it = a.iter().filter(|&x| *x > 1); - /// assert_eq!(it.next().unwrap(), &2); + /// assert_eq!(it.next(), Some(&2)); /// assert!(it.next().is_none()); /// ``` #[inline] @@ -275,7 +275,7 @@ pub trait Iterator { /// ``` /// let a = [1, 2]; /// let mut it = a.iter().filter_map(|&x| if x > 1 {Some(2 * x)} else {None}); - /// assert_eq!(it.next().unwrap(), 4); + /// assert_eq!(it.next(), Some(4)); /// assert!(it.next().is_none()); /// ``` #[inline] @@ -310,8 +310,8 @@ pub trait Iterator { /// ``` /// let a = [100, 200]; /// let mut it = a.iter().enumerate(); - /// assert_eq!(it.next().unwrap(), (0, &100)); - /// assert_eq!(it.next().unwrap(), (1, &200)); + /// assert_eq!(it.next(), Some((0, &100))); + /// assert_eq!(it.next(), Some((1, &200))); /// assert!(it.next().is_none()); /// ``` #[inline] @@ -353,9 +353,9 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3, 4, 5]; /// let mut it = a.iter().skip_while(|&a| *a < 3); - /// assert_eq!(it.next().unwrap(), &3); - /// assert_eq!(it.next().unwrap(), &4); - /// assert_eq!(it.next().unwrap(), &5); + /// assert_eq!(it.next(), Some(&3)); + /// assert_eq!(it.next(), Some(&4)); + /// assert_eq!(it.next(), Some(&5)); /// assert!(it.next().is_none()); /// ``` #[inline] @@ -375,8 +375,8 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3, 4, 5]; /// let mut it = a.iter().take_while(|&a| *a < 3); - /// assert_eq!(it.next().unwrap(), &1); - /// assert_eq!(it.next().unwrap(), &2); + /// assert_eq!(it.next(), Some(&1)); + /// assert_eq!(it.next(), Some(&2)); /// assert!(it.next().is_none()); /// ``` #[inline] @@ -395,8 +395,8 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3, 4, 5]; /// let mut it = a.iter().skip(3); - /// assert_eq!(it.next().unwrap(), &4); - /// assert_eq!(it.next().unwrap(), &5); + /// assert_eq!(it.next(), Some(&4)); + /// assert_eq!(it.next(), Some(&5)); /// assert!(it.next().is_none()); /// ``` #[inline] @@ -413,9 +413,9 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3, 4, 5]; /// let mut it = a.iter().take(3); - /// assert_eq!(it.next().unwrap(), &1); - /// assert_eq!(it.next().unwrap(), &2); - /// assert_eq!(it.next().unwrap(), &3); + /// assert_eq!(it.next(), Some(&1)); + /// assert_eq!(it.next(), Some(&2)); + /// assert_eq!(it.next(), Some(&3)); /// assert!(it.next().is_none()); /// ``` #[inline] @@ -437,11 +437,11 @@ pub trait Iterator { /// *fac = *fac * x; /// Some(*fac) /// }); - /// assert_eq!(it.next().unwrap(), 1); - /// assert_eq!(it.next().unwrap(), 2); - /// assert_eq!(it.next().unwrap(), 6); - /// assert_eq!(it.next().unwrap(), 24); - /// assert_eq!(it.next().unwrap(), 120); + /// assert_eq!(it.next(), Some(1)); + /// assert_eq!(it.next(), Some(2)); + /// assert_eq!(it.next(), Some(6)); + /// assert_eq!(it.next(), Some(24)); + /// assert_eq!(it.next(), Some(120)); /// assert!(it.next().is_none()); /// ``` #[inline] @@ -680,7 +680,7 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3, 4, 5]; /// let mut it = a.iter(); - /// assert_eq!(it.find(|&x| *x == 3).unwrap(), &3); + /// assert_eq!(it.find(|&x| *x == 3), Some(&3)); /// assert_eq!(it.collect::<Vec<_>>(), [&4, &5]); #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -715,7 +715,7 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3, 4, 5]; /// let mut it = a.iter(); - /// assert_eq!(it.position(|x| *x == 3).unwrap(), 2); + /// assert_eq!(it.position(|x| *x == 3), Some(2)); /// assert_eq!(it.collect::<Vec<_>>(), [&4, &5]); #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -743,7 +743,7 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 2, 4, 5]; /// let mut it = a.iter(); - /// assert_eq!(it.rposition(|x| *x == 2).unwrap(), 2); + /// assert_eq!(it.rposition(|x| *x == 2), Some(2)); /// assert_eq!(it.collect::<Vec<_>>(), [&1, &2]); #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -773,7 +773,7 @@ pub trait Iterator { /// /// ``` /// let a = [1, 2, 3, 4, 5]; - /// assert_eq!(a.iter().max().unwrap(), &5); + /// assert_eq!(a.iter().max(), Some(&5)); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -796,7 +796,7 @@ pub trait Iterator { /// /// ``` /// let a = [1, 2, 3, 4, 5]; - /// assert_eq!(a.iter().min().unwrap(), &1); + /// assert_eq!(a.iter().min(), Some(&1)); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -1025,9 +1025,9 @@ pub trait Iterator { /// ``` /// let a = [1, 2]; /// let mut it = a.iter().cycle(); - /// assert_eq!(it.next().unwrap(), &1); - /// assert_eq!(it.next().unwrap(), &2); - /// assert_eq!(it.next().unwrap(), &1); + /// assert_eq!(it.next(), Some(&1)); + /// assert_eq!(it.next(), Some(&2)); + /// assert_eq!(it.next(), Some(&1)); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index 56dee303487..9db1ceddf0d 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -140,7 +140,7 @@ impl<T> SliceExt for [T] { assume(!p.is_null()); if mem::size_of::<T>() == 0 { Iter {ptr: p, - end: (p as usize + self.len()) as *const T, + end: ((p as usize).wrapping_add(self.len())) as *const T, _marker: marker::PhantomData} } else { Iter {ptr: p, @@ -277,7 +277,7 @@ impl<T> SliceExt for [T] { assume(!p.is_null()); if mem::size_of::<T>() == 0 { IterMut {ptr: p, - end: (p as usize + self.len()) as *mut T, + end: ((p as usize).wrapping_add(self.len())) as *mut T, _marker: marker::PhantomData} } else { IterMut {ptr: p, @@ -632,35 +632,17 @@ fn size_from_ptr<T>(_: *const T) -> usize { // Use macros to be generic over const/mut -// -// They require non-negative `$by` because otherwise the expression -// `(ptr as usize + $by)` would interpret `-1` as `usize::MAX` (and -// thus trigger a panic when overflow checks are on). - -// Use this to do `$ptr + $by`, where `$by` is non-negative. -macro_rules! slice_add_offset { +macro_rules! slice_offset { ($ptr:expr, $by:expr) => {{ let ptr = $ptr; if size_from_ptr(ptr) == 0 { - transmute(ptr as usize + $by) + transmute((ptr as isize).wrapping_add($by)) } else { ptr.offset($by) } }}; } -// Use this to do `$ptr - $by`, where `$by` is non-negative. -macro_rules! slice_sub_offset { - ($ptr:expr, $by:expr) => {{ - let ptr = $ptr; - if size_from_ptr(ptr) == 0 { - transmute(ptr as usize - $by) - } else { - ptr.offset(-$by) - } - }}; -} - macro_rules! slice_ref { ($ptr:expr) => {{ let ptr = $ptr; @@ -683,14 +665,16 @@ macro_rules! iterator { #[inline] fn next(&mut self) -> Option<$elem> { // could be implemented with slices, but this avoids bounds checks - unsafe { - ::intrinsics::assume(!self.ptr.is_null()); - ::intrinsics::assume(!self.end.is_null()); - if self.ptr == self.end { - None - } else { + if self.ptr == self.end { + None + } else { + unsafe { + if mem::size_of::<T>() != 0 { + ::intrinsics::assume(!self.ptr.is_null()); + ::intrinsics::assume(!self.end.is_null()); + } let old = self.ptr; - self.ptr = slice_add_offset!(self.ptr, 1); + self.ptr = slice_offset!(self.ptr, 1); Some(slice_ref!(old)) } } @@ -698,7 +682,7 @@ macro_rules! iterator { #[inline] fn size_hint(&self) -> (usize, Option<usize>) { - let diff = (self.end as usize) - (self.ptr as usize); + let diff = (self.end as usize).wrapping_sub(self.ptr as usize); let size = mem::size_of::<T>(); let exact = diff / (if size == 0 {1} else {size}); (exact, Some(exact)) @@ -726,13 +710,15 @@ macro_rules! iterator { #[inline] fn next_back(&mut self) -> Option<$elem> { // could be implemented with slices, but this avoids bounds checks - unsafe { - ::intrinsics::assume(!self.ptr.is_null()); - ::intrinsics::assume(!self.end.is_null()); - if self.end == self.ptr { - None - } else { - self.end = slice_sub_offset!(self.end, 1); + if self.end == self.ptr { + None + } else { + unsafe { + self.end = slice_offset!(self.end, -1); + if mem::size_of::<T>() != 0 { + ::intrinsics::assume(!self.ptr.is_null()); + ::intrinsics::assume(!self.end.is_null()); + } Some(slice_ref!(self.end)) } } @@ -742,29 +728,29 @@ macro_rules! iterator { } macro_rules! make_slice { - ($t: ty => $result: ty: $start: expr, $end: expr) => {{ - let diff = $end as usize - $start as usize; - let len = if mem::size_of::<T>() == 0 { - diff + ($start: expr, $end: expr) => {{ + let start = $start; + let diff = ($end as usize).wrapping_sub(start as usize); + if size_from_ptr(start) == 0 { + // use a non-null pointer value + unsafe { from_raw_parts(1 as *const _, diff) } } else { - diff / mem::size_of::<$t>() - }; - unsafe { - from_raw_parts($start, len) + let len = diff / size_from_ptr(start); + unsafe { from_raw_parts(start, len) } } }} } macro_rules! make_mut_slice { - ($t: ty => $result: ty: $start: expr, $end: expr) => {{ - let diff = $end as usize - $start as usize; - let len = if mem::size_of::<T>() == 0 { - diff + ($start: expr, $end: expr) => {{ + let start = $start; + let diff = ($end as usize).wrapping_sub(start as usize); + if size_from_ptr(start) == 0 { + // use a non-null pointer value + unsafe { from_raw_parts_mut(1 as *mut _, diff) } } else { - diff / mem::size_of::<$t>() - }; - unsafe { - from_raw_parts_mut($start, len) + let len = diff / size_from_ptr(start); + unsafe { from_raw_parts_mut(start, len) } } }} } @@ -787,14 +773,14 @@ impl<'a, T> Iter<'a, T> { /// iterator can continue to be used while this exists. #[unstable(feature = "core")] pub fn as_slice(&self) -> &'a [T] { - make_slice!(T => &'a [T]: self.ptr, self.end) + make_slice!(self.ptr, self.end) } // Helper function for Iter::nth fn iter_nth(&mut self, n: usize) -> Option<&'a T> { match self.as_slice().get(n) { Some(elem_ref) => unsafe { - self.ptr = slice_add_offset!(elem_ref as *const _, 1); + self.ptr = slice_offset!(self.ptr, (n as isize).wrapping_add(1)); Some(slice_ref!(elem_ref)) }, None => { @@ -827,12 +813,7 @@ impl<'a, T> RandomAccessIterator for Iter<'a, T> { fn idx(&mut self, index: usize) -> Option<&'a T> { unsafe { if index < self.indexable() { - if mem::size_of::<T>() == 0 { - // Use a non-null pointer value - Some(&mut *(1 as *mut _)) - } else { - Some(transmute(self.ptr.offset(index as isize))) - } + Some(slice_ref!(self.ptr.offset(index as isize))) } else { None } @@ -860,14 +841,14 @@ impl<'a, T> IterMut<'a, T> { /// restricted lifetimes that do not consume the iterator. #[unstable(feature = "core")] pub fn into_slice(self) -> &'a mut [T] { - make_mut_slice!(T => &'a mut [T]: self.ptr, self.end) + make_mut_slice!(self.ptr, self.end) } // Helper function for IterMut::nth fn iter_nth(&mut self, n: usize) -> Option<&'a mut T> { - match make_mut_slice!(T => &'a mut [T]: self.ptr, self.end).get_mut(n) { + match make_mut_slice!(self.ptr, self.end).get_mut(n) { Some(elem_ref) => unsafe { - self.ptr = slice_add_offset!(elem_ref as *mut _, 1); + self.ptr = slice_offset!(self.ptr, (n as isize).wrapping_add(1)); Some(slice_ref!(elem_ref)) }, None => { diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 4d39607b16e..11ca6e332b5 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -44,8 +44,11 @@ pub trait FromStr { #[stable(feature = "rust1", since = "1.0.0")] type Err; - /// Parses a string `s` to return an optional value of this type. If the - /// string is ill-formatted, the None is returned. + /// Parses a string `s` to return a value of this type. + /// + /// If parsing succeeds, return the value inside `Ok`, otherwise + /// when the string is ill-formatted return an error specific to the + /// inside `Err`. The error type is specific to implementation of the trait. #[stable(feature = "rust1", since = "1.0.0")] fn from_str(s: &str) -> Result<Self, Self::Err>; } diff --git a/src/liblibc/lib.rs b/src/liblibc/lib.rs index 55934da00a3..69ab34fee5a 100644 --- a/src/liblibc/lib.rs +++ b/src/liblibc/lib.rs @@ -5722,6 +5722,9 @@ pub mod funcs { pub fn tcgetpgrp(fd: c_int) -> pid_t; pub fn ttyname(fd: c_int) -> *mut c_char; pub fn unlink(c: *const c_char) -> c_int; + pub fn wait(status: *const c_int) -> pid_t; + pub fn waitpid(pid: pid_t, status: *const c_int, options: c_int) + -> pid_t; pub fn write(fd: c_int, buf: *const c_void, count: size_t) -> ssize_t; pub fn pread(fd: c_int, buf: *mut c_void, count: size_t, @@ -5773,6 +5776,9 @@ pub mod funcs { pub fn sysconf(name: c_int) -> c_long; pub fn ttyname(fd: c_int) -> *mut c_char; pub fn unlink(c: *const c_char) -> c_int; + pub fn wait(status: *const c_int) -> pid_t; + pub fn waitpid(pid: pid_t, status: *const c_int, options: c_int) + -> pid_t; pub fn write(fd: c_int, buf: *const c_void, count: size_t) -> ssize_t; pub fn pread(fd: c_int, buf: *mut c_void, count: size_t, diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index aaf615ee404..6690e6831af 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -273,8 +273,8 @@ See also http://doc.rust-lang.org/book/unsafe.html E0137: r##" This error indicates that the compiler found multiple functions with the -#[main] attribute. This is an error because there must be a unique entry point -into a Rust program. +`#[main]` attribute. This is an error because there must be a unique entry +point into a Rust program. "##, E0152: r##" @@ -745,6 +745,7 @@ variable. For example: +``` let x: i32 = "I am not a number!"; // ~~~ ~~~~~~~~~~~~~~~~~~~~ // | | @@ -752,6 +753,7 @@ let x: i32 = "I am not a number!"; // | compiler infers type `&str` // | // type `i32` assigned to variable `x` +``` "##, E0309: r##" @@ -760,6 +762,7 @@ how long the data stored within them is guaranteed to be live. This lifetime must be as long as the data needs to be alive, and missing the constraint that denotes this will cause this error. +``` // This won't compile because T is not constrained, meaning the data // stored in it is not guaranteed to last as long as the reference struct Foo<'a, T> { @@ -770,6 +773,7 @@ struct Foo<'a, T> { struct Foo<'a, T: 'a> { foo: &'a T } +``` "##, E0310: r##" @@ -778,6 +782,7 @@ how long the data stored within them is guaranteed to be live. This lifetime must be as long as the data needs to be alive, and missing the constraint that denotes this will cause this error. +``` // This won't compile because T is not constrained to the static lifetime // the reference needs struct Foo<T> { @@ -788,6 +793,7 @@ struct Foo<T> { struct Foo<T: 'static> { foo: &'static T } +``` "## } diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index 06a40f1dd27..b6202084296 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -189,6 +189,7 @@ pub const tag_item_impl_vtables: usize = 0x7e; pub const tag_impls: usize = 0x109; // top-level only pub const tag_impls_impl: usize = 0x7f; +pub const tag_impls_impl_trait_def_id: usize = 0x8d; pub const tag_items_data_item_inherent_impl: usize = 0x80; pub const tag_items_data_item_extension_impl: usize = 0x81; diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index 7132ac4895a..6caefec4878 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -304,31 +304,23 @@ pub fn get_native_libraries(cstore: &cstore::CStore, crate_num: ast::CrateNum) decoder::get_native_libraries(&*cdata) } -pub fn each_impl<F>(cstore: &cstore::CStore, - crate_num: ast::CrateNum, - callback: F) where - F: FnMut(ast::DefId), -{ - let cdata = cstore.get_crate_data(crate_num); - decoder::each_impl(&*cdata, callback) -} - -pub fn each_implementation_for_type<F>(cstore: &cstore::CStore, - def_id: ast::DefId, - callback: F) where +pub fn each_inherent_implementation_for_type<F>(cstore: &cstore::CStore, + def_id: ast::DefId, + callback: F) where F: FnMut(ast::DefId), { let cdata = cstore.get_crate_data(def_id.krate); - decoder::each_implementation_for_type(&*cdata, def_id.node, callback) + decoder::each_inherent_implementation_for_type(&*cdata, def_id.node, callback) } pub fn each_implementation_for_trait<F>(cstore: &cstore::CStore, def_id: ast::DefId, - callback: F) where + mut callback: F) where F: FnMut(ast::DefId), { - let cdata = cstore.get_crate_data(def_id.krate); - decoder::each_implementation_for_trait(&*cdata, def_id.node, callback) + cstore.iter_crate_data(|_, cdata| { + decoder::each_implementation_for_trait(cdata, def_id, &mut callback) + }) } /// If the given def ID describes an item belonging to a trait (either a diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 00fc42341c3..382dc437bdc 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -21,7 +21,8 @@ use metadata::common::*; use metadata::csearch::MethodInfo; use metadata::csearch; use metadata::cstore; -use metadata::tydecode::{parse_ty_data, parse_region_data, parse_def_id, +use metadata::encoder::def_to_u64; +use metadata::tydecode::{parse_ty_data, parse_region_data, parse_type_param_def_data, parse_bare_fn_ty_data, parse_trait_ref_data, parse_predicate_data}; use middle::def; @@ -190,29 +191,32 @@ fn item_symbol(item: rbml::Doc) -> String { reader::get_doc(item, tag_items_data_item_symbol).as_str().to_string() } -fn item_parent_item(d: rbml::Doc) -> Option<ast::DefId> { +fn translated_def_id(cdata: Cmd, d: rbml::Doc) -> ast::DefId { + let id = reader::doc_as_u64(d); + let def_id = ast::DefId { krate: (id >> 32) as u32, node: id as u32 }; + translate_def_id(cdata, def_id) +} + +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(reader::with_doc_data(did, parse_def_id)); + ret = Some(translated_def_id(cdata, did)); false }); ret } -fn item_reqd_and_translated_parent_item(cnum: ast::CrateNum, - d: rbml::Doc) -> ast::DefId { - let trait_did = item_parent_item(d).expect("item without parent"); - ast::DefId { krate: cnum, node: trait_did.node } +fn item_require_parent_item(cdata: Cmd, d: rbml::Doc) -> ast::DefId { + translated_def_id(cdata, reader::get_doc(d, tag_items_data_parent_item)) } fn item_def_id(d: rbml::Doc, cdata: Cmd) -> ast::DefId { - let tagdoc = reader::get_doc(d, tag_def_id); - return translate_def_id(cdata, reader::with_doc_data(tagdoc, parse_def_id)); + translated_def_id(cdata, reader::get_doc(d, tag_def_id)) } fn get_provided_source(d: rbml::Doc, cdata: Cmd) -> Option<ast::DefId> { reader::maybe_get_doc(d, tag_item_method_provided_source).map(|doc| { - translate_def_id(cdata, reader::with_doc_data(doc, parse_def_id)) + translated_def_id(cdata, doc) }) } @@ -261,14 +265,12 @@ fn item_trait_ref<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd) } fn enum_variant_ids(item: rbml::Doc, cdata: Cmd) -> Vec<ast::DefId> { - let mut ids: Vec<ast::DefId> = Vec::new(); - let v = tag_items_data_item_variant; - reader::tagged_docs(item, v, |p| { - let ext = reader::with_doc_data(p, parse_def_id); - ids.push(ast::DefId { krate: cdata.cnum, node: ext.node }); + let mut ids = vec![]; + reader::tagged_docs(item, tag_items_data_item_variant, |p| { + ids.push(translated_def_id(cdata, p)); true }); - return ids; + ids } fn item_path(item_doc: rbml::Doc) -> Vec<ast_map::PathElem> { @@ -303,8 +305,7 @@ fn item_name(intr: &IdentInterner, item: rbml::Doc) -> ast::Name { } } -fn item_to_def_like(item: rbml::Doc, did: ast::DefId, cnum: ast::CrateNum) - -> DefLike { +fn item_to_def_like(cdata: Cmd, item: rbml::Doc, did: ast::DefId) -> DefLike { let fam = item_family(item); match fam { Constant => { @@ -314,11 +315,9 @@ fn item_to_def_like(item: rbml::Doc, did: ast::DefId, cnum: ast::CrateNum) // See the comment for methods below. let provenance = if reader::maybe_get_doc( item, tag_item_trait_parent_sort).is_some() { - def::FromTrait(item_reqd_and_translated_parent_item(cnum, - item)) + def::FromTrait(item_require_parent_item(cdata, item)) } else { - def::FromImpl(item_reqd_and_translated_parent_item(cnum, - item)) + def::FromImpl(item_require_parent_item(cdata, item)) }; DlDef(def::DefAssociatedConst(did, provenance)) } else { @@ -339,17 +338,15 @@ fn item_to_def_like(item: rbml::Doc, did: ast::DefId, cnum: ast::CrateNum) // a trait_parent_sort. let provenance = if reader::maybe_get_doc( item, tag_item_trait_parent_sort).is_some() { - def::FromTrait(item_reqd_and_translated_parent_item(cnum, - item)) + def::FromTrait(item_require_parent_item(cdata, item)) } else { - def::FromImpl(item_reqd_and_translated_parent_item(cnum, - item)) + def::FromImpl(item_require_parent_item(cdata, item)) }; DlDef(def::DefMethod(did, provenance)) } Type => { if item_sort(item) == Some('t') { - let trait_did = item_reqd_and_translated_parent_item(cnum, item); + let trait_did = item_require_parent_item(cdata, item); DlDef(def::DefAssociatedTy(trait_did, did)) } else { DlDef(def::DefTy(did, false)) @@ -358,11 +355,11 @@ fn item_to_def_like(item: rbml::Doc, did: ast::DefId, cnum: ast::CrateNum) Mod => DlDef(def::DefMod(did)), ForeignMod => DlDef(def::DefForeignMod(did)), StructVariant => { - let enum_did = item_reqd_and_translated_parent_item(cnum, item); + let enum_did = item_require_parent_item(cdata, item); DlDef(def::DefVariant(enum_did, did, true)) } TupleVariant => { - let enum_did = item_reqd_and_translated_parent_item(cnum, item); + let enum_did = item_require_parent_item(cdata, item); DlDef(def::DefVariant(enum_did, did, false)) } Trait => DlDef(def::DefTrait(did)), @@ -560,9 +557,7 @@ fn each_child_of_item_or_crate<F, G>(intr: Rc<IdentInterner>, { // Iterate over all children. let _ = reader::tagged_docs(item_doc, tag_mod_child, |child_info_doc| { - let child_def_id = reader::with_doc_data(child_info_doc, - parse_def_id); - let child_def_id = translate_def_id(cdata, child_def_id); + 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 // reexport. @@ -584,9 +579,7 @@ fn each_child_of_item_or_crate<F, G>(intr: Rc<IdentInterner>, Some(child_item_doc) => { // Hand off the item to the callback. let child_name = item_name(&*intr, child_item_doc); - let def_like = item_to_def_like(child_item_doc, - child_def_id, - cdata.cnum); + 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); @@ -615,9 +608,8 @@ fn each_child_of_item_or_crate<F, G>(intr: Rc<IdentInterner>, if let StaticMethod = item_family(impl_method_doc) { // Hand off the static method to the callback. let static_method_name = item_name(&*intr, impl_method_doc); - let static_method_def_like = item_to_def_like(impl_method_doc, - impl_item_def_id, - cdata.cnum); + let static_method_def_like = item_to_def_like(cdata, impl_method_doc, + impl_item_def_id); callback(static_method_def_like, static_method_name, item_visibility(impl_method_doc)); @@ -633,9 +625,7 @@ fn each_child_of_item_or_crate<F, G>(intr: Rc<IdentInterner>, let _ = each_reexport(item_doc, |reexport_doc| { let def_id_doc = reader::get_doc(reexport_doc, tag_items_data_item_reexport_def_id); - let child_def_id = reader::with_doc_data(def_id_doc, - parse_def_id); - let child_def_id = translate_def_id(cdata, child_def_id); + let child_def_id = translated_def_id(cdata, def_id_doc); let name_doc = reader::get_doc(reexport_doc, tag_items_data_item_reexport_name); @@ -657,9 +647,7 @@ fn each_child_of_item_or_crate<F, G>(intr: Rc<IdentInterner>, // Get the item. if let Some(child_item_doc) = maybe_find_item(child_def_id.node, other_crates_items) { // Hand off the item to the callback. - let def_like = item_to_def_like(child_item_doc, - child_def_id, - child_def_id.krate); + let def_like = item_to_def_like(crate_data, child_item_doc, child_def_id); // These items have a public visibility because they're part of // a public re-export. callback(def_like, token::intern(name), ast::Public); @@ -733,9 +721,8 @@ pub fn maybe_get_item_ast<'tcx>(cdata: Cmd, tcx: &ty::ctxt<'tcx>, id: ast::NodeI match decode_inlined_item(cdata, tcx, path, item_doc) { Ok(ii) => csearch::FoundAst::Found(ii), Err(path) => { - match item_parent_item(item_doc) { + match item_parent_item(cdata, item_doc) { Some(did) => { - let did = translate_def_id(cdata, did); let parent_item = lookup_item(did.node, cdata.data()); match decode_inlined_item(cdata, tcx, path, parent_item) { Ok(ii) => csearch::FoundAst::FoundParent(did, ii), @@ -759,7 +746,7 @@ pub fn get_enum_variant_defs(intr: &IdentInterner, let item = find_item(did.node, items); let name = item_name(intr, item); let visibility = item_visibility(item); - match item_to_def_like(item, *did, cdata.cnum) { + match item_to_def_like(cdata, item, *did) { DlDef(def @ def::DefVariant(..)) => (def, name, visibility), _ => unreachable!() } @@ -889,8 +876,7 @@ pub fn get_impl_or_trait_item<'tcx>(intr: Rc<IdentInterner>, let def_id = item_def_id(method_doc, cdata); - let container_id = item_reqd_and_translated_parent_item(cdata.cnum, - method_doc); + let container_id = item_require_parent_item(cdata, method_doc); let container_doc = lookup_item(container_id.node, cdata.data()); let container = match item_family(container_doc) { Trait => TraitContainer(container_id), @@ -1094,7 +1080,7 @@ pub fn get_tuple_struct_definition_if_ctor(cdata: Cmd, 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_reqd_and_translated_parent_item(cdata.cnum, item)); + ret = Some(item_require_parent_item(cdata, item)); false }); ret @@ -1144,7 +1130,7 @@ pub fn get_struct_fields(intr: Rc<IdentInterner>, cdata: Cmd, id: ast::NodeId) 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 = translate_def_id(cdata, reader::with_doc_data(tagdoc, parse_def_id)); + let origin_id = translated_def_id(cdata, tagdoc); result.push(ty::field_ty { name: name, id: did, @@ -1158,7 +1144,7 @@ pub fn get_struct_fields(intr: Rc<IdentInterner>, cdata: Cmd, id: ast::NodeId) 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 = translate_def_id(cdata, reader::with_doc_data(tagdoc, parse_def_id)); + let origin_id = translated_def_id(cdata, tagdoc); result.push(ty::field_ty { name: special_idents::unnamed_field.name, id: did, @@ -1342,55 +1328,77 @@ pub fn translate_def_id(cdata: Cmd, did: ast::DefId) -> ast::DefId { } } -pub fn each_impl<F>(cdata: Cmd, mut callback: F) where - F: FnMut(ast::DefId), -{ - let impls_doc = reader::get_doc(rbml::Doc::new(cdata.data()), tag_impls); - let _ = reader::tagged_docs(impls_doc, tag_impls_impl, |impl_doc| { - callback(item_def_id(impl_doc, cdata)); - true - }); +// Translate a DefId from the current compilation environment to a DefId +// for an external crate. +fn reverse_translate_def_id(cdata: Cmd, did: ast::DefId) -> Option<ast::DefId> { + if did.krate == cdata.cnum { + return Some(ast::DefId { krate: ast::LOCAL_CRATE, node: did.node }); + } + + for (&local, &global) in &cdata.cnum_map { + if global == did.krate { + return Some(ast::DefId { krate: local, node: did.node }); + } + } + + None } -pub fn each_implementation_for_type<F>(cdata: Cmd, - id: ast::NodeId, - mut callback: F) +pub fn each_inherent_implementation_for_type<F>(cdata: Cmd, + id: ast::NodeId, + mut callback: F) 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| { - let implementation_def_id = item_def_id(impl_doc, cdata); - callback(implementation_def_id); + 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, - id: ast::NodeId, + def_id: ast::DefId, mut callback: F) where F: FnMut(ast::DefId), { - let item_doc = lookup_item(id, cdata.data()); + 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| { + callback(item_def_id(impl_doc, cdata)); + true + }); + return; + } - let _ = reader::tagged_docs(item_doc, - tag_items_data_item_extension_impl, - |impl_doc| { - let implementation_def_id = item_def_id(impl_doc, cdata); - callback(implementation_def_id); - true - }); + // Do a reverse lookup beforehand to avoid touching the crate_num + // hash map in the loop below. + if let Some(crate_local_did) = reverse_translate_def_id(cdata, def_id) { + 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| { + 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 + }); + } } pub fn get_trait_of_item(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt) -> Option<ast::DefId> { let item_doc = lookup_item(id, cdata.data()); - let parent_item_id = match item_parent_item(item_doc) { + let parent_item_id = match item_parent_item(cdata, item_doc) { None => return None, Some(item_id) => item_id, }; - let parent_item_id = translate_def_id(cdata, parent_item_id); let parent_item_doc = lookup_item(parent_item_id.node, cdata.data()); match item_family(parent_item_doc) { Trait => Some(item_def_id(parent_item_doc, cdata)), @@ -1538,8 +1546,7 @@ fn doc_generics<'tcx>(base_doc: rbml::Doc, let name = item_name(&*token::get_ident_interner(), ident_str_doc); let def_id_doc = reader::get_doc(rp_doc, tag_region_param_def_def_id); - let def_id = reader::with_doc_data(def_id_doc, parse_def_id); - let def_id = translate_def_id(cdata, def_id); + let def_id = translated_def_id(cdata, def_id_doc); let doc = reader::get_doc(rp_doc, tag_region_param_def_space); let space = subst::ParamSpace::from_uint(reader::doc_as_u64(doc) as usize); diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 90dd452e06b..afc71f83975 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -91,8 +91,8 @@ fn encode_impl_type_basename(rbml_w: &mut Encoder, name: ast::Name) { rbml_w.wr_tagged_str(tag_item_impl_type_basename, &token::get_name(name)); } -pub fn encode_def_id(rbml_w: &mut Encoder, id: DefId) { - rbml_w.wr_tagged_str(tag_def_id, &def_to_string(id)); +fn encode_def_id(rbml_w: &mut Encoder, id: DefId) { + rbml_w.wr_tagged_u64(tag_def_id, def_to_u64(id)); } #[derive(Clone)] @@ -122,6 +122,10 @@ fn encode_family(rbml_w: &mut Encoder, c: char) { rbml_w.wr_tagged_u8(tag_items_data_item_family, c as u8); } +pub fn def_to_u64(did: DefId) -> u64 { + (did.krate as u64) << 32 | (did.node as u64) +} + pub fn def_to_string(did: DefId) -> String { format!("{}:{}", did.krate, did.node) } @@ -153,9 +157,9 @@ fn encode_bounds_and_type<'a, 'tcx>(rbml_w: &mut Encoder, } fn encode_variant_id(rbml_w: &mut Encoder, vid: DefId) { - let s = def_to_string(vid); - rbml_w.wr_tagged_str(tag_items_data_item_variant, &s[..]); - rbml_w.wr_tagged_str(tag_mod_child, &s[..]); + let id = def_to_u64(vid); + rbml_w.wr_tagged_u64(tag_items_data_item_variant, id); + rbml_w.wr_tagged_u64(tag_mod_child, id); } pub fn write_closure_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, @@ -260,7 +264,7 @@ fn encode_disr_val(_: &EncodeContext, } fn encode_parent_item(rbml_w: &mut Encoder, id: DefId) { - rbml_w.wr_tagged_str(tag_items_data_parent_item, &def_to_string(id)); + rbml_w.wr_tagged_u64(tag_items_data_parent_item, def_to_u64(id)); } fn encode_struct_fields(rbml_w: &mut Encoder, @@ -275,7 +279,7 @@ fn encode_struct_fields(rbml_w: &mut Encoder, } encode_struct_field_family(rbml_w, f.vis); encode_def_id(rbml_w, f.id); - rbml_w.wr_tagged_str(tag_item_field_origin, &def_to_string(origin)); + rbml_w.wr_tagged_u64(tag_item_field_origin, def_to_u64(origin)); rbml_w.end_tag(); } } @@ -358,8 +362,8 @@ fn encode_reexported_static_method(rbml_w: &mut Encoder, debug!("(encode reexported static method) {}::{}", exp.name, token::get_name(method_name)); rbml_w.start_tag(tag_items_data_item_reexport); - rbml_w.wr_tagged_str(tag_items_data_item_reexport_def_id, - &def_to_string(method_def_id)); + rbml_w.wr_tagged_u64(tag_items_data_item_reexport_def_id, + def_to_u64(method_def_id)); rbml_w.wr_tagged_str(tag_items_data_item_reexport_name, &format!("{}::{}", exp.name, token::get_name(method_name))); @@ -495,8 +499,8 @@ fn encode_reexports(ecx: &EncodeContext, exp.def_id.node, id); rbml_w.start_tag(tag_items_data_item_reexport); - rbml_w.wr_tagged_str(tag_items_data_item_reexport_def_id, - &def_to_string(exp.def_id)); + rbml_w.wr_tagged_u64(tag_items_data_item_reexport_def_id, + def_to_u64(exp.def_id)); rbml_w.wr_tagged_str(tag_items_data_item_reexport_name, exp.name.as_str()); rbml_w.end_tag(); @@ -526,12 +530,12 @@ fn encode_info_for_mod(ecx: &EncodeContext, // Encode info about all the module children. for item in &md.items { - rbml_w.wr_tagged_str(tag_mod_child, - &def_to_string(local_def(item.id))); + rbml_w.wr_tagged_u64(tag_mod_child, + def_to_u64(local_def(item.id))); each_auxiliary_node_id(&**item, |auxiliary_node_id| { - rbml_w.wr_tagged_str(tag_mod_child, - &def_to_string(local_def(auxiliary_node_id))); + rbml_w.wr_tagged_u64(tag_mod_child, + def_to_u64(local_def(auxiliary_node_id))); true }); @@ -541,8 +545,7 @@ fn encode_info_for_mod(ecx: &EncodeContext, token::get_ident(ident), did, ecx.tcx.map.node_to_string(did)); - rbml_w.wr_tagged_str(tag_mod_impl, - &def_to_string(local_def(did))); + rbml_w.wr_tagged_u64(tag_mod_impl, def_to_u64(local_def(did))); } } @@ -619,8 +622,7 @@ fn encode_parent_sort(rbml_w: &mut Encoder, sort: char) { fn encode_provided_source(rbml_w: &mut Encoder, source_opt: Option<DefId>) { if let Some(source) = source_opt { - rbml_w.wr_tagged_str(tag_item_method_provided_source, - &def_to_string(source)); + rbml_w.wr_tagged_u64(tag_item_method_provided_source, def_to_u64(source)); } } @@ -725,8 +727,8 @@ fn encode_generics<'a, 'tcx>(rbml_w: &mut Encoder, encode_name(rbml_w, param.name); rbml_w.end_tag(); - rbml_w.wr_tagged_str(tag_region_param_def_def_id, - &def_to_string(param.def_id)); + rbml_w.wr_tagged_u64(tag_region_param_def_def_id, + def_to_u64(param.def_id)); rbml_w.wr_tagged_u64(tag_region_param_def_space, param.space.to_uint() as u64); @@ -1089,8 +1091,8 @@ fn encode_info_for_item(ecx: &EncodeContext, // Encode all the items in this module. for foreign_item in &fm.items { - rbml_w.wr_tagged_str(tag_mod_child, - &def_to_string(local_def(foreign_item.id))); + rbml_w.wr_tagged_u64(tag_mod_child, + def_to_u64(local_def(foreign_item.id))); } encode_visibility(rbml_w, vis); encode_stability(rbml_w, stab); @@ -1335,8 +1337,8 @@ fn encode_info_for_item(ecx: &EncodeContext, } rbml_w.end_tag(); - rbml_w.wr_tagged_str(tag_mod_child, - &def_to_string(method_def_id.def_id())); + rbml_w.wr_tagged_u64(tag_mod_child, + def_to_u64(method_def_id.def_id())); } encode_path(rbml_w, path.clone()); @@ -1893,6 +1895,7 @@ impl<'a, 'b, 'c, 'tcx, 'v> Visitor<'v> for ImplVisitor<'a, 'b, 'c, 'tcx> { def_id.krate != ast::LOCAL_CRATE { self.rbml_w.start_tag(tag_impls_impl); encode_def_id(self.rbml_w, local_def(item.id)); + self.rbml_w.wr_tagged_u64(tag_impls_impl_trait_def_id, def_to_u64(def_id)); self.rbml_w.end_tag(); } } @@ -1932,12 +1935,12 @@ fn encode_misc_info(ecx: &EncodeContext, rbml_w.start_tag(tag_misc_info); rbml_w.start_tag(tag_misc_info_crate_items); for item in &krate.module.items { - rbml_w.wr_tagged_str(tag_mod_child, - &def_to_string(local_def(item.id))); + rbml_w.wr_tagged_u64(tag_mod_child, + def_to_u64(local_def(item.id))); each_auxiliary_node_id(&**item, |auxiliary_node_id| { - rbml_w.wr_tagged_str(tag_mod_child, - &def_to_string(local_def(auxiliary_node_id))); + rbml_w.wr_tagged_u64(tag_mod_child, + def_to_u64(local_def(auxiliary_node_id))); true }); } diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index d740d24e236..0458bd70346 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -1125,7 +1125,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { // that case we can adjust the length of the // original vec accordingly, but we'd have to // make trans do the right thing, and it would - // only work for `~` vectors. It seems simpler + // only work for `Box<[T]>`s. It seems simpler // to just require that people call // `vec.pop()` or `vec.unshift()`. let slice_bk = ty::BorrowKind::from_mutbl(slice_mutbl); diff --git a/src/librustc/middle/traits/coherence.rs b/src/librustc/middle/traits/coherence.rs index d9f8a88fddc..222da6d7c3e 100644 --- a/src/librustc/middle/traits/coherence.rs +++ b/src/librustc/middle/traits/coherence.rs @@ -323,7 +323,7 @@ fn ty_is_local_constructor<'tcx>(tcx: &ty::ctxt<'tcx>, def_id.krate == ast::LOCAL_CRATE } - ty::ty_uniq(_) => { // treat ~T like Box<T> + ty::ty_uniq(_) => { // Box<T> let krate = tcx.lang_items.owned_box().map(|d| d.krate); krate == Some(ast::LOCAL_CRATE) } diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 49371eae265..e199bb17bf9 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -117,23 +117,71 @@ pub enum MethodMatchedData { /// obligation is for `int`. In that case, we drop the impl out of the /// list. But the other cases are considered *candidates*. /// -/// Candidates can either be definitive or ambiguous. An ambiguous -/// candidate is one that might match or might not, depending on how -/// type variables wind up being resolved. This only occurs during inference. +/// For selection to succeed, there must be exactly one matching +/// candidate. If the obligation is fully known, this is guaranteed +/// by coherence. However, if the obligation contains type parameters +/// or variables, there may be multiple such impls. /// -/// For selection to succeed, there must be exactly one non-ambiguous -/// candidate. Usually, it is not possible to have more than one -/// definitive candidate, due to the coherence rules. However, there is -/// one case where it could occur: if there is a blanket impl for a -/// trait (that is, an impl applied to all T), and a type parameter -/// with a where clause. In that case, we can have a candidate from the -/// where clause and a second candidate from the impl. This is not a -/// problem because coherence guarantees us that the impl which would -/// be used to satisfy the where clause is the same one that we see -/// now. To resolve this issue, therefore, we ignore impls if we find a -/// matching where clause. Part of the reason for this is that where -/// clauses can give additional information (like, the types of output -/// parameters) that would have to be inferred from the impl. +/// It is not a real problem if multiple matching impls exist because +/// of type variables - it just means the obligation isn't sufficiently +/// elaborated. In that case we report an ambiguity, and the caller can +/// try again after more type information has been gathered or report a +/// "type annotations required" error. +/// +/// However, with type parameters, this can be a real problem - type +/// parameters don't unify with regular types, but they *can* unify +/// with variables from blanket impls, and (unless we know its bounds +/// will always be satisfied) picking the blanket impl will be wrong +/// for at least *some* substitutions. To make this concrete, if we have +/// +/// trait AsDebug { type Out : fmt::Debug; fn debug(self) -> Self::Out; } +/// impl<T: fmt::Debug> AsDebug for T { +/// type Out = T; +/// fn debug(self) -> fmt::Debug { self } +/// } +/// fn foo<T: AsDebug>(t: T) { println!("{:?}", <T as AsDebug>::debug(t)); } +/// +/// we can't just use the impl to resolve the <T as AsDebug> obligation +/// - a type from another crate (that doesn't implement fmt::Debug) could +/// implement AsDebug. +/// +/// Because where-clauses match the type exactly, multiple clauses can +/// only match if there are unresolved variables, and we can mostly just +/// report this ambiguity in that case. This is still a problem - we can't +/// *do anything* with ambiguities that involve only regions. This is issue +/// #21974. +/// +/// If a single where-clause matches and there are no inference +/// variables left, then it definitely matches and we can just select +/// it. +/// +/// In fact, we even select the where-clause when the obligation contains +/// inference variables. The can lead to inference making "leaps of logic", +/// for example in this situation: +/// +/// pub trait Foo<T> { fn foo(&self) -> T; } +/// impl<T> Foo<()> for T { fn foo(&self) { } } +/// impl Foo<bool> for bool { fn foo(&self) -> bool { *self } } +/// +/// pub fn foo<T>(t: T) where T: Foo<bool> { +/// println!("{:?}", <T as Foo<_>>::foo(&t)); +/// } +/// fn main() { foo(false); } +/// +/// Here the obligation <T as Foo<$0>> can be matched by both the blanket +/// impl and the where-clause. We select the where-clause and unify $0=bool, +/// so the program prints "false". However, if the where-clause is omitted, +/// the blanket impl is selected, we unify $0=(), and the program prints +/// "()". +/// +/// Exactly the same issues apply to projection and object candidates, except +/// that we can have both a projection candidate and a where-clause candidate +/// for the same obligation. In that case either would do (except that +/// different "leaps of logic" would occur if inference variables are +/// present), and we just pick the projection. This is, for example, +/// required for associated types to work in default impls, as the bounds +/// are visible both as projection bounds and as where-clauses from the +/// parameter environment. #[derive(PartialEq,Eq,Debug,Clone)] enum SelectionCandidate<'tcx> { PhantomFnCandidate, @@ -1350,63 +1398,51 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Returns true if `candidate_i` should be dropped in favor of /// `candidate_j`. Generally speaking we will drop duplicate /// candidates and prefer where-clause candidates. + /// Returns true if `victim` should be dropped in favor of + /// `other`. Generally speaking we will drop duplicate + /// candidates and prefer where-clause candidates. + /// + /// See the comment for "SelectionCandidate" for more details. fn candidate_should_be_dropped_in_favor_of<'o>(&mut self, - candidate_i: &SelectionCandidate<'tcx>, - candidate_j: &SelectionCandidate<'tcx>) + victim: &SelectionCandidate<'tcx>, + other: &SelectionCandidate<'tcx>) -> bool { - if candidate_i == candidate_j { + if victim == other { return true; } - match (candidate_i, candidate_j) { - (&ImplCandidate(..), &ParamCandidate(..)) | - (&ClosureCandidate(..), &ParamCandidate(..)) | - (&FnPointerCandidate(..), &ParamCandidate(..)) | - (&BuiltinObjectCandidate(..), &ParamCandidate(_)) | - (&BuiltinCandidate(..), &ParamCandidate(..)) => { - // We basically prefer always prefer to use a - // where-clause over another option. Where clauses - // impose the burden of finding the exact match onto - // the caller. Using an impl in preference of a where - // clause can also lead us to "overspecialize", as in - // #18453. - true - } - (&ImplCandidate(..), &ObjectCandidate(..)) => { - // This means that we are matching an object of type - // `Trait` against the trait `Trait`. In that case, we - // always prefer to use the object vtable over the - // impl. Like a where clause, the impl may or may not - // be the one that is used by the object (because the - // impl may have additional where-clauses that the - // object's source might not meet) -- if it is, using - // the vtable is fine. If it is not, using the vtable - // is good. A win win! - true - } - (&DefaultImplCandidate(_), _) => { - // Prefer other candidates over default implementations. - self.tcx().sess.bug( - "default implementations shouldn't be recorded \ - when there are other valid candidates"); - } - (&ProjectionCandidate, &ParamCandidate(_)) => { - // FIXME(#20297) -- this gives where clauses precedent - // over projections. Really these are just two means - // of deducing information (one based on the where - // clauses on the trait definition; one based on those - // on the enclosing scope), and it'd be better to - // integrate them more intelligently. But for now this - // seems ok. If we DON'T give where clauses - // precedence, we run into trouble in default methods, - // where both the projection bounds for `Self::A` and - // the where clauses are in scope. - true - } - _ => { - false - } + match other { + &ObjectCandidate(..) | + &ParamCandidate(_) | &ProjectionCandidate => match victim { + &DefaultImplCandidate(..) => { + self.tcx().sess.bug( + "default implementations shouldn't be recorded \ + when there are other valid candidates"); + } + &PhantomFnCandidate => { + self.tcx().sess.bug("PhantomFn didn't short-circuit selection"); + } + &ImplCandidate(..) | + &ClosureCandidate(..) | + &FnPointerCandidate(..) | + &BuiltinObjectCandidate(..) | + &DefaultImplObjectCandidate(..) | + &BuiltinCandidate(..) => { + // We have a where-clause so don't go around looking + // for impls. + true + } + &ObjectCandidate(..) | + &ProjectionCandidate => { + // Arbitrarily give param candidates priority + // over projection and object candidates. + true + }, + &ParamCandidate(..) => false, + &ErrorCandidate => false // propagate errors + }, + _ => false } } @@ -2441,10 +2477,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// `match_impl()`. For example, if `impl_def_id` is declared /// as: /// - /// impl<T:Copy> Foo for ~T { ... } + /// impl<T:Copy> Foo for Box<T> { ... } /// - /// and `obligation_self_ty` is `int`, we'd back an `Err(_)` - /// result. But if `obligation_self_ty` were `~int`, we'd get + /// and `obligation_self_ty` is `int`, we'd get back an `Err(_)` + /// result. But if `obligation_self_ty` were `Box<int>`, we'd get /// back `Ok(T=int)`. fn match_inherent_impl(&mut self, impl_def_id: ast::DefId, diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index cb069acdfd2..e445b6bb300 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -2564,9 +2564,11 @@ impl<'tcx> TraitDef<'tcx> { 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)); + // 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. - if let Some(sty) = fast_reject::simplify_type(tcx, impl_trait_ref.self_ty(), false) { if let Some(is) = self.nonblanket_impls.borrow().get(&sty) { @@ -6336,10 +6338,10 @@ pub fn populate_implementations_for_primitive_if_necessary(tcx: &ctxt, tcx.populated_external_primitive_impls.borrow_mut().insert(primitive_def_id); } -/// Populates the type context with all the implementations for the given type -/// if necessary. -pub fn populate_implementations_for_type_if_necessary(tcx: &ctxt, - type_id: ast::DefId) { +/// Populates the type context with all the inherent implementations for +/// the given type if necessary. +pub fn populate_inherent_implementations_for_type_if_necessary(tcx: &ctxt, + type_id: ast::DefId) { if type_id.krate == LOCAL_CRATE { return } @@ -6348,37 +6350,15 @@ pub fn populate_implementations_for_type_if_necessary(tcx: &ctxt, return } - debug!("populate_implementations_for_type_if_necessary: searching for {:?}", type_id); + debug!("populate_inherent_implementations_for_type_if_necessary: searching for {:?}", type_id); let mut inherent_impls = Vec::new(); - csearch::each_implementation_for_type(&tcx.sess.cstore, type_id, |impl_def_id| { - let impl_items = csearch::get_impl_items(&tcx.sess.cstore, impl_def_id); - - // Record the implementation, if needed - if let Some(trait_ref) = csearch::get_impl_trait(tcx, impl_def_id) { - let trait_def = lookup_trait_def(tcx, trait_ref.def_id); - trait_def.record_impl(tcx, impl_def_id, trait_ref); - } else { - inherent_impls.push(impl_def_id); - } - - // For any methods that use a default implementation, add them to - // the map. This is a bit unfortunate. - for impl_item_def_id in &impl_items { - let method_def_id = impl_item_def_id.def_id(); - match impl_or_trait_item(tcx, method_def_id) { - MethodTraitItem(method) => { - if let Some(source) = method.provided_source { - tcx.provided_method_sources - .borrow_mut() - .insert(method_def_id, source); - } - } - _ => {} - } - } + csearch::each_inherent_implementation_for_type(&tcx.sess.cstore, type_id, |impl_def_id| { + // Record the implementation. + inherent_impls.push(impl_def_id); // Store the implementation info. + let impl_items = csearch::get_impl_items(&tcx.sess.cstore, impl_def_id); tcx.impl_items.borrow_mut().insert(impl_def_id, impl_items); }); @@ -6388,18 +6368,18 @@ pub fn populate_implementations_for_type_if_necessary(tcx: &ctxt, /// Populates the type context with all the implementations for the given /// trait if necessary. -pub fn populate_implementations_for_trait_if_necessary( - tcx: &ctxt, - trait_id: ast::DefId) { +pub fn populate_implementations_for_trait_if_necessary(tcx: &ctxt, trait_id: ast::DefId) { if trait_id.krate == LOCAL_CRATE { return } let def = lookup_trait_def(tcx, trait_id); if def.flags.get().intersects(TraitFlags::IMPLS_VALID) { - return + return; } + debug!("populate_implementations_for_trait_if_necessary: searching for {}", def.repr(tcx)); + if csearch::is_defaulted_trait(&tcx.sess.cstore, trait_id) { record_trait_has_default_impl(tcx, trait_id); } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index aa89c1943a2..32ec70c4878 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -637,7 +637,7 @@ impl<'tcx, T:Repr<'tcx>> Repr<'tcx> for OwnedSlice<T> { } } -// This is necessary to handle types like Option<~[T]>, for which +// 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 { diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index 9776538de3f..839b39a8ca0 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -732,7 +732,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { /// let p: Point; /// p.x = 22; // ok, even though `p` is uninitialized /// - /// let p: ~Point; + /// let p: Box<Point>; /// (*p).x = 22; // not ok, p is uninitialized, can't deref /// ``` fn check_if_assigned_path_is_moved(&self, diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 128e29ee76e..9a8bbc5ea0b 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -1314,7 +1314,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> { // `impl [... for] Private` is never visible. let self_contains_private; // impl [... for] Public<...>, but not `impl [... for] - // ~[Public]` or `(Public,)` etc. + // Vec<Public>` or `(Public,)` etc. let self_is_public_path; // check the properties of the Self type: diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index a896bd31169..7e7af800680 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -10,8 +10,111 @@ #![allow(non_snake_case)] +// Error messages for EXXXX errors. +// Each message should start and end with a new line, and be wrapped to 80 characters. +// In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable. +register_long_diagnostics! { + +E0154: r##" +Imports (`use` statements) are not allowed after non-item statements, such as +variable declarations and expression statements. + +Here is an example that demonstrates the error: +``` +fn f() { + // Variable declaration before import + let x = 0; + use std::io::Read; + ... +} +``` + +The solution is to declare the imports at the top of the block, function, or +file. + +Here is the previous example again, with the correct order: +``` +fn f() { + use std::io::Read; + let x = 0; + ... +} +``` + +See the Declaration Statements section of the reference for more information +about what constitutes an Item declaration and what does not: + +http://doc.rust-lang.org/reference.html#statements +"##, + +E0259: r##" +The name chosen for an external crate conflicts with another external crate that +has been imported into the current module. + +Wrong example: +``` +extern crate a; +extern crate crate_a as a; +``` + +The solution is to choose a different name that doesn't conflict with any +external crate imported into the current module. + +Correct example: +``` +extern crate a; +extern crate crate_a as other_name; +``` +"##, + +E0260: r##" +The name for an item declaration conflicts with an external crate's name. + +For instance, +``` +extern crate abc; + +struct abc; +``` + +There are two possible solutions: + +Solution #1: Rename the item. + +``` +extern crate abc; + +struct xyz; +``` + +Solution #2: Import the crate with a different name. + +``` +extern crate abc as xyz; + +struct abc; +``` + +See the Declaration Statements section of the reference for more information +about what constitutes an Item declaration and what does not: + +http://doc.rust-lang.org/reference.html#statements +"##, + +E0317: r##" +User-defined types or type parameters cannot shadow the primitive types. +This error indicates you tried to define a type, struct or enum with the same +name as an existing primitive type. + +See the Types section of the reference for more information about the primitive +types: + +http://doc.rust-lang.org/reference.html#types +"## + +} + register_diagnostics! { - E0154, E0157, E0153, E0251, // a named type or value has already been imported in this module @@ -22,9 +125,6 @@ register_diagnostics! { E0256, // import conflicts with type in this module E0257, // inherent implementations are only allowed on types defined in the current module E0258, // import conflicts with existing submodule - E0259, // an extern crate has already been imported into this module - E0260, // name conflicts with an external crate that has been imported into this module - E0317, // user-defined types or type parameters cannot shadow the primitive types E0364, // item is private E0365 // item is private } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 7abe5a84c5f..447230ada22 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2688,18 +2688,21 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { check_ribs: bool) -> AssocItemResolveResult { + let max_assoc_types; + match maybe_qself { - Some(&ast::QSelf { position: 0, .. }) => - return TypecheckRequired, - _ => {} + Some(qself) => { + if qself.position == 0 { + return TypecheckRequired; + } + max_assoc_types = path.segments.len() - qself.position; + // Make sure the trait is valid. + let _ = self.resolve_trait_reference(id, path, max_assoc_types); + } + None => { + max_assoc_types = path.segments.len(); + } } - let max_assoc_types = if let Some(qself) = maybe_qself { - // Make sure the trait is valid. - let _ = self.resolve_trait_reference(id, path, 1); - path.segments.len() - qself.position - } else { - path.segments.len() - }; let mut resolution = self.with_no_errors(|this| { this.resolve_path(id, path, 0, namespace, check_ribs) diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 350f69d30c4..9870b41e7fa 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -618,7 +618,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { namespace_name, name_bindings.def_for_namespace(namespace)); self.check_for_conflicting_import( - &import_resolution.target_for_namespace(namespace), + &import_resolution, directive.span, target, namespace); @@ -755,7 +755,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { // Continue. } Some(ref value_target) => { - self.check_for_conflicting_import(&dest_import_resolution.value_target, + self.check_for_conflicting_import(&dest_import_resolution, import_directive.span, *ident, ValueNS); @@ -767,7 +767,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { // Continue. } Some(ref type_target) => { - self.check_for_conflicting_import(&dest_import_resolution.type_target, + self.check_for_conflicting_import(&dest_import_resolution, import_directive.span, *ident, TypeNS); @@ -887,24 +887,31 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { /// Checks that imported names and items don't have the same name. fn check_for_conflicting_import(&mut self, - target: &Option<Target>, + import_resolution: &ImportResolution, import_span: Span, name: Name, namespace: Namespace) { + let target = import_resolution.target_for_namespace(namespace); debug!("check_for_conflicting_import: {}; target exists: {}", &token::get_name(name), target.is_some()); - match *target { + match target { Some(ref target) if target.shadowable != Shadowable::Always => { - let msg = format!("a {} named `{}` has already been imported \ - in this module", - match namespace { - TypeNS => "type", - ValueNS => "value", - }, + let ns_word = match namespace { + TypeNS => "type", + ValueNS => "value", + }; + span_err!(self.resolver.session, import_span, E0252, + "a {} named `{}` has already been imported \ + in this module", ns_word, &token::get_name(name)); - span_err!(self.resolver.session, import_span, E0252, "{}", &msg[..]); + let use_id = import_resolution.id(namespace); + let item = self.resolver.ast_map.expect_item(use_id); + // item is syntax::ast::Item; + span_note!(self.resolver.session, item.span, + "previous import of `{}` here", + token::get_name(name)); } Some(_) | None => {} } diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index a11b0f69faa..38ad909dd01 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -289,7 +289,7 @@ pub fn mangle<PI: Iterator<Item=PathElem>>(path: PI, // when using unix's linker. Perhaps one day when we just use a linker from LLVM // we won't need to do this name mangling. The problem with name mangling is // that it seriously limits the available characters. For example we can't - // have things like &T or ~[T] in symbol names when one would theoretically + // have things like &T in symbol names when one would theoretically // want them for things like impls of traits on that type. // // To be able to work on all platforms and get *some* reasonable output, we diff --git a/src/librustc_trans/save/span_utils.rs b/src/librustc_trans/save/span_utils.rs index 84a7678959d..504663571f5 100644 --- a/src/librustc_trans/save/span_utils.rs +++ b/src/librustc_trans/save/span_utils.rs @@ -230,8 +230,8 @@ impl<'a> SpanUtils<'a> { // Reparse span and return an owned vector of sub spans of the first limit // identifier tokens in the given nesting level. // example with Foo<Bar<T,V>, Bar<T,V>> - // Nesting = 0: all idents outside of brackets: ~[Foo] - // Nesting = 1: idents within one level of brackets: ~[Bar, Bar] + // Nesting = 0: all idents outside of brackets: Vec<Foo> + // Nesting = 1: idents within one level of brackets: Vec<Bar, Bar> pub fn spans_with_brackets(&self, span: Span, nesting: isize, limit: isize) -> Vec<Span> { let mut result: Vec<Span> = vec!(); @@ -352,7 +352,7 @@ impl<'a> SpanUtils<'a> { return vec!(); } // Type params are nested within one level of brackets: - // i.e. we want ~[A, B] from Foo<A, B<T,U>> + // i.e. we want Vec<A, B> from Foo<A, B<T,U>> self.spans_with_brackets(span, 1, number) } diff --git a/src/librustc_trans/trans/attributes.rs b/src/librustc_trans/trans/attributes.rs index b32181426a3..132947e34d7 100644 --- a/src/librustc_trans/trans/attributes.rs +++ b/src/librustc_trans/trans/attributes.rs @@ -196,7 +196,7 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx // The `noalias` attribute on the return value is useful to a // function ptr caller. match ret_ty.sty { - // `~` pointer return values never alias because ownership + // `Box` pointer return values never alias because ownership // is transferred ty::ty_uniq(it) if common::type_is_sized(ccx.tcx(), it) => { attrs.ret(llvm::Attribute::NoAlias); @@ -239,7 +239,7 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx attrs.arg(idx, llvm::Attribute::ZExt); } - // `~` pointer parameters never alias because ownership is transferred + // `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)); diff --git a/src/librustc_trans/trans/debuginfo/metadata.rs b/src/librustc_trans/trans/debuginfo/metadata.rs index 9ff69e7f9dd..bd04bd7a754 100644 --- a/src/librustc_trans/trans/debuginfo/metadata.rs +++ b/src/librustc_trans/trans/debuginfo/metadata.rs @@ -142,26 +142,24 @@ impl<'tcx> TypeMap<'tcx> { fn get_unique_type_id_of_type<'a>(&mut self, cx: &CrateContext<'a, 'tcx>, type_: Ty<'tcx>) -> UniqueTypeId { - // basic type -> {:name of the type:} - // tuple -> {tuple_(:param-uid:)*} - // struct -> {struct_:svh: / :node-id:_<(:param-uid:),*> } - // enum -> {enum_:svh: / :node-id:_<(:param-uid:),*> } - // enum variant -> {variant_:variant-name:_:enum-uid:} - // reference (&) -> {& :pointee-uid:} - // mut reference (&mut) -> {&mut :pointee-uid:} - // ptr (*) -> {* :pointee-uid:} - // mut ptr (*mut) -> {*mut :pointee-uid:} - // unique ptr (~) -> {~ :pointee-uid:} - // @-ptr (@) -> {@ :pointee-uid:} - // sized vec ([T; x]) -> {[:size:] :element-uid:} - // unsized vec ([T]) -> {[] :element-uid:} - // trait (T) -> {trait_:svh: / :node-id:_<(:param-uid:),*> } - // closure -> {<unsafe_> <once_> :store-sigil: |(:param-uid:),* <,_...>| -> \ + // basic type -> {:name of the type:} + // tuple -> {tuple_(:param-uid:)*} + // struct -> {struct_:svh: / :node-id:_<(:param-uid:),*> } + // enum -> {enum_:svh: / :node-id:_<(:param-uid:),*> } + // enum variant -> {variant_:variant-name:_:enum-uid:} + // reference (&) -> {& :pointee-uid:} + // mut reference (&mut) -> {&mut :pointee-uid:} + // ptr (*) -> {* :pointee-uid:} + // mut ptr (*mut) -> {*mut :pointee-uid:} + // unique ptr (box) -> {box :pointee-uid:} + // @-ptr (@) -> {@ :pointee-uid:} + // sized vec ([T; x]) -> {[:size:] :element-uid:} + // unsized vec ([T]) -> {[] :element-uid:} + // trait (T) -> {trait_:svh: / :node-id:_<(:param-uid:),*> } + // closure -> {<unsafe_> <once_> :store-sigil: |(:param-uid:),* <,_...>| -> \ // :return-type-uid: : (:bounds:)*} - // function -> {<unsafe_> <abi_> fn( (:param-uid:)* <,_...> ) -> \ + // function -> {<unsafe_> <abi_> fn( (:param-uid:)* <,_...> ) -> \ // :return-type-uid:} - // unique vec box (~[]) -> {HEAP_VEC_BOX<:pointee-uid:>} - // gc box -> {GC_BOX<:pointee-uid:>} match self.type_to_unique_id.get(&type_).cloned() { Some(unique_type_id) => return unique_type_id, @@ -202,7 +200,7 @@ impl<'tcx> TypeMap<'tcx> { } }, ty::ty_uniq(inner_type) => { - unique_type_id.push('~'); + 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[..]); diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 677254238c0..54ec1aace92 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1603,7 +1603,8 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>, Some(i as usize)), _ => { span_err!(tcx.sess, ast_ty.span, E0249, - "expected constant expr for array length"); + "expected constant integer expression \ + for array length"); this.tcx().types.err } } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index c94fa037026..6171df218bb 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -371,7 +371,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { fn assemble_inherent_impl_candidates_for_type(&mut self, def_id: ast::DefId) { // Read the inherent implementation candidates for this type from the // metadata if necessary. - ty::populate_implementations_for_type_if_necessary(self.tcx(), 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 { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index c05c1c6b085..3769e9fa0f3 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2458,7 +2458,7 @@ fn check_expr_with_lvalue_pref<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, expr: &'tcx ast:: } // determine the `self` type, using fresh variables for all variables -// declared on the impl declaration e.g., `impl<A,B> for ~[(A,B)]` +// declared on the impl declaration e.g., `impl<A,B> for Vec<(A,B)>` // would return ($0, $1) where $0 and $1 are freshly instantiated type // variables. pub fn impl_self_ty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 05b74a5cc22..4dc1596b1ff 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -16,13 +16,10 @@ // mappings. That mapping code resides here. -use metadata::csearch::{each_impl, get_impl_trait}; -use metadata::csearch; use middle::subst::{self, Subst}; use middle::ty::RegionEscape; use middle::ty::{ImplContainer, ImplOrTraitItemId, ConstTraitItemId}; -use middle::ty::{MethodTraitItemId, TypeTraitItemId}; -use middle::ty::{ParameterEnvironment, lookup_item_type}; +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}; @@ -33,7 +30,6 @@ use middle::ty; use CrateCtxt; use middle::infer::InferCtxt; use middle::infer::new_infer_ctxt; -use std::collections::HashSet; use std::cell::RefCell; use std::rc::Rc; use syntax::ast::{Crate, DefId}; @@ -130,11 +126,6 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { Rc::new((*v.borrow()).clone())); } - // Bring in external crates. It's fine for this to happen after the - // coherence checks, because we ensure by construction that no errors - // can happen at link time. - self.add_external_crates(); - // Populate the table of destructors. It might seem a bit strange to // do this here, but it's actually the most convenient place, since // the coherence tables contain the trait -> type mappings. @@ -267,11 +258,6 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { trait_def.record_impl(self.crate_context.tcx, impl_def_id, impl_trait_ref); } - fn get_self_type_for_implementation(&self, impl_did: DefId) - -> TypeScheme<'tcx> { - self.crate_context.tcx.tcache.borrow().get(&impl_did).unwrap().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 { @@ -313,66 +299,6 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { } } - // External crate handling - - fn add_external_impl(&self, - impls_seen: &mut HashSet<DefId>, - impl_def_id: DefId) { - let tcx = self.crate_context.tcx; - let impl_items = csearch::get_impl_items(&tcx.sess.cstore, - impl_def_id); - - // Make sure we don't visit the same implementation multiple times. - if !impls_seen.insert(impl_def_id) { - // Skip this one. - return - } - // Good. Continue. - - let _ = lookup_item_type(tcx, impl_def_id); - let associated_traits = get_impl_trait(tcx, impl_def_id); - - // Do a sanity check. - assert!(associated_traits.is_some()); - - // Record all the trait items. - if let Some(trait_ref) = associated_traits { - self.add_trait_impl(trait_ref, impl_def_id); - } - - // For any methods that use a default implementation, add them to - // the map. This is a bit unfortunate. - for item_def_id in &impl_items { - let impl_item = ty::impl_or_trait_item(tcx, item_def_id.def_id()); - match impl_item { - ty::MethodTraitItem(ref method) => { - if let Some(source) = method.provided_source { - tcx.provided_method_sources - .borrow_mut() - .insert(item_def_id.def_id(), source); - } - } - _ => {} - } - } - - tcx.impl_items.borrow_mut().insert(impl_def_id, impl_items); - } - - // Adds implementations and traits from external crates to the coherence - // info. - fn add_external_crates(&self) { - let mut impls_seen = HashSet::new(); - - let crate_store = &self.crate_context.tcx.sess.cstore; - crate_store.iter_crate_data(|crate_number, _crate_metadata| { - each_impl(crate_store, crate_number, |def_id| { - assert_eq!(crate_number, def_id.krate); - self.add_external_impl(&mut impls_seen, def_id) - }) - }) - } - // // Destructors // @@ -395,7 +321,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { } let method_def_id = items[0]; - let self_type = self.get_self_type_for_implementation(impl_did); + 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, _) | @@ -451,7 +377,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { return } - let self_type = self.get_self_type_for_implementation(impl_did); + let self_type = ty::lookup_item_type(tcx, impl_did); debug!("check_implementations_of_copy: self_type={} (bound)", self_type.repr(tcx)); diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs index 46cce543011..e9c69c84630 100644 --- a/src/librustc_typeck/coherence/overlap.rs +++ b/src/librustc_typeck/coherence/overlap.rs @@ -48,14 +48,9 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> { // check_for_overlapping_impls_of_trait() check, since that // check can populate this table further with impls from other // crates. - let trait_defs : Vec<&ty::TraitDef> = { - let d = self.tcx.trait_defs.borrow(); - d.values().map(|&v|v).collect() - }; + let trait_defs: Vec<_> = self.tcx.trait_defs.borrow().values().cloned().collect(); for trait_def in trait_defs { - // FIXME -- it seems like this method actually pushes - // duplicate impls onto the list ty::populate_implementations_for_trait_if_necessary( self.tcx, trait_def.trait_ref.def_id); diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 0e6386618f1..f9565d528e8 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -46,6 +46,23 @@ enum variant, one of the fields was not provided. Each field should be specified exactly once. "##, +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. + +``` +use std::collections::LinkedList; + +// Good +let mut list = LinkedList::new(); + + +// Bad: assignment to non-lvalue expression +LinkedList::new() += 1; +``` +"##, + 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, @@ -119,6 +136,162 @@ construct an instance of the following type using only safe code: ``` enum Empty {} ``` +"##, + +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 `()`. +"##, + +E0132: r##" +It is not possible to declare type parameters on a function that has the `start` +attribute. Such a function must have the following type signature: + +``` +fn(isize, *const *const u8) -> isize +``` +"##, + +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 +incorrect and can lead to memory unsafety (see [issue #20126][iss20126]), so +it has been disabled for now. + +[iss20126]: https://github.com/rust-lang/rust/issues/20126 +"##, + +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 +mentioned field. Note that this may not be possible, as in the example of + +``` +struct Foo { + foo : Vec<u32>, +} + +impl Copy for Foo { } +``` + +This fails because `Vec<T>` does not implement `Copy` for any `T`. + +Here's another example that will fail: + +``` +#[derive(Copy)] +struct Foo<'a> { + ty: &'a mut bool, +} +``` + +This fails because `&mut T` is not `Copy`, even when `T` is `Copy` (this +differs from the behavior for `&T`, which is always `Copy`). +"##, + +E0205: r##" +An attempt to implement the `Copy` trait for an enum failed because one of the +variants does not implement `Copy`. To fix this, you must implement `Copy` for +the mentioned variant. Note that this may not be possible, as in the example of + +``` +enum Foo { + Bar(Vec<u32>), + Baz, +} + +impl Copy for Foo { } +``` + +This fails because `Vec<T>` does not implement `Copy` for any `T`. + +Here's another example that will fail: + +``` +#[derive(Copy)] +enum Foo<'a> { + Bar(&'a mut bool), + Baz +} +``` + +This fails because `&mut T` is not `Copy`, even when `T` is `Copy` (this +differs from the behavior for `&T`, which is always `Copy`). +"##, + +E0206: r##" +You can only implement `Copy` for a struct or enum. Both of the following +examples will fail, because neither `i32` (primitive type) nor `&'static Bar` +(reference to `Bar`) is a struct or enum: + +``` +type Foo = i32; +impl Copy for Foo { } // error + +#[derive(Copy, Clone)] +struct Bar; +impl Copy for &'static Bar { } // error +``` +"##, + +E0243: r##" +This error indicates that not enough type parameters were found in a type or +trait. + +For example, the `Foo` struct below is defined to be generic in `T`, but the +type parameter is missing in the definition of `Bar`: + +``` +struct Foo<T> { x: T } + +struct Bar { x: Foo } +``` +"##, + +E0244: r##" +This error indicates that too many type parameters were found in a type or +trait. + +For example, the `Foo` struct below has no type parameters, but is supplied +with two in the definition of `Bar`: + +``` +struct Foo { x: bool } + +struct Bar<S, T> { x: Foo<S, T> } +``` +"##, + +E0249: r##" +This error indicates a constant expression for the array length was found, but +it was not an integer (signed or unsigned) expression. + +Some examples of code that produces this error are: + +``` +const A: [u32; "hello"] = []; // error +const B: [u32; true] = []; // error +const C: [u32; 0.0] = []; // error +"##, + +E0250: r##" +This means 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: + +``` +// divide by zero in the length expression +const A: [u32; 1/0] = []; + +// Rust currently will not evaluate the function `foo` at compile time +fn foo() -> usize { 12 } +const B: [u32; foo()] = []; + +// it is an error to try to add `u8` and `f64` +use std::{f64, u8}; +const C: [u32; u8::MAX + f64::EPSILON] = []; +``` "## } @@ -133,23 +306,22 @@ register_diagnostics! { E0030, E0031, E0033, - E0034, - E0035, - E0036, - E0038, + E0034, // multiple applicable methods in scope + E0035, // does not take type parameters + E0036, // incorrect number of type parameters given for this method + E0038, // cannot convert to a trait object because trait is not object-safe E0040, // explicit use of destructor method - E0044, - E0045, + E0044, // foreign items may not have type parameters + E0045, // variadic function must have C calling convention E0049, E0050, E0053, - E0055, - E0057, + E0055, // method has an incompatible type for trait + E0057, // method has an incompatible type for trait E0059, E0060, E0061, E0066, - E0067, E0068, E0069, E0070, @@ -189,8 +361,6 @@ register_diagnostics! { E0128, E0129, E0130, - E0131, - E0132, E0141, E0159, E0163, @@ -204,7 +374,6 @@ register_diagnostics! { E0178, E0182, E0183, - E0184, E0185, E0186, E0187, // can't infer the kind of the closure @@ -226,12 +395,6 @@ register_diagnostics! { E0202, // associated items are not allowed in inherent impls E0203, // type parameter has more than one relaxed default bound, // and only one is supported - E0204, // trait `Copy` may not be implemented for this type; field - // does not implement `Copy` - E0205, // trait `Copy` may not be implemented for this type; variant - // does not implement `copy` - E0206, // trait `Copy` may not be implemented for this type; type is - // not a structure or enumeration E0207, // type parameter is not constrained by the impl trait, self type, or predicate E0208, E0209, // builtin traits can only be implemented on structs or enums @@ -268,14 +431,10 @@ register_diagnostics! { E0240, E0241, E0242, // internal error looking up a definition - E0243, // wrong number of type arguments - E0244, // wrong number of type arguments E0245, // not a trait E0246, // illegal recursive type E0247, // found module name used as a type E0248, // found value name used as a type - E0249, // expected constant expr for array length - E0250, // expected constant expr for array length 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 diff --git a/src/librustc_typeck/variance.rs b/src/librustc_typeck/variance.rs index 9e8c23734e3..7c062d354d3 100644 --- a/src/librustc_typeck/variance.rs +++ b/src/librustc_typeck/variance.rs @@ -178,8 +178,8 @@ //! further that for whatever reason I specifically supply the value of //! `String` for the type parameter `T`: //! -//! let mut vector = ~["string", ...]; -//! convertAll::<int, String>(v); +//! let mut vector = vec!["string", ...]; +//! convertAll::<int, String>(vector); //! //! Is this legal? To put another way, can we apply the `impl` for //! `Object` to the type `String`? The answer is yes, but to see why diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 0d59577a6d8..3ce8835b1a8 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -221,7 +221,7 @@ fn build_type(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId) -> clean::ItemEn pub fn build_impls(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId) -> Vec<clean::Item> { - ty::populate_implementations_for_type_if_necessary(tcx, did); + ty::populate_inherent_implementations_for_type_if_necessary(tcx, did); let mut impls = Vec::new(); match tcx.inherent_impls.borrow().get(&did) { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 444e5dea89a..4c2357f8a8f 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -897,7 +897,7 @@ impl<'tcx> Clean<Type> for ty::ProjectionTy<'tcx> { } } -// maybe use a Generic enum and use ~[Generic]? +// maybe use a Generic enum and use Vec<Generic>? #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)] pub struct Generics { pub lifetimes: Vec<Lifetime>, diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 08792044c2a..36cf650d54e 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -905,6 +905,8 @@ impl DocFolder for Cache { // Index this method for searching later on if let Some(ref s) = item.name { let (parent, is_method) = match item.inner { + clean::AssociatedTypeItem(..) | + clean::AssociatedConstItem(..) | clean::TyMethodItem(..) | clean::StructFieldItem(..) | clean::VariantItem(..) => { @@ -1862,6 +1864,17 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, try!(write!(w, "</div>")); } + if !consts.is_empty() { + try!(write!(w, " + <h2 id='associated-const'>Associated Constants</h2> + <div class='methods'> + ")); + for t in &consts { + try!(trait_item(w, *t)); + } + try!(write!(w, "</div>")); + } + // Output the documentation for each function individually if !required.is_empty() { try!(write!(w, " diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 6a1d7bdfd83..932a536ab18 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -34,7 +34,8 @@ "macro", "primitive", "associatedtype", - "constant"]; + "constant", + "associatedconstant"]; $('.js-only').removeClass('js-only'); diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 9b824f11b92..48f65a5abfd 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -916,6 +916,24 @@ impl<K, V, S> HashMap<K, V, S> } /// Gets the given key's corresponding entry in the map for in-place manipulation. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut letters = HashMap::new(); + /// + /// for ch in "a short treatise on fungi".chars() { + /// let counter = letters.entry(ch).or_insert(0); + /// *counter += 1; + /// } + /// + /// assert_eq!(letters[&'s'], 2); + /// assert_eq!(letters[&'t'], 3); + /// assert_eq!(letters[&'u'], 1); + /// assert_eq!(letters.get(&'y'), None); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn entry(&mut self, key: K) -> Entry<K, V> { // Gotta resize now. diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 9089b417fcb..e7b2b01d09f 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -844,7 +844,7 @@ impl fmt::Display for CharsError { /// An iterator over the contents of an instance of `BufRead` split on a /// particular byte. /// -/// See `BufReadExt::split` for more information. +/// See `BufRead::split` for more information. #[stable(feature = "rust1", since = "1.0.0")] pub struct Split<B> { buf: B, @@ -873,7 +873,7 @@ impl<B: BufRead> Iterator for Split<B> { /// An iterator over the lines of an instance of `BufRead` split on a newline /// byte. /// -/// See `BufReadExt::lines` for more information. +/// See `BufRead::lines` for more information. #[stable(feature = "rust1", since = "1.0.0")] pub struct Lines<B> { buf: B, diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 8ccc387c902..934b3156357 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1199,7 +1199,7 @@ impl Into<OsString> for PathBuf { /// absolute, and so on. More details about the overall approach can be found in /// the module documentation. /// -/// This is an *unsized* type, meaning that it must always be used with behind a +/// This is an *unsized* type, meaning that it must always be used behind a /// pointer like `&` or `Box`. /// /// # Examples @@ -1449,6 +1449,8 @@ impl Path { /// Determines whether `base` is a prefix of `self`. /// + /// Only considers whole path components to match. + /// /// # Examples /// /// ``` @@ -1457,6 +1459,8 @@ impl Path { /// let path = Path::new("/etc/passwd"); /// /// assert!(path.starts_with("/etc")); + /// + /// assert!(!path.starts_with("/e")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn starts_with<P: AsRef<Path>>(&self, base: P) -> bool { @@ -1465,6 +1469,8 @@ impl Path { /// Determines whether `child` is a suffix of `self`. /// + /// Only considers whole path components to match. + /// /// # Examples /// /// ``` diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs index 41bdf034705..2e043c58a5d 100644 --- a/src/libstd/thread/local.rs +++ b/src/libstd/thread/local.rs @@ -85,6 +85,8 @@ pub struct LocalKey<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] diff --git a/src/libstd/thread/scoped_tls.rs b/src/libstd/thread/scoped_tls.rs index 35684a1f390..e195c3aaa3f 100644 --- a/src/libstd/thread/scoped_tls.rs +++ b/src/libstd/thread/scoped_tls.rs @@ -66,6 +66,8 @@ pub struct ScopedKey<T> { #[doc(hidden)] pub inner: __impl::KeyInner<T> } /// /// This macro declares a `static` item on which methods are used to get and /// set the value stored within. +/// +/// See [ScopedKey documentation](thread/struct.ScopedKey.html) for more information. #[macro_export] #[allow_internal_unstable] macro_rules! scoped_thread_local { diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs index b1ab0438a01..1525f1a822b 100644 --- a/src/libsyntax/ext/deriving/generic/mod.rs +++ b/src/libsyntax/ext/deriving/generic/mod.rs @@ -904,8 +904,8 @@ impl<'a> MethodDef<'a> { nonself_args: &[P<Expr>]) -> P<Expr> { - let mut raw_fields = Vec::new(); // ~[[fields of self], - // [fields of next Self arg], [etc]] + let mut raw_fields = Vec::new(); // Vec<[fields of self], + // [fields of next Self arg], [etc]> let mut patterns = Vec::new(); for i in 0..self_args.len() { let struct_path= cx.path(DUMMY_SP, vec!( type_ident )); diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 476ab0fbf11..d71557bd737 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -1719,7 +1719,7 @@ mod tests { // induced by visit. Each of these arrays contains a list of indexes, // interpreted as the varrefs in the varref traversal that this binding // should match. So, for instance, in a program with two bindings and - // three varrefs, the array ~[~[1,2],~[0]] would indicate that the first + // three varrefs, the array [[1, 2], [0]] would indicate that the first // binding should match the second two varrefs, and the second binding // should match the first varref. // diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index eb1c338ac85..541ec16b415 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -109,15 +109,6 @@ pub enum PathParsingMode { LifetimeAndTypesWithColons, } -/// How to parse a qualified path, whether to allow trailing parameters. -#[derive(Copy, Clone, PartialEq)] -pub enum QPathParsingMode { - /// No trailing parameters, e.g. `<T as Trait>::Item` - NoParameters, - /// Optional parameters, e.g. `<T as Trait>::item::<'a, U>` - MaybeParameters, -} - /// How to parse a bound, whether to allow bound modifiers such as `?`. #[derive(Copy, Clone, PartialEq)] pub enum BoundParsingMode { @@ -1359,7 +1350,7 @@ impl<'a> Parser<'a> { } else if try!(self.eat_lt()) { let (qself, path) = - try!(self.parse_qualified_path(QPathParsingMode::NoParameters)); + try!(self.parse_qualified_path(NoTypesAllowed)); TyPath(Some(qself), path) } else if self.check(&token::ModSep) || @@ -1578,7 +1569,7 @@ impl<'a> Parser<'a> { // QUALIFIED PATH `<TYPE [as TRAIT_REF]>::IDENT[::<PARAMS>]` // Assumes that the leading `<` has been parsed already. - pub fn parse_qualified_path(&mut self, mode: QPathParsingMode) + pub fn parse_qualified_path(&mut self, mode: PathParsingMode) -> PResult<(QSelf, ast::Path)> { let self_type = try!(self.parse_ty_sum()); let mut path = if try!(self.eat_keyword(keywords::As)) { @@ -1599,29 +1590,18 @@ impl<'a> Parser<'a> { try!(self.expect(&token::Gt)); try!(self.expect(&token::ModSep)); - let item_name = try!(self.parse_ident()); - let parameters = match mode { - QPathParsingMode::NoParameters => ast::PathParameters::none(), - QPathParsingMode::MaybeParameters => { - if try!(self.eat(&token::ModSep)) { - try!(self.expect_lt()); - // Consumed `item::<`, go look for types - let (lifetimes, types, bindings) = - try!(self.parse_generic_values_after_lt()); - ast::AngleBracketedParameters(ast::AngleBracketedParameterData { - lifetimes: lifetimes, - types: OwnedSlice::from_vec(types), - bindings: OwnedSlice::from_vec(bindings), - }) - } else { - ast::PathParameters::none() - } + let segments = match mode { + LifetimeAndTypesWithoutColons => { + try!(self.parse_path_segments_without_colons()) + } + LifetimeAndTypesWithColons => { + try!(self.parse_path_segments_with_colons()) + } + NoTypesAllowed => { + try!(self.parse_path_segments_without_types()) } }; - path.segments.push(ast::PathSegment { - identifier: item_name, - parameters: parameters - }); + path.segments.extend(segments); if path.segments.len() == 1 { path.span.lo = self.last_span.lo; @@ -2096,7 +2076,7 @@ impl<'a> Parser<'a> { if try!(self.eat_lt()){ let (qself, path) = - try!(self.parse_qualified_path(QPathParsingMode::MaybeParameters)); + try!(self.parse_qualified_path(LifetimeAndTypesWithColons)); return Ok(self.mk_expr(lo, hi, ExprPath(Some(qself), path))); } @@ -3176,7 +3156,7 @@ impl<'a> Parser<'a> { let (qself, path) = if try!(self.eat_lt()) { // Parse a qualified path let (qself, path) = - try!(self.parse_qualified_path(QPathParsingMode::NoParameters)); + try!(self.parse_qualified_path(NoTypesAllowed)); (Some(qself), path) } else { // Parse an unqualified path @@ -3270,7 +3250,7 @@ impl<'a> Parser<'a> { let (qself, path) = if try!(self.eat_lt()) { // Parse a qualified path let (qself, path) = - try!(self.parse_qualified_path(QPathParsingMode::NoParameters)); + try!(self.parse_qualified_path(NoTypesAllowed)); (Some(qself), path) } else { // Parse an unqualified path diff --git a/src/libsyntax/print/pp.rs b/src/libsyntax/print/pp.rs index 15aaf9cf390..ed9937c53f4 100644 --- a/src/libsyntax/print/pp.rs +++ b/src/libsyntax/print/pp.rs @@ -312,7 +312,7 @@ impl<'a> Printer<'a> { self.token[self.right] = t; } pub fn pretty_print(&mut self, token: Token) -> io::Result<()> { - debug!("pp ~[{},{}]", self.left, self.right); + debug!("pp Vec<{},{}>", self.left, self.right); match token { Token::Eof => { if !self.scan_stack_empty { @@ -329,7 +329,7 @@ impl<'a> Printer<'a> { self.left = 0; self.right = 0; } else { self.advance_right(); } - debug!("pp Begin({})/buffer ~[{},{}]", + debug!("pp Begin({})/buffer Vec<{},{}>", b.offset, self.left, self.right); self.token[self.right] = token; self.size[self.right] = -self.right_total; @@ -339,10 +339,10 @@ impl<'a> Printer<'a> { } Token::End => { if self.scan_stack_empty { - debug!("pp End/print ~[{},{}]", self.left, self.right); + debug!("pp End/print Vec<{},{}>", self.left, self.right); self.print(token, 0) } else { - debug!("pp End/buffer ~[{},{}]", self.left, self.right); + debug!("pp End/buffer Vec<{},{}>", self.left, self.right); self.advance_right(); self.token[self.right] = token; self.size[self.right] = -1; @@ -358,7 +358,7 @@ impl<'a> Printer<'a> { self.left = 0; self.right = 0; } else { self.advance_right(); } - debug!("pp Break({})/buffer ~[{},{}]", + debug!("pp Break({})/buffer Vec<{},{}>", b.offset, self.left, self.right); self.check_stack(0); let right = self.right; @@ -370,11 +370,11 @@ impl<'a> Printer<'a> { } Token::String(s, len) => { if self.scan_stack_empty { - debug!("pp String('{}')/print ~[{},{}]", + debug!("pp String('{}')/print Vec<{},{}>", s, self.left, self.right); self.print(Token::String(s, len), len) } else { - debug!("pp String('{}')/buffer ~[{},{}]", + debug!("pp String('{}')/buffer Vec<{},{}>", s, self.left, self.right); self.advance_right(); self.token[self.right] = Token::String(s, len); @@ -386,7 +386,7 @@ impl<'a> Printer<'a> { } } pub fn check_stream(&mut self) -> io::Result<()> { - debug!("check_stream ~[{}, {}] with left_total={}, right_total={}", + debug!("check_stream Vec<{}, {}> with left_total={}, right_total={}", self.left, self.right, self.left_total, self.right_total); if self.right_total - self.left_total > self.space { debug!("scan window is {}, longer than space on line ({})", @@ -446,7 +446,7 @@ impl<'a> Printer<'a> { assert!((self.right != self.left)); } pub fn advance_left(&mut self) -> io::Result<()> { - debug!("advance_left ~[{},{}], sizeof({})={}", self.left, self.right, + debug!("advance_left Vec<{},{}>, sizeof({})={}", self.left, self.right, self.left, self.size[self.left]); let mut left_size = self.size[self.left]; diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 4d0b746c60c..00ef8760985 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -259,8 +259,8 @@ pub fn test_main(args: &[String], tests: Vec<TestDescAndFn> ) { // This will panic (intentionally) when fed any dynamic tests, because // it is copying the static values out into a dynamic vector and cannot // copy dynamic values. It is doing this because from this point on -// a ~[TestDescAndFn] is used in order to effect ownership-transfer -// semantics into parallel test runners, which in turn requires a ~[] +// a Vec<TestDescAndFn> is used in order to effect ownership-transfer +// semantics into parallel test runners, which in turn requires a Vec<> // rather than a &[]. pub fn test_main_static(args: env::Args, tests: &[TestDescAndFn]) { let args = args.collect::<Vec<_>>(); diff --git a/src/test/compile-fail/double-import.rs b/src/test/compile-fail/double-import.rs new file mode 100644 index 00000000000..cbf13c0a559 --- /dev/null +++ b/src/test/compile-fail/double-import.rs @@ -0,0 +1,27 @@ +// 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(no_std)] +#![no_std] + +// This tests that conflicting imports shows both `use` lines +// when reporting the error. + +mod sub1 { + fn foo() {} // implementation 1 +} + +mod sub2 { + fn foo() {} // implementation 2 +} + +use sub1::foo; //~ NOTE previous import of `foo` here +use sub2::foo; //~ ERROR a value named `foo` has already been imported in this module [E0252] + +fn main() {} diff --git a/src/test/compile-fail/issue-20413.rs b/src/test/compile-fail/issue-20413.rs new file mode 100644 index 00000000000..a48c03aa178 --- /dev/null +++ b/src/test/compile-fail/issue-20413.rs @@ -0,0 +1,25 @@ +// 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 { + fn answer(self); +} + +struct NoData<T>; +//~^ ERROR: parameter `T` is never used + +impl<T> Foo for T where NoData<T>: Foo { +//~^ ERROR: overflow evaluating the requirement + fn answer(self) { + let val: NoData<T> = NoData; + } +} + +fn main() {} diff --git a/src/test/compile-fail/kindck-copy.rs b/src/test/compile-fail/kindck-copy.rs index d43ddff6b95..95ab2bbab14 100644 --- a/src/test/compile-fail/kindck-copy.rs +++ b/src/test/compile-fail/kindck-copy.rs @@ -37,7 +37,7 @@ fn test<'a,T,U:Copy>(_: &'a isize) { assert_copy::<&'static mut isize>(); //~ ERROR `core::marker::Copy` is not implemented assert_copy::<&'a mut isize>(); //~ ERROR `core::marker::Copy` is not implemented - // ~ pointers are not ok + // owned pointers 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 diff --git a/src/test/debuginfo/issue11600.rs b/src/test/debuginfo/issue11600.rs index e93704cac34..dea2a0c5a23 100644 --- a/src/test/debuginfo/issue11600.rs +++ b/src/test/debuginfo/issue11600.rs @@ -13,7 +13,7 @@ // ignore-test fn main() { - let args : ~[String] = ::std::os::args(); + let args : Vec<String> = ::std::os::args(); ::std::io::println(args[0]); } @@ -25,6 +25,6 @@ fn main() { // compile-flags:-g // gdb-command:list // gdb-check:1[...]fn main() { -// gdb-check:2[...]let args : ~[String] = ::std::os::args(); +// gdb-check:2[...]let args : Vec<String> = ::std::os::args(); // gdb-check:3[...]::std::io::println(args[0]); // gdb-check:4[...]} diff --git a/src/test/run-pass/associated-item-long-paths.rs b/src/test/run-pass/associated-item-long-paths.rs new file mode 100644 index 00000000000..4ad0187df7a --- /dev/null +++ b/src/test/run-pass/associated-item-long-paths.rs @@ -0,0 +1,55 @@ +// 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::size_of; + +// The main point of this test is to ensure that we can parse and resolve +// associated items on associated types. + +trait Foo { + type U; +} + +trait Bar { + // Note 1: Chains of associated items in a path won't type-check. + // Note 2: Associated consts can't depend on type parameters or `Self`, + // which are the only types that an associated type can be referenced on for + // now, so we can only test methods. + fn method() -> u32; + fn generic_method<T>() -> usize; +} + +struct MyFoo; +struct MyBar; + +impl Foo for MyFoo { + type U = MyBar; +} + +impl Bar for MyBar { + fn method() -> u32 { + 2u32 + } + fn generic_method<T>() -> usize { + size_of::<T>() + } +} + +fn foo<T>() + where T: Foo, + T::U: Bar, +{ + assert_eq!(2u32, <T as Foo>::U::method()); + assert_eq!(8usize, <T as Foo>::U::generic_method::<f64>()); +} + +fn main() { + foo::<MyFoo>(); +} diff --git a/src/test/run-pass/const-bound.rs b/src/test/run-pass/const-bound.rs index 5c2985ffa77..72a23b998e5 100644 --- a/src/test/run-pass/const-bound.rs +++ b/src/test/run-pass/const-bound.rs @@ -20,7 +20,7 @@ struct F { field: isize } pub fn main() { /*foo(1); foo("hi".to_string()); - foo(~[1, 2, 3]); + foo(vec![1, 2, 3]); foo(F{field: 42}); foo((1, 2)); foo(@1);*/ diff --git a/src/test/run-pass/issue-18075.rs b/src/test/run-pass/issue-18075.rs new file mode 100644 index 00000000000..5f07ba2235f --- /dev/null +++ b/src/test/run-pass/issue-18075.rs @@ -0,0 +1,16 @@ +// 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. + +// exec-env:RUST_LOG=rustc::middle=debug + +fn main() { + let b = 1isize; + println!("{}", b); +} diff --git a/src/test/run-pass/issue-23336.rs b/src/test/run-pass/issue-23336.rs new file mode 100644 index 00000000000..21e51298444 --- /dev/null +++ b/src/test/run-pass/issue-23336.rs @@ -0,0 +1,20 @@ +// 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 Data { fn doit(&self) {} } +impl<T> Data for T {} +pub trait UnaryLogic { type D: Data; } +impl UnaryLogic for () { type D = i32; } + +pub fn crashes<T: UnaryLogic>(t: T::D) { + t.doit(); +} + +fn main() { crashes::<()>(0); } diff --git a/src/test/run-pass/issue-3556.rs b/src/test/run-pass/issue-3556.rs index 0efa85e232b..e6b577ada0c 100644 --- a/src/test/run-pass/issue-3556.rs +++ b/src/test/run-pass/issue-3556.rs @@ -32,10 +32,6 @@ fn check_strs(actual: &str, expected: &str) -> bool pub fn main() { -// assert!(check_strs(fmt!("%?", Text(@"foo".to_string())), "Text(@~\"foo\")")); -// assert!(check_strs(fmt!("%?", ETag(@~["foo".to_string()], @"bar".to_string())), -// "ETag(@~[ ~\"foo\" ], @~\"bar\")")); - let t = Token::Text("foo".to_string()); let u = Token::Section(vec!["alpha".to_string()], true, diff --git a/src/test/run-pass/issue-4241.rs b/src/test/run-pass/issue-4241.rs index c9b684fd656..ab75c2064a4 100644 --- a/src/test/run-pass/issue-4241.rs +++ b/src/test/run-pass/issue-4241.rs @@ -22,8 +22,8 @@ use std::io::{ReaderUtil,WriterUtil}; enum Result { Nil, Int(isize), - Data(~[u8]), - List(~[Result]), + Data(Vec<u8>), + List(Vec<Result>), Error(String), Status(String) } @@ -35,7 +35,7 @@ fn parse_data(len: usize, io: @io::Reader) -> Result { assert_eq!(bytes.len(), len); Data(bytes) } else { - Data(~[]) + Data(vec![]) }; assert_eq!(io.read_char(), '\r'); assert_eq!(io.read_char(), '\n'); @@ -43,7 +43,7 @@ fn parse_data(len: usize, io: @io::Reader) -> Result { } fn parse_list(len: usize, io: @io::Reader) -> Result { - let mut list: ~[Result] = ~[]; + let mut list: Vec<Result> = vec![]; for _ in 0..len { let v = match io.read_char() { '$' => parse_bulk(io), @@ -72,7 +72,7 @@ fn parse_multi(io: @io::Reader) -> Result { match from_str::<isize>(chop(io.read_line())) { None => panic!(), Some(-1) => Nil, - Some(0) => List(~[]), + Some(0) => List(vec![]), Some(len) if len >= 0 => parse_list(len as usize, io), Some(_) => panic!() } @@ -96,7 +96,7 @@ fn parse_response(io: @io::Reader) -> Result { } } -fn cmd_to_string(cmd: ~[String]) -> String { +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"); @@ -107,7 +107,7 @@ fn cmd_to_string(cmd: ~[String]) -> String { res } -fn query(cmd: ~[String], sb: TcpSocketBuf) -> Result { +fn query(cmd: Vec<String>, sb: TcpSocketBuf) -> Result { let cmd = cmd_to_string(cmd); //println!("{}", cmd); sb.write_str(cmd); @@ -115,7 +115,7 @@ fn query(cmd: ~[String], sb: TcpSocketBuf) -> Result { res } -fn query2(cmd: ~[String]) -> Result { +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); diff --git a/src/test/run-pass/slice-of-zero-size-elements.rs b/src/test/run-pass/slice-of-zero-size-elements.rs new file mode 100644 index 00000000000..6fe510586c7 --- /dev/null +++ b/src/test/run-pass/slice-of-zero-size-elements.rs @@ -0,0 +1,60 @@ +// 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)] + +use std::slice; + +fn foo<T>(v: &[T]) -> Option<&[T]> { + let mut it = v.iter(); + for _ in 0..5 { + let _ = it.next(); + } + Some(it.as_slice()) +} + +fn foo_mut<T>(v: &mut [T]) -> Option<&mut [T]> { + let mut it = v.iter_mut(); + for _ in 0..5 { + let _ = it.next(); + } + Some(it.into_slice()) +} + +pub fn main() { + // In a slice of zero-size elements the pointer is meaningless. + // Ensure iteration still works even if the pointer is at the end of the address space. + let slice: &[()] = unsafe { slice::from_raw_parts(-5isize as *const (), 10) }; + assert_eq!(slice.len(), 10); + assert_eq!(slice.iter().count(), 10); + + // .nth() on the iterator should also behave correctly + let mut it = slice.iter(); + assert!(it.nth(5).is_some()); + assert_eq!(it.count(), 4); + + // Converting Iter to a slice should never have a null pointer + assert!(foo(slice).is_some()); + + // Test mutable iterators as well + let slice: &mut [()] = unsafe { slice::from_raw_parts_mut(-5isize as *mut (), 10) }; + assert_eq!(slice.len(), 10); + assert_eq!(slice.iter_mut().count(), 10); + + { + let mut it = slice.iter_mut(); + assert!(it.nth(5).is_some()); + assert_eq!(it.count(), 4); + } + + assert!(foo_mut(slice).is_some()) +} diff --git a/src/test/rustdoc/assoc-consts.rs b/src/test/rustdoc/assoc-consts.rs index cd8d7ec16dc..20d4c744414 100644 --- a/src/test/rustdoc/assoc-consts.rs +++ b/src/test/rustdoc/assoc-consts.rs @@ -13,6 +13,7 @@ pub trait Foo { // @has assoc_consts/trait.Foo.html '//*[@class="rust trait"]' \ // 'const FOO: usize;' + // @has - '//*[@id="associatedconstant.FOO"]' 'const FOO' const FOO: usize; } |
