<commit_before>/*

typeck.rs, an introduction

The type checker is responsible for:

1. Determining the type of each expression
2. Resolving methods and ifaces
3. Guaranteeing that most type rules are met ("most?", you say, "why most?"
   Well, dear reader, read on)

The main entry point is `check_crate()`.  Type checking operates in two major
phases: collect and check.  The collect phase passes over all items and
determines their type, without examining their "innards".  The check phase
then checks function bodies and so forth.

Within the check phase, we check each function body one at a time (bodies of
function expressions are checked as part of the containing function).
Inference is used to supply types wherever they are unknown. The actual
checking of a function itself has several phases (check, regionck, writeback),
as discussed in the documentation for the `check` module.

The type checker is defined into various submodules which are documented
independently:

- astconv: converts the AST representation of types
  into the `ty` representation

- collect: computes the types of each top-level item and enters them into
  the `cx.tcache` table for later use

- check: walks over function bodies and type checks them, inferring types for
  local variables, type parameters, etc as necessary.

- infer: finds the types to use for each type variable such that
  all subtyping and assignment constraints are met.  In essence, the check
  module specifies the constraints, and the infer module solves them.

*/

import result::{result, extensions};
import syntax::{ast, ast_util, ast_map};
import ast::spanned;
import syntax::ast_map::node_id_to_str;
import syntax::ast_util::{local_def, respan, split_class_items};
import syntax::visit;
import metadata::csearch;
import driver::session::session;
import util::common::may_break;
import syntax::codemap::span;
import pat_util::{pat_is_variant, pat_id_map};
import middle::ty;
import middle::ty::{arg, field, node_type_table, mk_nil,
                    ty_param_bounds_and_ty, lookup_public_fields};
import middle::typeck::infer::methods;
import util::ppaux::{ty_to_str, tys_to_str, region_to_str,
                     bound_region_to_str, vstore_to_str};
import std::smallintmap;
import std::smallintmap::map;
import std::map;
import std::map::{hashmap, int_hash};
import std::serialization::{serialize_uint, deserialize_uint};
import vec::each;
import syntax::print::pprust::*;
import util::common::{indent, indenter};
import std::list;
import list::{list, nil, cons};

export check_crate;
export infer;
export method_map;
export method_origin, serialize_method_origin, deserialize_method_origin;
export method_map_entry, serialize_method_map_entry;
export deserialize_method_map_entry;
export vtable_map;
export vtable_res;
export vtable_origin;

#[auto_serialize]
enum method_origin {
    // fully statically resolved method
    method_static(ast::def_id),

    // method invoked on a type parameter with a bounded iface
    method_param(method_param),

    // method invoked on a boxed iface
    method_iface(ast::def_id, uint),
}

// details for a method invoked with a receiver whose type is a type parameter
// with a bounded iface.
#[auto_serialize]
type method_param = {
    // the iface containing the method to be invoked
    iface_id: ast::def_id,

    // index of the method to be invoked amongst the iface's methods
    method_num: uint,

    // index of the type parameter (from those that are in scope) that is
    // the type of the receiver
    param_num: uint,

    // index of the bound for this type parameter which specifies the iface
    bound_num: uint
};

#[auto_serialize]
type method_map_entry = {
    // number of derefs that are required on the receiver
    derefs: uint,

    // method details being invoked
    origin: method_origin
};

// maps from an expression id that corresponds to a method call to the details
// of the method to be invoked
type method_map = hashmap<ast::node_id, method_map_entry>;

// Resolutions for bounds of all parameters, left to right, for a given path.
type vtable_res = @[vtable_origin];

enum vtable_origin {
    /*
      Statically known vtable. def_id gives the class or impl item
      from whence comes the vtable, and tys are the type substs.
      vtable_res is the vtable itself
     */
    vtable_static(ast::def_id, [ty::t], vtable_res),
    /*
      Dynamic vtable, comes from a parameter that has a bound on it:
      fn foo<T: quux, baz, bar>(a: T) -- a's vtable would have a
      vtable_param origin

      The first uint is the param number (identifying T in the example),
      and the second is the bound number (identifying baz)
     */
    vtable_param(uint, uint),
    /*
      Dynamic vtable, comes from something known to have an interface
      type. def_id refers to the iface item, tys are the substs
     */
    vtable_iface(ast::def_id, [ty::t]),
}

type vtable_map = hashmap<ast::node_id, vtable_res>;

type ty_param_substs_and_ty = {substs: ty::substs, ty: ty::t};

type ty_table = hashmap<ast::def_id, ty::t>;

type crate_ctxt = {impl_map: resolve::impl_map,
                   method_map: method_map,
                   vtable_map: vtable_map,
                   tcx: ty::ctxt};

// Functions that write types into the node type table
fn write_ty_to_tcx(tcx: ty::ctxt, node_id: ast::node_id, ty: ty::t) {
    #debug["write_ty_to_tcx(%d, %s)", node_id, ty_to_str(tcx, ty)];
    smallintmap::insert(*tcx.node_types, node_id as uint, ty);
}
fn write_substs_to_tcx(tcx: ty::ctxt,
                       node_id: ast::node_id,
                       +substs: [ty::t]) {
    if substs.len() > 0u {
        tcx.node_type_substs.insert(node_id, substs);
    }
}

fn lookup_def_tcx(tcx: ty::ctxt, sp: span, id: ast::node_id) -> ast::def {
    alt tcx.def_map.find(id) {
      some(x) { x }
      _ {
        tcx.sess.span_fatal(sp, "internal error looking up a definition")
      }
    }
}

fn lookup_def_ccx(ccx: @crate_ctxt, sp: span, id: ast::node_id) -> ast::def {
    lookup_def_tcx(ccx.tcx, sp, id)
}

fn no_params(t: ty::t) -> ty::ty_param_bounds_and_ty {
    {bounds: @[], rp: ast::rp_none, ty: t}
}

fn require_same_types(
    tcx: ty::ctxt,
    maybe_infcx: option<infer::infer_ctxt>,
    span: span,
    t1: ty::t,
    t2: ty::t,
    msg: fn() -> str) -> bool {

    let l_tcx, l_infcx;
    alt maybe_infcx {
      none {
        l_tcx = tcx;
        l_infcx = infer::new_infer_ctxt(tcx);
      }
      some(i) {
        l_tcx = i.tcx;
        l_infcx = i;
      }
    }

    alt infer::mk_eqty(l_infcx, t1, t2) {
      result::ok(()) { true }
      result::err(terr) {
        l_tcx.sess.span_err(span, msg() + ": " +
            ty::type_err_to_str(l_tcx, terr));
        false
      }
    }
}

fn arg_is_argv_ty(_tcx: ty::ctxt, a: ty::arg) -> bool {
    alt ty::get(a.ty).struct {
      ty::ty_evec(mt, vstore_uniq) {
        if mt.mutbl != ast::m_imm { ret false; }
        alt ty::get(mt.ty).struct {
          ty::ty_str { ret true; }
          _ { ret false; }
        }
      }
      _ { ret false; }
    }
}

fn check_main_fn_ty(ccx: @crate_ctxt,
                    main_id: ast::node_id,
                    main_span: span) {

    let tcx = ccx.tcx;
    let main_t = ty::node_id_to_type(tcx, main_id);
    alt ty::get(main_t).struct {
      ty::ty_fn({purity: ast::impure_fn, proto: ast::proto_bare,
                 inputs, output, ret_style: ast::return_val, constraints}) {
        alt tcx.items.find(main_id) {
         some(ast_map::node_item(it,_)) {
             alt it.node {
               ast::item_fn(_,ps,_) if vec::is_not_empty(ps) {
                  tcx.sess.span_err(main_span,
                    "main function is not allowed to have type parameters");
                  ret;
               }
               _ {}
             }
         }
         _ {}
        }
        let mut ok = vec::len(constraints) == 0u;
        ok &= ty::type_is_nil(output);
        let num_args = vec::len(inputs);
        ok &= num_args == 0u || num_args == 1u &&
              arg_is_argv_ty(tcx, inputs[0]);
        if !ok {
                tcx.sess.span_err(main_span,
                   #fmt("Wrong type in main function: found `%s`, \
                   expecting `native fn([str]) -> ()` or `native fn() -> ()`",
                         ty_to_str(tcx, main_t)));
         }
      }
      _ {
        tcx.sess.span_bug(main_span,
                          "main has a non-function type: found `" +
                              ty_to_str(tcx, main_t) + "`");
      }
    }
}

fn check_for_main_fn(ccx: @crate_ctxt, crate: @ast::crate) {
    let tcx = ccx.tcx;
    if !tcx.sess.building_library {
        alt copy tcx.sess.main_fn {
          some((id, sp)) { check_main_fn_ty(ccx, id, sp); }
          none { tcx.sess.span_err(crate.span, "main function not found"); }
        }
    }
}

fn check_crate(tcx: ty::ctxt, impl_map: resolve::impl_map,
               crate: @ast::crate) -> (method_map, vtable_map) {
    let ccx = @{impl_map: impl_map,
                method_map: std::map::int_hash(),
                vtable_map: std::map::int_hash(),
                tcx: tcx};
    collect::collect_item_types(ccx, crate);
    check::check_item_types(ccx, crate);
    check_for_main_fn(ccx, crate);
    tcx.sess.abort_if_errors();
    (ccx.method_map, ccx.vtable_map)
}
//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
//
<commit_msg>Don't need a span on "main function not found" error.  Issue #2707.<commit_after>/*

typeck.rs, an introduction

The type checker is responsible for:

1. Determining the type of each expression
2. Resolving methods and ifaces
3. Guaranteeing that most type rules are met ("most?", you say, "why most?"
   Well, dear reader, read on)

The main entry point is `check_crate()`.  Type checking operates in two major
phases: collect and check.  The collect phase passes over all items and
determines their type, without examining their "innards".  The check phase
then checks function bodies and so forth.

Within the check phase, we check each function body one at a time (bodies of
function expressions are checked as part of the containing function).
Inference is used to supply types wherever they are unknown. The actual
checking of a function itself has several phases (check, regionck, writeback),
as discussed in the documentation for the `check` module.

The type checker is defined into various submodules which are documented
independently:

- astconv: converts the AST representation of types
  into the `ty` representation

- collect: computes the types of each top-level item and enters them into
  the `cx.tcache` table for later use

- check: walks over function bodies and type checks them, inferring types for
  local variables, type parameters, etc as necessary.

- infer: finds the types to use for each type variable such that
  all subtyping and assignment constraints are met.  In essence, the check
  module specifies the constraints, and the infer module solves them.

*/

import result::{result, extensions};
import syntax::{ast, ast_util, ast_map};
import ast::spanned;
import syntax::ast_map::node_id_to_str;
import syntax::ast_util::{local_def, respan, split_class_items};
import syntax::visit;
import metadata::csearch;
import driver::session::session;
import util::common::may_break;
import syntax::codemap::span;
import pat_util::{pat_is_variant, pat_id_map};
import middle::ty;
import middle::ty::{arg, field, node_type_table, mk_nil,
                    ty_param_bounds_and_ty, lookup_public_fields};
import middle::typeck::infer::methods;
import util::ppaux::{ty_to_str, tys_to_str, region_to_str,
                     bound_region_to_str, vstore_to_str};
import std::smallintmap;
import std::smallintmap::map;
import std::map;
import std::map::{hashmap, int_hash};
import std::serialization::{serialize_uint, deserialize_uint};
import vec::each;
import syntax::print::pprust::*;
import util::common::{indent, indenter};
import std::list;
import list::{list, nil, cons};

export check_crate;
export infer;
export method_map;
export method_origin, serialize_method_origin, deserialize_method_origin;
export method_map_entry, serialize_method_map_entry;
export deserialize_method_map_entry;
export vtable_map;
export vtable_res;
export vtable_origin;

#[auto_serialize]
enum method_origin {
    // fully statically resolved method
    method_static(ast::def_id),

    // method invoked on a type parameter with a bounded iface
    method_param(method_param),

    // method invoked on a boxed iface
    method_iface(ast::def_id, uint),
}

// details for a method invoked with a receiver whose type is a type parameter
// with a bounded iface.
#[auto_serialize]
type method_param = {
    // the iface containing the method to be invoked
    iface_id: ast::def_id,

    // index of the method to be invoked amongst the iface's methods
    method_num: uint,

    // index of the type parameter (from those that are in scope) that is
    // the type of the receiver
    param_num: uint,

    // index of the bound for this type parameter which specifies the iface
    bound_num: uint
};

#[auto_serialize]
type method_map_entry = {
    // number of derefs that are required on the receiver
    derefs: uint,

    // method details being invoked
    origin: method_origin
};

// maps from an expression id that corresponds to a method call to the details
// of the method to be invoked
type method_map = hashmap<ast::node_id, method_map_entry>;

// Resolutions for bounds of all parameters, left to right, for a given path.
type vtable_res = @[vtable_origin];

enum vtable_origin {
    /*
      Statically known vtable. def_id gives the class or impl item
      from whence comes the vtable, and tys are the type substs.
      vtable_res is the vtable itself
     */
    vtable_static(ast::def_id, [ty::t], vtable_res),
    /*
      Dynamic vtable, comes from a parameter that has a bound on it:
      fn foo<T: quux, baz, bar>(a: T) -- a's vtable would have a
      vtable_param origin

      The first uint is the param number (identifying T in the example),
      and the second is the bound number (identifying baz)
     */
    vtable_param(uint, uint),
    /*
      Dynamic vtable, comes from something known to have an interface
      type. def_id refers to the iface item, tys are the substs
     */
    vtable_iface(ast::def_id, [ty::t]),
}

type vtable_map = hashmap<ast::node_id, vtable_res>;

type ty_param_substs_and_ty = {substs: ty::substs, ty: ty::t};

type ty_table = hashmap<ast::def_id, ty::t>;

type crate_ctxt = {impl_map: resolve::impl_map,
                   method_map: method_map,
                   vtable_map: vtable_map,
                   tcx: ty::ctxt};

// Functions that write types into the node type table
fn write_ty_to_tcx(tcx: ty::ctxt, node_id: ast::node_id, ty: ty::t) {
    #debug["write_ty_to_tcx(%d, %s)", node_id, ty_to_str(tcx, ty)];
    smallintmap::insert(*tcx.node_types, node_id as uint, ty);
}
fn write_substs_to_tcx(tcx: ty::ctxt,
                       node_id: ast::node_id,
                       +substs: [ty::t]) {
    if substs.len() > 0u {
        tcx.node_type_substs.insert(node_id, substs);
    }
}

fn lookup_def_tcx(tcx: ty::ctxt, sp: span, id: ast::node_id) -> ast::def {
    alt tcx.def_map.find(id) {
      some(x) { x }
      _ {
        tcx.sess.span_fatal(sp, "internal error looking up a definition")
      }
    }
}

fn lookup_def_ccx(ccx: @crate_ctxt, sp: span, id: ast::node_id) -> ast::def {
    lookup_def_tcx(ccx.tcx, sp, id)
}

fn no_params(t: ty::t) -> ty::ty_param_bounds_and_ty {
    {bounds: @[], rp: ast::rp_none, ty: t}
}

fn require_same_types(
    tcx: ty::ctxt,
    maybe_infcx: option<infer::infer_ctxt>,
    span: span,
    t1: ty::t,
    t2: ty::t,
    msg: fn() -> str) -> bool {

    let l_tcx, l_infcx;
    alt maybe_infcx {
      none {
        l_tcx = tcx;
        l_infcx = infer::new_infer_ctxt(tcx);
      }
      some(i) {
        l_tcx = i.tcx;
        l_infcx = i;
      }
    }

    alt infer::mk_eqty(l_infcx, t1, t2) {
      result::ok(()) { true }
      result::err(terr) {
        l_tcx.sess.span_err(span, msg() + ": " +
            ty::type_err_to_str(l_tcx, terr));
        false
      }
    }
}

fn arg_is_argv_ty(_tcx: ty::ctxt, a: ty::arg) -> bool {
    alt ty::get(a.ty).struct {
      ty::ty_evec(mt, vstore_uniq) {
        if mt.mutbl != ast::m_imm { ret false; }
        alt ty::get(mt.ty).struct {
          ty::ty_str { ret true; }
          _ { ret false; }
        }
      }
      _ { ret false; }
    }
}

fn check_main_fn_ty(ccx: @crate_ctxt,
                    main_id: ast::node_id,
                    main_span: span) {

    let tcx = ccx.tcx;
    let main_t = ty::node_id_to_type(tcx, main_id);
    alt ty::get(main_t).struct {
      ty::ty_fn({purity: ast::impure_fn, proto: ast::proto_bare,
                 inputs, output, ret_style: ast::return_val, constraints}) {
        alt tcx.items.find(main_id) {
         some(ast_map::node_item(it,_)) {
             alt it.node {
               ast::item_fn(_,ps,_) if vec::is_not_empty(ps) {
                  tcx.sess.span_err(main_span,
                    "main function is not allowed to have type parameters");
                  ret;
               }
               _ {}
             }
         }
         _ {}
        }
        let mut ok = vec::len(constraints) == 0u;
        ok &= ty::type_is_nil(output);
        let num_args = vec::len(inputs);
        ok &= num_args == 0u || num_args == 1u &&
              arg_is_argv_ty(tcx, inputs[0]);
        if !ok {
                tcx.sess.span_err(main_span,
                   #fmt("Wrong type in main function: found `%s`, \
                   expecting `native fn([str]) -> ()` or `native fn() -> ()`",
                         ty_to_str(tcx, main_t)));
         }
      }
      _ {
        tcx.sess.span_bug(main_span,
                          "main has a non-function type: found `" +
                              ty_to_str(tcx, main_t) + "`");
      }
    }
}

fn check_for_main_fn(ccx: @crate_ctxt) {
    let tcx = ccx.tcx;
    if !tcx.sess.building_library {
        alt copy tcx.sess.main_fn {
          some((id, sp)) { check_main_fn_ty(ccx, id, sp); }
          none { tcx.sess.err("main function not found"); }
        }
    }
}

fn check_crate(tcx: ty::ctxt, impl_map: resolve::impl_map,
               crate: @ast::crate) -> (method_map, vtable_map) {
    let ccx = @{impl_map: impl_map,
                method_map: std::map::int_hash(),
                vtable_map: std::map::int_hash(),
                tcx: tcx};
    collect::collect_item_types(ccx, crate);
    check::check_item_types(ccx, crate);
    check_for_main_fn(ccx);
    tcx.sess.abort_if_errors();
    (ccx.method_map, ccx.vtable_map)
}
//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
//
<|endoftext|>


<commit_before><commit_msg>2019: Day 10, part 1.<commit_after>use std::collections::HashSet;
use std::convert::TryInto;
use std::io;
use std::io::Read;
use std::iter;

mod errors;

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
struct Asteroid {
    y: i128,
    x: i128,
}

struct Asteroids(HashSet<Asteroid>);

impl Asteroids {
    fn iter(&self) -> impl Iterator<Item = &Asteroid> {
        self.0.iter()
    }

    fn print_field_from_perspective_of(&self, asteroid: &Asteroid) {
        let width = self.0.iter().map(|a| a.x).max().expect("No asteroids!") + 1;
        let height = self.0.iter().map(|a| a.y).max().expect("No asteroids!") + 1;
        for y in 0..height {
            for x in 0..width {
                let other = Asteroid { x, y };
                if asteroid == &other {
                    print!("#");
                } else if self.0.contains(&other) {
                    if self.blocked(asteroid, &other) {
                        print!("%");
                    } else {
                        print!("*");
                    }
                } else {
                    print!(".");
                }
            }
            println!();
        }
    }

    fn count_in_line_of_sight(&self, asteroid: &Asteroid) -> usize {
        self.iter()
            .filter(|other| asteroid != *other)
            .filter(|other| !self.blocked(asteroid, other))
            .count()
    }

    fn blocked(&self, a: &Asteroid, b: &Asteroid) -> bool {
        let x = b.x - a.x;
        let y = b.y - a.y;
        let divisor = gcd(x.abs(), y.abs());
        (1..divisor)
            .map(|n| Asteroid {
                x: a.x + x / divisor * n,
                y: a.y + y / divisor * n,
            })
            .filter(|other| a != other && b != other)
            .any(|other| self.0.contains(&other))
    }
}

impl iter::FromIterator<Asteroid> for Asteroids {
    fn from_iter<T: IntoIterator<Item = Asteroid>>(iterator: T) -> Self {
        Asteroids(iterator.into_iter().collect())
    }
}

fn main() -> io::Result<()> {
    let mut input = String::new();
    io::stdin().read_to_string(&mut input)?;
    let asteroids = input
        .trim()
        .split("\n")
        .enumerate()
        .flat_map(|(y, row)| {
            row.trim()
                .chars()
                .enumerate()
                .flat_map(move |(x, cell)| match cell {
                    '#' => Some(Asteroid {
                        x: x.try_into().unwrap(),
                        y: y.try_into().unwrap(),
                    }),
                    '.' => None,
                    invalid => panic!("Invalid character: {}", invalid),
                })
        })
        .collect::<Asteroids>();

    let (best, count) = asteroids
        .iter()
        .map(|asteroid| (asteroid, asteroids.count_in_line_of_sight(asteroid)))
        .max_by_key(|(_, count)| *count)
        .ok_or(errors::io("No asteroids!"))?;

    asteroids.print_field_from_perspective_of(best);
    println!();
    println!("{}", count);

    Ok(())
}

fn gcd(a: i128, b: i128) -> i128 {
    iter::successors(Some((a, b)), |(a, b)| {
        if *b == 0 {
            None
        } else {
            Some((*b, *a % *b))
        }
    })
    .last()
    .unwrap()
    .0
}
<|endoftext|>


<commit_before><commit_msg>day 20, part 1. simple, but *so* slow<commit_after>#![feature(iter_arith)]
fn presents_received(house: u32) -> u32 {
    let factors = (1..house + 1).filter(|i| house % i == 0);
    factors.map(|i| i * 10).sum()
}

fn main() {
    let amount = 36000000;
    // In the best case, a number is divisible by every number from 1 to itself
    // (n). In this case, it would receive 10 (1 + 2 + ... + n) presents, or
    // 10 ( n (n + 1) / 2), or 5 (n^2 + n). The i for which this quantity is at
    // least this amount, is the first house for which this is even possible.
    let lower = (1..).find(|i| 5 * (i * i + i) >= amount).unwrap();
    let house = (lower..).find(|&house| presents_received(house) >= amount);
    println!("{}", house.unwrap());
}
<|endoftext|>


<commit_before><commit_msg>Rewrite all_category_names() for removed Store::retrieve_for_module()<commit_after><|endoftext|>


<commit_before><commit_msg>Fix: Do not write newline character when asked not to do<commit_after><|endoftext|>


<commit_before>use core::ops::DerefMut;
use redox::ion::command::{Application};

pub fn main() {
    unsafe {
        let mut app = box Application::new();
        application = app.deref_mut();
        app.main();
    }
}
<commit_msg>Fixed issue regarding terminal not compiling<commit_after>use core::ops::DerefMut;
use redox::ion::command::{Application};
static mut application: *mut Application = 0 as *mut Application;
pub fn main() {
    unsafe {
        let mut app = box Application::new();
        application = app.deref_mut();
        app.main();
    }
}
<|endoftext|>


<commit_before><commit_msg>blank message<commit_after><|endoftext|>


<commit_before><commit_msg>add an io example<commit_after>extern crate hyper;
extern crate par;

use std::io::{self, Read};
use hyper::Client;
use hyper::header::{ContentLength, Connection, UserAgent};
use par::{Bar, Reader};

fn main() {
    let client = Client::new();
    let mut res = client.get("https://api.github.com/users/softprops/repos")
        .header(Connection::close())
        .header(UserAgent(String::from("par/0.1.0")))
        .send().unwrap();
    if let Some(&ContentLength(len)) = res.headers.clone().get::<ContentLength>() {
        let mut bar = Bar::new(len as usize);
        bar.units = par::Units::Bytes;
        let mut proxy = Reader::new(res, bar);
        let mut buf = String::new();
        proxy.read_to_string(&mut buf);
    };

}
<|endoftext|>


<commit_before><commit_msg>Fix typography and wording in French code example<commit_after><|endoftext|>


<commit_before><commit_msg>build: use repo module<commit_after><|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use rbml::opaque::Encoder;
use rustc::dep_graph::{DepGraphQuery, DepNode};
use rustc::hir::def_id::DefId;
use rustc::middle::cstore::LOCAL_CRATE;
use rustc::session::Session;
use rustc::ty::TyCtxt;
use rustc_serialize::{Encodable as RustcEncodable};
use std::hash::{Hash, Hasher, SipHasher};
use std::io::{self, Cursor, Write};
use std::fs::{self, File};
use std::path::PathBuf;

use super::data::*;
use super::directory::*;
use super::hash::*;
use super::util::*;

pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
    debug!("save_dep_graph()");
    let _ignore = tcx.dep_graph.in_ignore();
    let sess = tcx.sess;
    if sess.opts.incremental.is_none() {
        return;
    }
    let mut hcx = HashContext::new(tcx);
    let mut builder = DefIdDirectoryBuilder::new(tcx);
    let query = tcx.dep_graph.query();
    save_in(sess, dep_graph_path(tcx), |e| encode_dep_graph(&mut hcx, &mut builder, &query, e));
    save_in(sess, metadata_hash_path(tcx, LOCAL_CRATE), |e| encode_metadata_hashes(&mut hcx, &mut builder, &query, e));
}

pub fn save_work_products(sess: &Session, local_crate_name: &str) {
    debug!("save_work_products()");
    let _ignore = sess.dep_graph.in_ignore();
    let path = sess_work_products_path(sess, local_crate_name);
    save_in(sess, path, |e| encode_work_products(sess, e));
}

fn save_in<F>(sess: &Session,
              opt_path_buf: Option<PathBuf>,
              encode: F)
    where F: FnOnce(&mut Encoder) -> io::Result<()>
{
    let path_buf = match opt_path_buf {
        Some(p) => p,
        None => return
    };

    // FIXME(#32754) lock file?

    // delete the old dep-graph, if any
    if path_buf.exists() {
        match fs::remove_file(&path_buf) {
            Ok(()) => { }
            Err(err) => {
                sess.err(
                    &format!("unable to delete old dep-graph at `{}`: {}",
                             path_buf.display(), err));
                return;
            }
        }
    }

    // generate the data in a memory buffer
    let mut wr = Cursor::new(Vec::new());
    match encode(&mut Encoder::new(&mut wr)) {
        Ok(()) => { }
        Err(err) => {
            sess.err(
                &format!("could not encode dep-graph to `{}`: {}",
                         path_buf.display(), err));
            return;
        }
    }

    // write the data out
    let data = wr.into_inner();
    match
        File::create(&path_buf)
        .and_then(|mut file| file.write_all(&data))
    {
        Ok(_) => { }
        Err(err) => {
            sess.err(
                &format!("failed to write dep-graph to `{}`: {}",
                         path_buf.display(), err));
            return;
        }
    }
}

pub fn encode_dep_graph<'a, 'tcx>(hcx: &mut HashContext<'a, 'tcx>,
                                  builder: &mut DefIdDirectoryBuilder,
                                  query: &DepGraphQuery<DefId>,
                                  encoder: &mut Encoder)
                                  -> io::Result<()>
{
    let (nodes, edges) = (query.nodes(), query.edges());

    // Create hashes for inputs.
    let hashes =
        nodes.iter()
             .filter_map(|dep_node| {
                 hcx.hash(dep_node)
                    .map(|(_, hash)| {
                        let node = builder.map(dep_node);
                        SerializedHash { node: node, hash: hash }
                    })
             })
             .collect();

    // Create the serialized dep-graph.
    let graph = SerializedDepGraph {
        nodes: nodes.iter().map(|node| builder.map(node)).collect(),
        edges: edges.iter()
                    .map(|&(ref source_node, ref target_node)| {
                        let source = builder.map(source_node);
                        let target = builder.map(target_node);
                        (source, target)
                    })
                    .collect(),
        hashes: hashes,
    };

    debug!("graph = {:#?}", graph);

    // Encode the directory and then the graph data.
    try!(builder.directory().encode(encoder));
    try!(graph.encode(encoder));

    Ok(())
}

pub fn encode_metadata_hashes<'a, 'tcx>(hcx: &mut HashContext<'a, 'tcx>,
                                        builder: &mut DefIdDirectoryBuilder,
                                        query: &DepGraphQuery<DefId>,
                                        encoder: &mut Encoder)
                                        -> io::Result<()>
{
    let tcx = hcx.tcx;

    let serialized_hashes = {
        // Identify the `MetaData(X)` nodes where `X` is local. These are
        // the metadata items we export. Downstream crates will want to
        // see a hash that tells them whether we might have changed the
        // metadata for a given item since they last compiled.
        let meta_data_def_ids =
            query.nodes()
                 .into_iter()
                 .filter_map(|dep_node| match *dep_node {
                     DepNode::MetaData(def_id) if def_id.is_local() => Some(def_id),
                     _ => None,
                 });

        // To create the hash for each item `X`, we don't hash the raw
        // bytes of the metadata (though in principle we
        // could). Instead, we walk the predecessors of `MetaData(X)`
        // from the dep-graph. This corresponds to all the inputs that
        // were read to construct the metadata. To create the hash for
        // the metadata, we hash (the hash of) all of those inputs.
        let hashes =
            meta_data_def_ids
            .map(|def_id| {
                assert!(def_id.is_local());
                let dep_node = DepNode::MetaData(def_id);
                let mut state = SipHasher::new();
                debug!("save: computing metadata hash for {:?}", dep_node);

                let predecessors = query.transitive_predecessors(&dep_node);
                let mut hashes: Vec<_> =
                    predecessors.iter()
                                .filter_map(|node| hcx.hash(&node))
                                .map(|(def_id, hash)| {
                                    let index = builder.add(def_id);
                                    let path = builder.lookup_def_path(index);
                                    (path.to_string(tcx), hash) // (*)
                                })
                                .collect();

                // (*) creating a `String` from each def-path is a bit inefficient,
                // but it's the easiest way to get a deterministic ord/hash.

                hashes.sort();
                state.write_usize(hashes.len());
                for (path, hash) in hashes {
                    debug!("save: predecessor {:?} has hash {}", path, hash);
                    path.hash(&mut state);
                    state.write_u64(hash.to_le());
                }

                let hash = state.finish();
                debug!("save: metadata hash for {:?} is {}", dep_node, hash);

                SerializedMetadataHash {
                    def_index: def_id.index,
                    hash: hash,
                }
            });

        // Collect these up into a vector.
        SerializedMetadataHashes {
            hashes: hashes.collect()
        }
    };

    // Encode everything.
    try!(serialized_hashes.encode(encoder));

    Ok(())
}

pub fn encode_work_products(sess: &Session,
                            encoder: &mut Encoder)
                            -> io::Result<()>
{
    let work_products: Vec<_> =
        sess.dep_graph.work_products()
                     .iter()
                     .map(|(id, work_product)| {
                         SerializedWorkProduct {
                             id: id.clone(),
                             work_product: work_product.clone(),
                         }
                     })
                     .collect();

    work_products.encode(encoder)
}

<commit_msg>rustfmt save.rs<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use rbml::opaque::Encoder;
use rustc::dep_graph::{DepGraphQuery, DepNode};
use rustc::hir::def_id::DefId;
use rustc::middle::cstore::LOCAL_CRATE;
use rustc::session::Session;
use rustc::ty::TyCtxt;
use rustc_serialize::Encodable as RustcEncodable;
use std::hash::{Hash, Hasher, SipHasher};
use std::io::{self, Cursor, Write};
use std::fs::{self, File};
use std::path::PathBuf;

use super::data::*;
use super::directory::*;
use super::hash::*;
use super::util::*;

pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
    debug!("save_dep_graph()");
    let _ignore = tcx.dep_graph.in_ignore();
    let sess = tcx.sess;
    if sess.opts.incremental.is_none() {
        return;
    }
    let mut hcx = HashContext::new(tcx);
    let mut builder = DefIdDirectoryBuilder::new(tcx);
    let query = tcx.dep_graph.query();
    save_in(sess,
            dep_graph_path(tcx),
            |e| encode_dep_graph(&mut hcx, &mut builder, &query, e));
    save_in(sess,
            metadata_hash_path(tcx, LOCAL_CRATE),
            |e| encode_metadata_hashes(&mut hcx, &mut builder, &query, e));
}

pub fn save_work_products(sess: &Session, local_crate_name: &str) {
    debug!("save_work_products()");
    let _ignore = sess.dep_graph.in_ignore();
    let path = sess_work_products_path(sess, local_crate_name);
    save_in(sess, path, |e| encode_work_products(sess, e));
}

fn save_in<F>(sess: &Session, opt_path_buf: Option<PathBuf>, encode: F)
    where F: FnOnce(&mut Encoder) -> io::Result<()>
{
    let path_buf = match opt_path_buf {
        Some(p) => p,
        None => return,
    };

    // FIXME(#32754) lock file?

    // delete the old dep-graph, if any
    if path_buf.exists() {
        match fs::remove_file(&path_buf) {
            Ok(()) => {}
            Err(err) => {
                sess.err(&format!("unable to delete old dep-graph at `{}`: {}",
                                  path_buf.display(),
                                  err));
                return;
            }
        }
    }

    // generate the data in a memory buffer
    let mut wr = Cursor::new(Vec::new());
    match encode(&mut Encoder::new(&mut wr)) {
        Ok(()) => {}
        Err(err) => {
            sess.err(&format!("could not encode dep-graph to `{}`: {}",
                              path_buf.display(),
                              err));
            return;
        }
    }

    // write the data out
    let data = wr.into_inner();
    match File::create(&path_buf).and_then(|mut file| file.write_all(&data)) {
        Ok(_) => {}
        Err(err) => {
            sess.err(&format!("failed to write dep-graph to `{}`: {}",
                              path_buf.display(),
                              err));
            return;
        }
    }
}

pub fn encode_dep_graph<'a, 'tcx>(hcx: &mut HashContext<'a, 'tcx>,
                                  builder: &mut DefIdDirectoryBuilder,
                                  query: &DepGraphQuery<DefId>,
                                  encoder: &mut Encoder)
                                  -> io::Result<()> {
    let (nodes, edges) = (query.nodes(), query.edges());

    // Create hashes for inputs.
    let hashes = nodes.iter()
        .filter_map(|dep_node| {
            hcx.hash(dep_node)
                .map(|(_, hash)| {
                    let node = builder.map(dep_node);
                    SerializedHash {
                        node: node,
                        hash: hash,
                    }
                })
        })
        .collect();

    // Create the serialized dep-graph.
    let graph = SerializedDepGraph {
        nodes: nodes.iter().map(|node| builder.map(node)).collect(),
        edges: edges.iter()
            .map(|&(ref source_node, ref target_node)| {
                let source = builder.map(source_node);
                let target = builder.map(target_node);
                (source, target)
            })
            .collect(),
        hashes: hashes,
    };

    debug!("graph = {:#?}", graph);

    // Encode the directory and then the graph data.
    try!(builder.directory().encode(encoder));
    try!(graph.encode(encoder));

    Ok(())
}

pub fn encode_metadata_hashes<'a, 'tcx>(hcx: &mut HashContext<'a, 'tcx>,
                                        builder: &mut DefIdDirectoryBuilder,
                                        query: &DepGraphQuery<DefId>,
                                        encoder: &mut Encoder)
                                        -> io::Result<()> {
    let tcx = hcx.tcx;

    let serialized_hashes = {
        // Identify the `MetaData(X)` nodes where `X` is local. These are
        // the metadata items we export. Downstream crates will want to
        // see a hash that tells them whether we might have changed the
        // metadata for a given item since they last compiled.
        let meta_data_def_ids = query.nodes()
            .into_iter()
            .filter_map(|dep_node| match *dep_node {
                DepNode::MetaData(def_id) if def_id.is_local() => Some(def_id),
                _ => None,
            });

        // To create the hash for each item `X`, we don't hash the raw
        // bytes of the metadata (though in principle we
        // could). Instead, we walk the predecessors of `MetaData(X)`
        // from the dep-graph. This corresponds to all the inputs that
        // were read to construct the metadata. To create the hash for
        // the metadata, we hash (the hash of) all of those inputs.
        let hashes = meta_data_def_ids.map(|def_id| {
            assert!(def_id.is_local());
            let dep_node = DepNode::MetaData(def_id);
            let mut state = SipHasher::new();
            debug!("save: computing metadata hash for {:?}", dep_node);

            let predecessors = query.transitive_predecessors(&dep_node);
            let mut hashes: Vec<_> = predecessors.iter()
                .filter_map(|node| hcx.hash(&node))
                .map(|(def_id, hash)| {
                    let index = builder.add(def_id);
                    let path = builder.lookup_def_path(index);
                    (path.to_string(tcx), hash) // (*)
                })
                .collect();

            // (*) creating a `String` from each def-path is a bit inefficient,
            // but it's the easiest way to get a deterministic ord/hash.

            hashes.sort();
            state.write_usize(hashes.len());
            for (path, hash) in hashes {
                debug!("save: predecessor {:?} has hash {}", path, hash);
                path.hash(&mut state);
                state.write_u64(hash.to_le());
            }

            let hash = state.finish();
            debug!("save: metadata hash for {:?} is {}", dep_node, hash);

            SerializedMetadataHash {
                def_index: def_id.index,
                hash: hash,
            }
        });

        // Collect these up into a vector.
        SerializedMetadataHashes { hashes: hashes.collect() }
    };

    // Encode everything.
    try!(serialized_hashes.encode(encoder));

    Ok(())
}

pub fn encode_work_products(sess: &Session, encoder: &mut Encoder) -> io::Result<()> {
    let work_products: Vec<_> = sess.dep_graph
        .work_products()
        .iter()
        .map(|(id, work_product)| {
            SerializedWorkProduct {
                id: id.clone(),
                work_product: work_product.clone(),
            }
        })
        .collect();

    work_products.encode(encoder)
}
<|endoftext|>


<commit_before>// Copyright 2016 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 rustc_data_structures::sync::Lrc;
use std::sync::Arc;

use monomorphize::Instance;
use rustc::hir;
use rustc::hir::TransFnAttrFlags;
use rustc::hir::def_id::CrateNum;
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
use rustc::middle::exported_symbols::{SymbolExportLevel, ExportedSymbol, metadata_symbol_name};
use rustc::session::config;
use rustc::ty::{TyCtxt, SymbolName};
use rustc::ty::maps::Providers;
use rustc::util::nodemap::{FxHashMap, DefIdSet};
use rustc_allocator::ALLOCATOR_METHODS;

pub type ExportedSymbols = FxHashMap<
    CrateNum,
    Arc<Vec<(String, SymbolExportLevel)>>,
>;

pub fn threshold(tcx: TyCtxt) -> SymbolExportLevel {
    crates_export_threshold(&tcx.sess.crate_types.borrow())
}

fn crate_export_threshold(crate_type: config::CrateType) -> SymbolExportLevel {
    match crate_type {
        config::CrateTypeExecutable |
        config::CrateTypeStaticlib  |
        config::CrateTypeProcMacro  |
        config::CrateTypeCdylib     => SymbolExportLevel::C,
        config::CrateTypeRlib       |
        config::CrateTypeDylib      => SymbolExportLevel::Rust,
    }
}

pub fn crates_export_threshold(crate_types: &[config::CrateType])
                                      -> SymbolExportLevel {
    if crate_types.iter().any(|&crate_type| {
        crate_export_threshold(crate_type) == SymbolExportLevel::Rust
    }) {
        SymbolExportLevel::Rust
    } else {
        SymbolExportLevel::C
    }
}

fn reachable_non_generics_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                             cnum: CrateNum)
                                             -> Lrc<DefIdSet>
{
    assert_eq!(cnum, LOCAL_CRATE);

    if !tcx.sess.opts.output_types.should_trans() {
        return Lrc::new(DefIdSet())
    }

    let export_threshold = threshold(tcx);

    // We already collect all potentially reachable non-generic items for
    // `exported_symbols`. Now we just filter them down to what is actually
    // exported for the given crate we are compiling.
    let reachable_non_generics = tcx
        .exported_symbols(LOCAL_CRATE)
        .iter()
        .filter_map(|&(exported_symbol, level)| {
            if let ExportedSymbol::NonGeneric(def_id) = exported_symbol {
                if level.is_below_threshold(export_threshold) {
                    return Some(def_id)
                }
            }

            None
        })
        .collect();

    Lrc::new(reachable_non_generics)
}

fn is_reachable_non_generic_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                               def_id: DefId)
                                               -> bool {
    tcx.reachable_non_generics(def_id.krate).contains(&def_id)
}

fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                             cnum: CrateNum)
                                             -> Arc<Vec<(ExportedSymbol<'tcx>,
                                                         SymbolExportLevel)>>
{
    assert_eq!(cnum, LOCAL_CRATE);

    if !tcx.sess.opts.output_types.should_trans() {
        return Arc::new(vec![])
    }

    // Check to see if this crate is a "special runtime crate". These
    // crates, implementation details of the standard library, typically
    // have a bunch of `pub extern` and `#[no_mangle]` functions as the
    // ABI between them. We don't want their symbols to have a `C`
    // export level, however, as they're just implementation details.
    // Down below we'll hardwire all of the symbols to the `Rust` export
    // level instead.
    let special_runtime_crate = tcx.is_panic_runtime(LOCAL_CRATE) ||
        tcx.is_compiler_builtins(LOCAL_CRATE);

    let reachable_non_generics: DefIdSet = tcx.reachable_set(LOCAL_CRATE).0
        .iter()
        .filter_map(|&node_id| {
            // We want to ignore some FFI functions that are not exposed from
            // this crate. Reachable FFI functions can be lumped into two
            // categories:
            //
            // 1. Those that are included statically via a static library
            // 2. Those included otherwise (e.g. dynamically or via a framework)
            //
            // Although our LLVM module is not literally emitting code for the
            // statically included symbols, it's an export of our library which
            // needs to be passed on to the linker and encoded in the metadata.
            //
            // As a result, if this id is an FFI item (foreign item) then we only
            // let it through if it's included statically.
            match tcx.hir.get(node_id) {
                hir::map::NodeForeignItem(..) => {
                    let def_id = tcx.hir.local_def_id(node_id);
                    if tcx.is_statically_included_foreign_item(def_id) {
                        Some(def_id)
                    } else {
                        None
                    }
                }

                // Only consider nodes that actually have exported symbols.
                hir::map::NodeItem(&hir::Item {
                    node: hir::ItemStatic(..),
                    ..
                }) |
                hir::map::NodeItem(&hir::Item {
                    node: hir::ItemFn(..), ..
                }) |
                hir::map::NodeImplItem(&hir::ImplItem {
                    node: hir::ImplItemKind::Method(..),
                    ..
                }) => {
                    let def_id = tcx.hir.local_def_id(node_id);
                    let generics = tcx.generics_of(def_id);
                    if (generics.parent_types == 0 && generics.types.is_empty()) &&
                        // Functions marked with #[inline] are only ever translated
                        // with "internal" linkage and are never exported.
                        !Instance::mono(tcx, def_id).def.requires_local(tcx) {
                        Some(def_id)
                    } else {
                        None
                    }
                }

                _ => None
            }
        })
        .collect();

    let mut symbols: Vec<_> = reachable_non_generics
        .iter()
        .map(|&def_id| {
            let export_level = if special_runtime_crate {
                let name = tcx.symbol_name(Instance::mono(tcx, def_id));
                // We can probably do better here by just ensuring that
                // it has hidden visibility rather than public
                // visibility, as this is primarily here to ensure it's
                // not stripped during LTO.
                //
                // In general though we won't link right if these
                // symbols are stripped, and LTO currently strips them.
                if &*name == "rust_eh_personality" ||
                   &*name == "rust_eh_register_frames" ||
                   &*name == "rust_eh_unregister_frames" {
                    SymbolExportLevel::C
                } else {
                    SymbolExportLevel::Rust
                }
            } else {
                tcx.symbol_export_level(def_id)
            };
            debug!("EXPORTED SYMBOL (local): {} ({:?})",
                   tcx.symbol_name(Instance::mono(tcx, def_id)),
                   export_level);
            (ExportedSymbol::NonGeneric(def_id), export_level)
        })
        .collect();

    if let Some(id) = tcx.sess.derive_registrar_fn.get() {
        let def_id = tcx.hir.local_def_id(id);
        symbols.push((ExportedSymbol::NonGeneric(def_id), SymbolExportLevel::C));
    }

    if let Some(id) = tcx.sess.plugin_registrar_fn.get() {
        let def_id = tcx.hir.local_def_id(id);
        symbols.push((ExportedSymbol::NonGeneric(def_id), SymbolExportLevel::C));
    }

    if let Some(_) = *tcx.sess.entry_fn.borrow() {
        let symbol_name = "main".to_string();
        let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(&symbol_name));

        symbols.push((exported_symbol, SymbolExportLevel::C));
    }

    if tcx.sess.allocator_kind.get().is_some() {
        for method in ALLOCATOR_METHODS {
            let symbol_name = format!("__rust_{}", method.name);
            let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(&symbol_name));

            symbols.push((exported_symbol, SymbolExportLevel::Rust));
        }
    }

    if tcx.sess.opts.debugging_opts.pgo_gen.is_some() {
        // These are weak symbols that point to the profile version and the
        // profile name, which need to be treated as exported so LTO doesn't nix
        // them.
        const PROFILER_WEAK_SYMBOLS: [&'static str; 2] = [
            "__llvm_profile_raw_version",
            "__llvm_profile_filename",
        ];
        for sym in &PROFILER_WEAK_SYMBOLS {
            let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(sym));
            symbols.push((exported_symbol, SymbolExportLevel::C));
        }
    }

    if tcx.sess.crate_types.borrow().contains(&config::CrateTypeDylib) {
        let symbol_name = metadata_symbol_name(tcx);
        let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(&symbol_name));

        symbols.push((exported_symbol, SymbolExportLevel::Rust));
    }

    // Sort so we get a stable incr. comp. hash.
    symbols.sort_unstable_by(|&(ref symbol1, ..), &(ref symbol2, ..)| {
        symbol1.compare_stable(tcx, symbol2)
    });

    Arc::new(symbols)
}

pub fn provide(providers: &mut Providers) {
    providers.reachable_non_generics = reachable_non_generics_provider;
    providers.is_reachable_non_generic = is_reachable_non_generic_provider;
    providers.exported_symbols = exported_symbols_provider_local;
    providers.symbol_export_level = symbol_export_level_provider;
}

pub fn provide_extern(providers: &mut Providers) {
    providers.is_reachable_non_generic = is_reachable_non_generic_provider;
    providers.symbol_export_level = symbol_export_level_provider;
}

fn symbol_export_level_provider(tcx: TyCtxt, sym_def_id: DefId) -> SymbolExportLevel {
    // We export anything that's not mangled at the "C" layer as it probably has
    // to do with ABI concerns. We do not, however, apply such treatment to
    // special symbols in the standard library for various plumbing between
    // core/std/allocators/etc. For example symbols used to hook up allocation
    // are not considered for export
    let trans_fn_attrs = tcx.trans_fn_attrs(sym_def_id);
    let is_extern = trans_fn_attrs.contains_extern_indicator();
    let std_internal = trans_fn_attrs.flags.contains(TransFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL);

    if is_extern && !std_internal {
        SymbolExportLevel::C
    } else {
        SymbolExportLevel::Rust
    }
}
<commit_msg>Move export level computation to reachable_non_generics query.<commit_after>// Copyright 2016 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 rustc_data_structures::sync::Lrc;
use std::sync::Arc;

use monomorphize::Instance;
use rustc::hir;
use rustc::hir::TransFnAttrFlags;
use rustc::hir::def_id::CrateNum;
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
use rustc::middle::exported_symbols::{SymbolExportLevel, ExportedSymbol, metadata_symbol_name};
use rustc::session::config;
use rustc::ty::{TyCtxt, SymbolName};
use rustc::ty::maps::Providers;
use rustc::util::nodemap::{FxHashMap, DefIdMap};
use rustc_allocator::ALLOCATOR_METHODS;

pub type ExportedSymbols = FxHashMap<
    CrateNum,
    Arc<Vec<(String, SymbolExportLevel)>>,
>;

pub fn threshold(tcx: TyCtxt) -> SymbolExportLevel {
    crates_export_threshold(&tcx.sess.crate_types.borrow())
}

fn crate_export_threshold(crate_type: config::CrateType) -> SymbolExportLevel {
    match crate_type {
        config::CrateTypeExecutable |
        config::CrateTypeStaticlib  |
        config::CrateTypeProcMacro  |
        config::CrateTypeCdylib     => SymbolExportLevel::C,
        config::CrateTypeRlib       |
        config::CrateTypeDylib      => SymbolExportLevel::Rust,
    }
}

pub fn crates_export_threshold(crate_types: &[config::CrateType])
                                      -> SymbolExportLevel {
    if crate_types.iter().any(|&crate_type| {
        crate_export_threshold(crate_type) == SymbolExportLevel::Rust
    }) {
        SymbolExportLevel::Rust
    } else {
        SymbolExportLevel::C
    }
}

fn reachable_non_generics_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                             cnum: CrateNum)
                                             -> Lrc<DefIdMap<SymbolExportLevel>>
{
    assert_eq!(cnum, LOCAL_CRATE);

    if !tcx.sess.opts.output_types.should_trans() {
        return Lrc::new(DefIdMap())
    }

    // Check to see if this crate is a "special runtime crate". These
    // crates, implementation details of the standard library, typically
    // have a bunch of `pub extern` and `#[no_mangle]` functions as the
    // ABI between them. We don't want their symbols to have a `C`
    // export level, however, as they're just implementation details.
    // Down below we'll hardwire all of the symbols to the `Rust` export
    // level instead.
    let special_runtime_crate = tcx.is_panic_runtime(LOCAL_CRATE) ||
        tcx.is_compiler_builtins(LOCAL_CRATE);

    let mut reachable_non_generics: DefIdMap<_> = tcx.reachable_set(LOCAL_CRATE).0
        .iter()
        .filter_map(|&node_id| {
            // We want to ignore some FFI functions that are not exposed from
            // this crate. Reachable FFI functions can be lumped into two
            // categories:
            //
            // 1. Those that are included statically via a static library
            // 2. Those included otherwise (e.g. dynamically or via a framework)
            //
            // Although our LLVM module is not literally emitting code for the
            // statically included symbols, it's an export of our library which
            // needs to be passed on to the linker and encoded in the metadata.
            //
            // As a result, if this id is an FFI item (foreign item) then we only
            // let it through if it's included statically.
            match tcx.hir.get(node_id) {
                hir::map::NodeForeignItem(..) => {
                    let def_id = tcx.hir.local_def_id(node_id);
                    if tcx.is_statically_included_foreign_item(def_id) {
                        Some(def_id)
                    } else {
                        None
                    }
                }

                // Only consider nodes that actually have exported symbols.
                hir::map::NodeItem(&hir::Item {
                    node: hir::ItemStatic(..),
                    ..
                }) |
                hir::map::NodeItem(&hir::Item {
                    node: hir::ItemFn(..), ..
                }) |
                hir::map::NodeImplItem(&hir::ImplItem {
                    node: hir::ImplItemKind::Method(..),
                    ..
                }) => {
                    let def_id = tcx.hir.local_def_id(node_id);
                    let generics = tcx.generics_of(def_id);
                    if (generics.parent_types == 0 && generics.types.is_empty()) &&
                        // Functions marked with #[inline] are only ever translated
                        // with "internal" linkage and are never exported.
                        !Instance::mono(tcx, def_id).def.requires_local(tcx) {
                        Some(def_id)
                    } else {
                        None
                    }
                }

                _ => None
            }
        })
        .map(|def_id| {
            let export_level = if special_runtime_crate {
                let name = tcx.symbol_name(Instance::mono(tcx, def_id));
                // We can probably do better here by just ensuring that
                // it has hidden visibility rather than public
                // visibility, as this is primarily here to ensure it's
                // not stripped during LTO.
                //
                // In general though we won't link right if these
                // symbols are stripped, and LTO currently strips them.
                if &*name == "rust_eh_personality" ||
                   &*name == "rust_eh_register_frames" ||
                   &*name == "rust_eh_unregister_frames" {
                    SymbolExportLevel::C
                } else {
                    SymbolExportLevel::Rust
                }
            } else {
                tcx.symbol_export_level(def_id)
            };
            debug!("EXPORTED SYMBOL (local): {} ({:?})",
                   tcx.symbol_name(Instance::mono(tcx, def_id)),
                   export_level);
            (def_id, export_level)
        })
        .collect();

    if let Some(id) = tcx.sess.derive_registrar_fn.get() {
        let def_id = tcx.hir.local_def_id(id);
        reachable_non_generics.insert(def_id, SymbolExportLevel::C);
    }

    if let Some(id) = tcx.sess.plugin_registrar_fn.get() {
        let def_id = tcx.hir.local_def_id(id);
        reachable_non_generics.insert(def_id, SymbolExportLevel::C);
    }

    Lrc::new(reachable_non_generics)
}

fn is_reachable_non_generic_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                     def_id: DefId)
                                                     -> bool {
    let export_threshold = threshold(tcx);

    if let Some(&level) = tcx.reachable_non_generics(def_id.krate).get(&def_id) {
        level.is_below_threshold(export_threshold)
    } else {
        false
    }
}

fn is_reachable_non_generic_provider_extern<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                      def_id: DefId)
                                                      -> bool {
    tcx.reachable_non_generics(def_id.krate).contains_key(&def_id)
}

fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                             cnum: CrateNum)
                                             -> Arc<Vec<(ExportedSymbol<'tcx>,
                                                         SymbolExportLevel)>>
{
    assert_eq!(cnum, LOCAL_CRATE);

    if !tcx.sess.opts.output_types.should_trans() {
        return Arc::new(vec![])
    }

    let mut symbols: Vec<_> = tcx.reachable_non_generics(LOCAL_CRATE)
                                 .iter()
                                 .map(|(&def_id, &level)| {
                                    (ExportedSymbol::NonGeneric(def_id), level)
                                 })
                                 .collect();

    if let Some(_) = *tcx.sess.entry_fn.borrow() {
        let symbol_name = "main".to_string();
        let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(&symbol_name));

        symbols.push((exported_symbol, SymbolExportLevel::C));
    }

    if tcx.sess.allocator_kind.get().is_some() {
        for method in ALLOCATOR_METHODS {
            let symbol_name = format!("__rust_{}", method.name);
            let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(&symbol_name));

            symbols.push((exported_symbol, SymbolExportLevel::Rust));
        }
    }

    if tcx.sess.opts.debugging_opts.pgo_gen.is_some() {
        // These are weak symbols that point to the profile version and the
        // profile name, which need to be treated as exported so LTO doesn't nix
        // them.
        const PROFILER_WEAK_SYMBOLS: [&'static str; 2] = [
            "__llvm_profile_raw_version",
            "__llvm_profile_filename",
        ];
        for sym in &PROFILER_WEAK_SYMBOLS {
            let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(sym));
            symbols.push((exported_symbol, SymbolExportLevel::C));
        }
    }

    if tcx.sess.crate_types.borrow().contains(&config::CrateTypeDylib) {
        let symbol_name = metadata_symbol_name(tcx);
        let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(&symbol_name));

        symbols.push((exported_symbol, SymbolExportLevel::Rust));
    }

    // Sort so we get a stable incr. comp. hash.
    symbols.sort_unstable_by(|&(ref symbol1, ..), &(ref symbol2, ..)| {
        symbol1.compare_stable(tcx, symbol2)
    });

    Arc::new(symbols)
}

pub fn provide(providers: &mut Providers) {
    providers.reachable_non_generics = reachable_non_generics_provider;
    providers.is_reachable_non_generic = is_reachable_non_generic_provider_local;
    providers.exported_symbols = exported_symbols_provider_local;
    providers.symbol_export_level = symbol_export_level_provider;
}

pub fn provide_extern(providers: &mut Providers) {
    providers.is_reachable_non_generic = is_reachable_non_generic_provider_extern;
    providers.symbol_export_level = symbol_export_level_provider;
}

fn symbol_export_level_provider(tcx: TyCtxt, sym_def_id: DefId) -> SymbolExportLevel {
    // We export anything that's not mangled at the "C" layer as it probably has
    // to do with ABI concerns. We do not, however, apply such treatment to
    // special symbols in the standard library for various plumbing between
    // core/std/allocators/etc. For example symbols used to hook up allocation
    // are not considered for export
    let trans_fn_attrs = tcx.trans_fn_attrs(sym_def_id);
    let is_extern = trans_fn_attrs.contains_extern_indicator();
    let std_internal = trans_fn_attrs.flags.contains(TransFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL);

    if is_extern && !std_internal {
        SymbolExportLevel::C
    } else {
        SymbolExportLevel::Rust
    }
}
<|endoftext|>


<commit_before><commit_msg>Usefuly read and write implementations to limit and count bytes.<commit_after>use std::io::{self, Read, Write, Result};
use core::ser;

/// A Read implementation that counts the number of bytes consumed from an
/// underlying Read.
pub struct CountingRead<'a> {
	counter: usize,
	source: &'a mut Read,
}

impl<'a> CountingRead<'a> {
	/// Creates a new Read wrapping the underlying one, counting bytes consumed
	pub fn new(source: &mut Read) -> CountingRead {
		CountingRead {
			counter: 0,
			source: source,
		}
	}

	/// Number of bytes that have been read from the underlying reader
	pub fn bytes_read(&self) -> usize {
		self.counter
	}
}

impl<'a> Read for CountingRead<'a> {
	fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
		let r = self.source.read(buf);
		if let Ok(sz) = r {
			self.counter += sz;
		}
		r
	}
}

/// A Read implementation that errors out past a maximum number of bytes read.
pub struct LimitedRead<'a> {
	counter: usize,
	max: usize,
	source: &'a mut Read,
}

impl<'a> LimitedRead<'a> {
	/// Creates a new Read wrapping the underlying one, erroring once the
	/// max_read bytes has been reached.
	pub fn new(source: &mut Read, max_read: usize) -> LimitedRead {
		LimitedRead {
			counter: 0,
			max: max_read,
			source: source,
		}
	}
}

impl<'a> Read for LimitedRead<'a> {
	fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
		let r = self.source.read(buf);
		if let Ok(sz) = r {
			self.counter += sz;
		}
		if self.counter > self.max {
			Err(io::Error::new(io::ErrorKind::Interrupted, "Reached read limit."))
		} else {
			r
		}
	}
}

/// A Write implementation that counts the number of bytes wrote to an
/// underlying Write.
struct CountingWrite<'a> {
	counter: usize,
	dest: &'a mut Write,
}

impl<'a> Write for CountingWrite<'a> {
	fn write(&mut self, buf: &[u8]) -> Result<usize> {
		let w = self.dest.write(buf);
		if let Ok(sz) = w {
			self.counter += sz;
		}
		w
	}
	fn flush(&mut self) -> Result<()> {
		self.dest.flush()
	}
}
<|endoftext|>


<commit_before><commit_msg>Fix(sync): revise fix for unmapped sync files<commit_after><|endoftext|>


<commit_before>// 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 visitor::FmtVisitor;
use utils::*;
use lists::{write_list, ListFormatting, SeparatorTactic, ListTactic};

use syntax::{ast, ptr};
use syntax::codemap::{Pos, Span};
use syntax::parse::token;
use syntax::print::pprust;

use MIN_STRING;

impl<'a> FmtVisitor<'a> {
    // TODO NEEDS TESTS
    fn rewrite_string_lit(&mut self, s: &str, span: Span, width: usize, offset: usize) -> String {
        // FIXME I bet this stomps unicode escapes in the source string

        // Check if there is anything to fix: we always try to fixup multi-line
        // strings, or if the string is too long for the line.
        let l_loc = self.codemap.lookup_char_pos(span.lo);
        let r_loc = self.codemap.lookup_char_pos(span.hi);
        if l_loc.line == r_loc.line && r_loc.col.to_usize() <= config!(max_width) {
            return self.snippet(span);
        }

        // TODO if lo.col > IDEAL - 10, start a new line (need cur indent for that)

        let s = s.escape_default();

        let offset = offset + 1;
        let indent = make_indent(offset);
        let indent = &indent;

        let max_chars = width - 1;

        let mut cur_start = 0;
        let mut result = String::new();
        result.push('"');
        loop {
            let mut cur_end = cur_start + max_chars;

            if cur_end >= s.len() {
                result.push_str(&s[cur_start..]);
                break;
            }

            // Make sure we're on a char boundary.
            cur_end = next_char(&s, cur_end);

            // Push cur_end left until we reach whitespace
            while !s.char_at(cur_end-1).is_whitespace() {
                cur_end = prev_char(&s, cur_end);

                if cur_end - cur_start < MIN_STRING {
                    // We can't break at whitespace, fall back to splitting
                    // anywhere that doesn't break an escape sequence
                    cur_end = next_char(&s, cur_start + max_chars);
                    while s.char_at(cur_end) == '\\' {
                        cur_end = prev_char(&s, cur_end);
                    }
                }
            }
            // Make sure there is no whitespace to the right of the break.
            while cur_end < s.len() && s.char_at(cur_end).is_whitespace() {
                cur_end = next_char(&s, cur_end+1);
            }
            result.push_str(&s[cur_start..cur_end]);
            result.push_str("\\\n");
            result.push_str(indent);

            cur_start = cur_end;
        }
        result.push('"');

        result
    }

    fn rewrite_call(&mut self,
                    callee: &ast::Expr,
                    args: &[ptr::P<ast::Expr>],
                    width: usize,
                    offset: usize)
        -> String
    {
        debug!("rewrite_call, width: {}, offset: {}", width, offset);

        // TODO using byte lens instead of char lens (and probably all over the place too)
        let callee_str = self.rewrite_expr(callee, width, offset);
        debug!("rewrite_call, callee_str: `{}`", callee_str);
        // 2 is for parens.
        let remaining_width = width - callee_str.len() - 2;
        let offset = callee_str.len() + 1 + offset;
        let arg_count = args.len();

        let args_str = if arg_count > 0 {
            let args: Vec<_> = args.iter().map(|e| (self.rewrite_expr(e,
                                                                      remaining_width,
                                                                      offset), String::new())).collect();
            let fmt = ListFormatting {
                tactic: ListTactic::HorizontalVertical,
                separator: ",",
                trailing_separator: SeparatorTactic::Never,
                indent: offset,
                h_width: remaining_width,
                v_width: remaining_width,
            };
            write_list(&args, &fmt)
        } else {
            String::new()
        };

        format!("{}({})", callee_str, args_str)
    }

    fn rewrite_paren(&mut self, subexpr: &ast::Expr, width: usize, offset: usize) -> String {
        debug!("rewrite_paren, width: {}, offset: {}", width, offset);
        // 1 is for opening paren, 2 is for opening+closing, we want to keep the closing
        // paren on the same line as the subexpr
        let subexpr_str = self.rewrite_expr(subexpr, width-2, offset+1);
        debug!("rewrite_paren, subexpr_str: `{}`", subexpr_str);
        format!("({})", subexpr_str)
    }

    fn rewrite_struct_lit(&mut self,
                          path: &ast::Path,
                          fields: &[ast::Field],
                          base: Option<&ast::Expr>,
                          width: usize,
                          offset: usize)
        -> String
    {
        debug!("rewrite_struct_lit: width {}, offset {}", width, offset);
        assert!(fields.len() > 0 || base.is_some());

        let path_str = pprust::path_to_string(path);
        // Foo { a: Foo } - indent is +3, width is -5.
        let indent = offset + path_str.len() + 3;
        let budget = width - (path_str.len() + 5);

        let mut field_strs: Vec<_> =
            fields.iter().map(|f| self.rewrite_field(f, budget, indent)).collect();
        if let Some(expr) = base {
            // Another 2 on the width/indent for the ..
            field_strs.push(format!("..{}", self.rewrite_expr(expr, budget - 2, indent + 2)))
        }

        // FIXME comments
        let field_strs: Vec<_> = field_strs.into_iter().map(|s| (s, String::new())).collect();
        let fmt = ListFormatting {
            tactic: ListTactic::HorizontalVertical,
            separator: ",",
            trailing_separator: if base.is_some() {
                    SeparatorTactic::Never
                } else {
                    config!(struct_lit_trailing_comma)
                },
            indent: indent,
            h_width: budget,
            v_width: budget,
        };
        let fields_str = write_list(&field_strs, &fmt);
        format!("{} {{ {} }}", path_str, fields_str)

        // FIXME if the usual multi-line layout is too wide, we should fall back to
        // Foo {
        //     a: ...,
        // }
    }

    fn rewrite_field(&mut self, field: &ast::Field, width: usize, offset: usize) -> String {
        let name = &token::get_ident(field.ident.node);
        let overhead = name.len() + 2;
        let expr = self.rewrite_expr(&field.expr, width - overhead, offset + overhead);
        format!("{}: {}", name, expr)
    }

    fn rewrite_tuple_lit(&mut self, items: &[ptr::P<ast::Expr>], width: usize, offset: usize)
        -> String {
        // opening paren
        let indent = offset + 1;
        // In case of length 1, need a trailing comma
        if items.len() == 1 {
            return format!("({},)", self.rewrite_expr(&*items[0], width - 3, indent));
        }
        // Only last line has width-1 as budget, other may take max_width
        let item_strs: Vec<_> =
            items.iter()
                 .enumerate()
                 .map(|(i, item)| self.rewrite_expr(
                    item,
                    // last line : given width (minus "("+")"), other lines : max_width
                    // (minus "("+","))
                    if i == items.len() - 1 { width - 2 } else { config!(max_width) - indent - 2 },
                    indent))
                 .collect();
        let tactics = if item_strs.iter().any(|s| s.contains('\n')) {
            ListTactic::Vertical
        } else {
            ListTactic::HorizontalVertical
        };
        // FIXME handle comments
        let item_strs: Vec<_> = item_strs.into_iter().map(|s| (s, String::new())).collect();
        let fmt = ListFormatting {
            tactic: tactics,
            separator: ",",
            trailing_separator: SeparatorTactic::Never,
            indent: indent,
            h_width: width - 2,
            v_width: width - 2,
        };
        let item_str = write_list(&item_strs, &fmt);
        format!("({})", item_str)
    }

    pub fn rewrite_expr(&mut self, expr: &ast::Expr, width: usize, offset: usize) -> String {
        match expr.node {
            ast::Expr_::ExprLit(ref l) => {
                match l.node {
                    ast::Lit_::LitStr(ref is, _) => {
                        let result = self.rewrite_string_lit(&is, l.span, width, offset);
                        debug!("string lit: `{}`", result);
                        return result;
                    }
                    _ => {}
                }
            }
            ast::Expr_::ExprCall(ref callee, ref args) => {
                return self.rewrite_call(callee, args, width, offset);
            }
            ast::Expr_::ExprParen(ref subexpr) => {
                return self.rewrite_paren(subexpr, width, offset);
            }
            ast::Expr_::ExprStruct(ref path, ref fields, ref base) => {
                return self.rewrite_struct_lit(path,
                                               fields,
                                               base.as_ref().map(|e| &**e),
                                               width,
                                               offset);
            }
            ast::Expr_::ExprTup(ref items) => {
                return self.rewrite_tuple_lit(items, width, offset);
            }
            _ => {}
        }

        self.snippet(expr.span)
    }
}
<commit_msg>Fix off-by-one bugs in `rewrite_string_lit`<commit_after>// 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 visitor::FmtVisitor;
use utils::*;
use lists::{write_list, ListFormatting, SeparatorTactic, ListTactic};

use syntax::{ast, ptr};
use syntax::codemap::{Pos, Span};
use syntax::parse::token;
use syntax::print::pprust;

use MIN_STRING;

impl<'a> FmtVisitor<'a> {
    fn rewrite_string_lit(&mut self, s: &str, span: Span, width: usize, offset: usize) -> String {
        // FIXME I bet this stomps unicode escapes in the source string

        // Check if there is anything to fix: we always try to fixup multi-line
        // strings, or if the string is too long for the line.
        let l_loc = self.codemap.lookup_char_pos(span.lo);
        let r_loc = self.codemap.lookup_char_pos(span.hi);
        if l_loc.line == r_loc.line && r_loc.col.to_usize() <= config!(max_width) {
            return self.snippet(span);
        }

        // TODO if lo.col > IDEAL - 10, start a new line (need cur indent for that)

        let s = s.escape_default();

        let offset = offset + 1;
        let indent = make_indent(offset);
        let indent = &indent;

        let mut cur_start = 0;
        let mut result = String::with_capacity(round_up_to_power_of_two(s.len()));
        result.push('"');
        loop {
            let max_chars = if cur_start == 0 {
                // First line.
                width - 2 // 2 = " + \
            } else {
                config!(max_width) - offset - 1 // 1 = either \ or ;
            };

            let mut cur_end = cur_start + max_chars;

            if cur_end >= s.len() {
                result.push_str(&s[cur_start..]);
                break;
            }

            // Make sure we're on a char boundary.
            cur_end = next_char(&s, cur_end);

            // Push cur_end left until we reach whitespace
            while !s.char_at(cur_end-1).is_whitespace() {
                cur_end = prev_char(&s, cur_end);

                if cur_end - cur_start < MIN_STRING {
                    // We can't break at whitespace, fall back to splitting
                    // anywhere that doesn't break an escape sequence
                    cur_end = next_char(&s, cur_start + max_chars);
                    while s.char_at(prev_char(&s, cur_end)) == '\\' {
                        cur_end = prev_char(&s, cur_end);
                    }
                    break;
                }
            }
            // Make sure there is no whitespace to the right of the break.
            while cur_end < s.len() && s.char_at(cur_end).is_whitespace() {
                cur_end = next_char(&s, cur_end+1);
            }
            result.push_str(&s[cur_start..cur_end]);
            result.push_str("\\\n");
            result.push_str(indent);

            cur_start = cur_end;
        }
        result.push('"');

        result
    }

    fn rewrite_call(&mut self,
                    callee: &ast::Expr,
                    args: &[ptr::P<ast::Expr>],
                    width: usize,
                    offset: usize)
        -> String
    {
        debug!("rewrite_call, width: {}, offset: {}", width, offset);

        // TODO using byte lens instead of char lens (and probably all over the place too)
        let callee_str = self.rewrite_expr(callee, width, offset);
        debug!("rewrite_call, callee_str: `{}`", callee_str);
        // 2 is for parens.
        let remaining_width = width - callee_str.len() - 2;
        let offset = callee_str.len() + 1 + offset;
        let arg_count = args.len();

        let args_str = if arg_count > 0 {
            let args: Vec<_> = args.iter().map(|e| (self.rewrite_expr(e,
                                                                      remaining_width,
                                                                      offset), String::new())).collect();
            let fmt = ListFormatting {
                tactic: ListTactic::HorizontalVertical,
                separator: ",",
                trailing_separator: SeparatorTactic::Never,
                indent: offset,
                h_width: remaining_width,
                v_width: remaining_width,
            };
            write_list(&args, &fmt)
        } else {
            String::new()
        };

        format!("{}({})", callee_str, args_str)
    }

    fn rewrite_paren(&mut self, subexpr: &ast::Expr, width: usize, offset: usize) -> String {
        debug!("rewrite_paren, width: {}, offset: {}", width, offset);
        // 1 is for opening paren, 2 is for opening+closing, we want to keep the closing
        // paren on the same line as the subexpr
        let subexpr_str = self.rewrite_expr(subexpr, width-2, offset+1);
        debug!("rewrite_paren, subexpr_str: `{}`", subexpr_str);
        format!("({})", subexpr_str)
    }

    fn rewrite_struct_lit(&mut self,
                          path: &ast::Path,
                          fields: &[ast::Field],
                          base: Option<&ast::Expr>,
                          width: usize,
                          offset: usize)
        -> String
    {
        debug!("rewrite_struct_lit: width {}, offset {}", width, offset);
        assert!(fields.len() > 0 || base.is_some());

        let path_str = pprust::path_to_string(path);
        // Foo { a: Foo } - indent is +3, width is -5.
        let indent = offset + path_str.len() + 3;
        let budget = width - (path_str.len() + 5);

        let mut field_strs: Vec<_> =
            fields.iter().map(|f| self.rewrite_field(f, budget, indent)).collect();
        if let Some(expr) = base {
            // Another 2 on the width/indent for the ..
            field_strs.push(format!("..{}", self.rewrite_expr(expr, budget - 2, indent + 2)))
        }

        // FIXME comments
        let field_strs: Vec<_> = field_strs.into_iter().map(|s| (s, String::new())).collect();
        let fmt = ListFormatting {
            tactic: ListTactic::HorizontalVertical,
            separator: ",",
            trailing_separator: if base.is_some() {
                    SeparatorTactic::Never
                } else {
                    config!(struct_lit_trailing_comma)
                },
            indent: indent,
            h_width: budget,
            v_width: budget,
        };
        let fields_str = write_list(&field_strs, &fmt);
        format!("{} {{ {} }}", path_str, fields_str)

        // FIXME if the usual multi-line layout is too wide, we should fall back to
        // Foo {
        //     a: ...,
        // }
    }

    fn rewrite_field(&mut self, field: &ast::Field, width: usize, offset: usize) -> String {
        let name = &token::get_ident(field.ident.node);
        let overhead = name.len() + 2;
        let expr = self.rewrite_expr(&field.expr, width - overhead, offset + overhead);
        format!("{}: {}", name, expr)
    }

    fn rewrite_tuple_lit(&mut self, items: &[ptr::P<ast::Expr>], width: usize, offset: usize)
        -> String {
        // opening paren
        let indent = offset + 1;
        // In case of length 1, need a trailing comma
        if items.len() == 1 {
            return format!("({},)", self.rewrite_expr(&*items[0], width - 3, indent));
        }
        // Only last line has width-1 as budget, other may take max_width
        let item_strs: Vec<_> =
            items.iter()
                 .enumerate()
                 .map(|(i, item)| self.rewrite_expr(
                    item,
                    // last line : given width (minus "("+")"), other lines : max_width
                    // (minus "("+","))
                    if i == items.len() - 1 { width - 2 } else { config!(max_width) - indent - 2 },
                    indent))
                 .collect();
        let tactics = if item_strs.iter().any(|s| s.contains('\n')) {
            ListTactic::Vertical
        } else {
            ListTactic::HorizontalVertical
        };
        // FIXME handle comments
        let item_strs: Vec<_> = item_strs.into_iter().map(|s| (s, String::new())).collect();
        let fmt = ListFormatting {
            tactic: tactics,
            separator: ",",
            trailing_separator: SeparatorTactic::Never,
            indent: indent,
            h_width: width - 2,
            v_width: width - 2,
        };
        let item_str = write_list(&item_strs, &fmt);
        format!("({})", item_str)
    }

    pub fn rewrite_expr(&mut self, expr: &ast::Expr, width: usize, offset: usize) -> String {
        match expr.node {
            ast::Expr_::ExprLit(ref l) => {
                match l.node {
                    ast::Lit_::LitStr(ref is, _) => {
                        let result = self.rewrite_string_lit(&is, l.span, width, offset);
                        debug!("string lit: `{}`", result);
                        return result;
                    }
                    _ => {}
                }
            }
            ast::Expr_::ExprCall(ref callee, ref args) => {
                return self.rewrite_call(callee, args, width, offset);
            }
            ast::Expr_::ExprParen(ref subexpr) => {
                return self.rewrite_paren(subexpr, width, offset);
            }
            ast::Expr_::ExprStruct(ref path, ref fields, ref base) => {
                return self.rewrite_struct_lit(path,
                                               fields,
                                               base.as_ref().map(|e| &**e),
                                               width,
                                               offset);
            }
            ast::Expr_::ExprTup(ref items) => {
                return self.rewrite_tuple_lit(items, width, offset);
            }
            _ => {}
        }

        self.snippet(expr.span)
    }
}
<|endoftext|>


<commit_before><commit_msg>genet-abi: add genet_abi_version_marker__<commit_after><|endoftext|>


<commit_before><commit_msg>hook: in debug, tell the hook we are executing<commit_after><|endoftext|>


<commit_before><commit_msg>Use a custom enum rather than strings for IDNA errors<commit_after><|endoftext|>


<commit_before><commit_msg>Add tests for ensuring docblock headings.<commit_after>#![crate_name = "foo"]

// @has foo/trait.Read.html
// @has - '//h2' 'Trait examples'
/// # Trait examples
pub trait Read {
    // @has - '//h5' 'Function examples'
    /// # Function examples
    fn read(&mut self, buf: &mut [u8]) -> Result<usize, ()>;
}

pub struct Foo;

// @has foo/struct.Foo.html
impl Foo {
    // @has - '//h5' 'Implementation header'
    /// # Implementation header
    pub fn bar(&self) -> usize {
        1
    }
}

impl Read for Foo {
    // @has - '//h5' 'Trait implementation header'
    /// # Trait implementation header
    fn read(&mut self, buf: &mut [u8]) -> Result<usize, ()> {
        Ok(1)
    }
}
<|endoftext|>


<commit_before><commit_msg>Remove unused `use`.<commit_after><|endoftext|>


<commit_before><commit_msg>random limits<commit_after><|endoftext|>