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

use core::prelude::*;

use back::link::mangle_exported_name;
use middle::trans::base::{get_insn_ctxt};
use middle::trans::base::{set_inline_hint_if_appr, set_inline_hint};
use middle::trans::base::{trans_enum_variant, trans_struct_dtor};
use middle::trans::base::{trans_fn, impl_self, decl_internal_cdecl_fn};
use middle::trans::base::{trans_item, get_item_val, no_self, self_arg};
use middle::trans::base;
use middle::trans::common::*;
use middle::trans::datum;
use middle::trans::foreign;
use middle::trans::machine;
use middle::trans::meth;
use middle::trans::shape;
use middle::trans::type_of::type_of_fn_from_ty;
use middle::trans::type_of;
use middle::trans::type_use;
use middle::ty::{FnSig};
use middle::typeck;

use core::option;
use core::vec;
use syntax::ast;
use syntax::ast_map::{path, path_mod, path_name};
use syntax::ast_util::local_def;
use syntax::parse::token::special_idents;

pub fn monomorphic_fn(ccx: @CrateContext,
                      fn_id: ast::def_id,
                      real_substs: ~[ty::t],
                      vtables: Option<typeck::vtable_res>,
                      impl_did_opt: Option<ast::def_id>,
                      ref_id: Option<ast::node_id>) ->
                      (ValueRef, bool) {
    let _icx = ccx.insn_ctxt("monomorphic_fn");
    let mut must_cast = false;
    let substs = vec::map(real_substs, |t| {
        match normalize_for_monomorphization(ccx.tcx, *t) {
          Some(t) => { must_cast = true; t }
          None => *t
        }
    });

    for real_substs.each() |s| { assert !ty::type_has_params(*s); }
    for substs.each() |s| { assert !ty::type_has_params(*s); }
    let param_uses = type_use::type_uses_for(ccx, fn_id, substs.len());
    // XXX: Bad copy.
    let hash_id = make_mono_id(ccx, fn_id, copy substs, vtables, impl_did_opt,
                               Some(param_uses));
    if vec::any(hash_id.params,
                |p| match *p { mono_precise(_, _) => false, _ => true }) {
        must_cast = true;
    }

    debug!("monomorphic_fn(fn_id=%? (%s), real_substs=%?, substs=%?, \
           hash_id = %?",
           fn_id, ty::item_path_str(ccx.tcx, fn_id),
           real_substs.map(|s| ty_to_str(ccx.tcx, *s)),
           substs.map(|s| ty_to_str(ccx.tcx, *s)), hash_id);

    match ccx.monomorphized.find(&hash_id) {
      Some(val) => {
        debug!("leaving monomorphic fn %s",
               ty::item_path_str(ccx.tcx, fn_id));
        return (val, must_cast);
      }
      None => ()
    }

    let tpt = ty::lookup_item_type(ccx.tcx, fn_id);
    let mut llitem_ty = tpt.ty;

    let map_node = session::expect(ccx.sess, ccx.tcx.items.find(&fn_id.node),
     || fmt!("While monomorphizing %?, couldn't find it in the item map \
        (may have attempted to monomorphize an item defined in a different \
        crate?)", fn_id));
    // Get the path so that we can create a symbol
    let (pt, name, span) = match map_node {
      ast_map::node_item(i, pt) => (pt, i.ident, i.span),
      ast_map::node_variant(ref v, enm, pt) => (pt, (*v).node.name, enm.span),
      ast_map::node_method(m, _, pt) => (pt, m.ident, m.span),
      ast_map::node_foreign_item(i, ast::foreign_abi_rust_intrinsic, pt)
      => (pt, i.ident, i.span),
      ast_map::node_foreign_item(*) => {
        // Foreign externs don't have to be monomorphized.
        return (get_item_val(ccx, fn_id.node), true);
      }
      ast_map::node_dtor(_, dtor, _, pt) =>
          (pt, special_idents::dtor, dtor.span),
      ast_map::node_trait_method(@ast::provided(m), _, pt) => {
        (pt, m.ident, m.span)
      }
      ast_map::node_trait_method(@ast::required(_), _, _) => {
        ccx.tcx.sess.bug(~"Can't monomorphize a required trait method")
      }
      ast_map::node_expr(*) => {
        ccx.tcx.sess.bug(~"Can't monomorphize an expr")
      }
      ast_map::node_stmt(*) => {
        ccx.tcx.sess.bug(~"Can't monomorphize a stmt")
      }
      ast_map::node_arg(*) => ccx.tcx.sess.bug(~"Can't monomorphize an arg"),
      ast_map::node_block(*) => {
          ccx.tcx.sess.bug(~"Can't monomorphize a block")
      }
      ast_map::node_local(*) => {
          ccx.tcx.sess.bug(~"Can't monomorphize a local")
      }
      ast_map::node_struct_ctor(_, i, pt) => (pt, i.ident, i.span)
    };

    // Look up the impl type if we're translating a default method.
    // XXX: Generics.
    let impl_ty_opt;
    match impl_did_opt {
        None => impl_ty_opt = None,
        Some(impl_did) => {
            impl_ty_opt = Some(ty::lookup_item_type(ccx.tcx, impl_did).ty);
        }
    }

    let mono_ty = ty::subst_tps(ccx.tcx, substs, impl_ty_opt, llitem_ty);
    let llfty = type_of_fn_from_ty(ccx, mono_ty);

    ccx.stats.n_monos += 1;

    let depth = option::get_or_default(ccx.monomorphizing.find(&fn_id), 0u);
    // Random cut-off -- code that needs to instantiate the same function
    // recursively more than ten times can probably safely be assumed to be
    // causing an infinite expansion.
    if depth > 10 {
        ccx.sess.span_fatal(
            span, ~"overly deep expansion of inlined function");
    }
    ccx.monomorphizing.insert(fn_id, depth + 1);

    let pt = vec::append(/*bad*/copy *pt,
                         ~[path_name((ccx.names)(*ccx.sess.str_of(name)))]);
    let s = mangle_exported_name(ccx, /*bad*/copy pt, mono_ty);

    let mk_lldecl = || {
        let lldecl = decl_internal_cdecl_fn(ccx.llmod, /*bad*/copy s, llfty);
        ccx.monomorphized.insert(hash_id, lldecl);
        lldecl
    };

    let psubsts = Some(@param_substs {
        tys: substs,
        vtables: vtables,
        bounds: tpt.bounds,
        self_ty: impl_ty_opt
    });

    let lldecl = match map_node {
      ast_map::node_item(i@@ast::item {
                // XXX: Bad copy.<commit_msg>bump up limit on monomorphization<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use core::prelude::*;

use back::link::mangle_exported_name;
use middle::trans::base::{get_insn_ctxt};
use middle::trans::base::{set_inline_hint_if_appr, set_inline_hint};
use middle::trans::base::{trans_enum_variant, trans_struct_dtor};
use middle::trans::base::{trans_fn, impl_self, decl_internal_cdecl_fn};
use middle::trans::base::{trans_item, get_item_val, no_self, self_arg};
use middle::trans::base;
use middle::trans::common::*;
use middle::trans::datum;
use middle::trans::foreign;
use middle::trans::machine;
use middle::trans::meth;
use middle::trans::shape;
use middle::trans::type_of::type_of_fn_from_ty;
use middle::trans::type_of;
use middle::trans::type_use;
use middle::ty::{FnSig};
use middle::typeck;

use core::option;
use core::vec;
use syntax::ast;
use syntax::ast_map::{path, path_mod, path_name};
use syntax::ast_util::local_def;
use syntax::parse::token::special_idents;

pub fn monomorphic_fn(ccx: @CrateContext,
                      fn_id: ast::def_id,
                      real_substs: ~[ty::t],
                      vtables: Option<typeck::vtable_res>,
                      impl_did_opt: Option<ast::def_id>,
                      ref_id: Option<ast::node_id>) ->
                      (ValueRef, bool) {
    let _icx = ccx.insn_ctxt("monomorphic_fn");
    let mut must_cast = false;
    let substs = vec::map(real_substs, |t| {
        match normalize_for_monomorphization(ccx.tcx, *t) {
          Some(t) => { must_cast = true; t }
          None => *t
        }
    });

    for real_substs.each() |s| { assert !ty::type_has_params(*s); }
    for substs.each() |s| { assert !ty::type_has_params(*s); }
    let param_uses = type_use::type_uses_for(ccx, fn_id, substs.len());
    // XXX: Bad copy.
    let hash_id = make_mono_id(ccx, fn_id, copy substs, vtables, impl_did_opt,
                               Some(param_uses));
    if vec::any(hash_id.params,
                |p| match *p { mono_precise(_, _) => false, _ => true }) {
        must_cast = true;
    }

    debug!("monomorphic_fn(fn_id=%? (%s), real_substs=%?, substs=%?, \
           hash_id = %?",
           fn_id, ty::item_path_str(ccx.tcx, fn_id),
           real_substs.map(|s| ty_to_str(ccx.tcx, *s)),
           substs.map(|s| ty_to_str(ccx.tcx, *s)), hash_id);

    match ccx.monomorphized.find(&hash_id) {
      Some(val) => {
        debug!("leaving monomorphic fn %s",
               ty::item_path_str(ccx.tcx, fn_id));
        return (val, must_cast);
      }
      None => ()
    }

    let tpt = ty::lookup_item_type(ccx.tcx, fn_id);
    let mut llitem_ty = tpt.ty;

    let map_node = session::expect(ccx.sess, ccx.tcx.items.find(&fn_id.node),
     || fmt!("While monomorphizing %?, couldn't find it in the item map \
        (may have attempted to monomorphize an item defined in a different \
        crate?)", fn_id));
    // Get the path so that we can create a symbol
    let (pt, name, span) = match map_node {
      ast_map::node_item(i, pt) => (pt, i.ident, i.span),
      ast_map::node_variant(ref v, enm, pt) => (pt, (*v).node.name, enm.span),
      ast_map::node_method(m, _, pt) => (pt, m.ident, m.span),
      ast_map::node_foreign_item(i, ast::foreign_abi_rust_intrinsic, pt)
      => (pt, i.ident, i.span),
      ast_map::node_foreign_item(*) => {
        // Foreign externs don't have to be monomorphized.
        return (get_item_val(ccx, fn_id.node), true);
      }
      ast_map::node_dtor(_, dtor, _, pt) =>
          (pt, special_idents::dtor, dtor.span),
      ast_map::node_trait_method(@ast::provided(m), _, pt) => {
        (pt, m.ident, m.span)
      }
      ast_map::node_trait_method(@ast::required(_), _, _) => {
        ccx.tcx.sess.bug(~"Can't monomorphize a required trait method")
      }
      ast_map::node_expr(*) => {
        ccx.tcx.sess.bug(~"Can't monomorphize an expr")
      }
      ast_map::node_stmt(*) => {
        ccx.tcx.sess.bug(~"Can't monomorphize a stmt")
      }
      ast_map::node_arg(*) => ccx.tcx.sess.bug(~"Can't monomorphize an arg"),
      ast_map::node_block(*) => {
          ccx.tcx.sess.bug(~"Can't monomorphize a block")
      }
      ast_map::node_local(*) => {
          ccx.tcx.sess.bug(~"Can't monomorphize a local")
      }
      ast_map::node_struct_ctor(_, i, pt) => (pt, i.ident, i.span)
    };

    // Look up the impl type if we're translating a default method.
    // XXX: Generics.
    let impl_ty_opt;
    match impl_did_opt {
        None => impl_ty_opt = None,
        Some(impl_did) => {
            impl_ty_opt = Some(ty::lookup_item_type(ccx.tcx, impl_did).ty);
        }
    }

    let mono_ty = ty::subst_tps(ccx.tcx, substs, impl_ty_opt, llitem_ty);
    let llfty = type_of_fn_from_ty(ccx, mono_ty);

    ccx.stats.n_monos += 1;

    let depth = option::get_or_default(ccx.monomorphizing.find(&fn_id), 0u);
    // Random cut-off -- code that needs to instantiate the same function
    // recursively more than thirty times can probably safely be assumed to be
    // causing an infinite expansion.
    if depth > 30 {
        ccx.sess.span_fatal(
            span, ~"overly deep expansion of inlined function");
    }
    ccx.monomorphizing.insert(fn_id, depth + 1);

    let pt = vec::append(/*bad*/copy *pt,
                         ~[path_name((ccx.names)(*ccx.sess.str_of(name)))]);
    let s = mangle_exported_name(ccx, /*bad*/copy pt, mono_ty);

    let mk_lldecl = || {
        let lldecl = decl_internal_cdecl_fn(ccx.llmod, /*bad*/copy s, llfty);
        ccx.monomorphized.insert(hash_id, lldecl);
        lldecl
    };

    let psubsts = Some(@param_substs {
        tys: substs,
        vtables: vtables,
        bounds: tpt.bounds,
        self_ty: impl_ty_opt
    });

    let lldecl = match map_node {
      ast_map::node_item(i@@ast::item {
                // XXX: Bad copy.
{'fraction_non_alphanumeric': 0.15088639796486208, 'fraction_numerical': 0.002066936958422768, 'mean_word_length': 2.8248707813925207, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 61, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3213203', 'n_tokens_mistral': 4523, 'n_tokens_neox': 4464, 'n_words': 943}