2014-08-01 23:25:41 -05:00
|
|
|
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
2012-12-03 18:48:01 -06:00
|
|
|
// 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.
|
|
|
|
|
2014-03-31 16:43:19 -05:00
|
|
|
use back::link::exported_name;
|
2014-11-15 19:30:33 -06:00
|
|
|
use session;
|
2014-07-07 19:58:01 -05:00
|
|
|
use llvm::ValueRef;
|
2014-08-01 14:27:12 -05:00
|
|
|
use llvm;
|
2014-12-17 13:16:28 -06:00
|
|
|
use middle::infer;
|
2014-05-13 10:35:42 -05:00
|
|
|
use middle::subst;
|
2014-12-17 13:16:28 -06:00
|
|
|
use middle::subst::{Subst, Substs};
|
|
|
|
use middle::traits;
|
2014-12-30 16:42:02 -06:00
|
|
|
use middle::ty_fold::{TypeFolder, TypeFoldable};
|
2014-11-15 19:30:33 -06:00
|
|
|
use trans::base::{set_llvm_fn_attrs, set_inline_hint};
|
|
|
|
use trans::base::{trans_enum_variant, push_ctxt, get_item_val};
|
|
|
|
use trans::base::{trans_fn, decl_internal_rust_fn};
|
|
|
|
use trans::base;
|
|
|
|
use trans::common::*;
|
|
|
|
use trans::foreign;
|
2015-01-03 21:42:21 -06:00
|
|
|
use middle::ty::{self, HasProjectionTypes, Ty};
|
2013-09-26 15:54:15 -05:00
|
|
|
use util::ppaux::Repr;
|
2012-12-13 15:05:22 -06:00
|
|
|
|
2014-04-02 03:19:41 -05:00
|
|
|
use syntax::abi;
|
2012-08-28 17:54:45 -05:00
|
|
|
use syntax::ast;
|
2013-02-25 13:11:21 -06:00
|
|
|
use syntax::ast_map;
|
2014-07-14 18:31:52 -05:00
|
|
|
use syntax::ast_util::{local_def, PostExpansionMethod};
|
2014-08-01 14:27:12 -05:00
|
|
|
use syntax::attr;
|
2014-12-31 13:42:06 -06:00
|
|
|
use syntax::codemap::DUMMY_SP;
|
std: Stabilize the std::hash module
This commit aims to prepare the `std::hash` module for alpha by formalizing its
current interface whileholding off on adding `#[stable]` to the new APIs. The
current usage with the `HashMap` and `HashSet` types is also reconciled by
separating out composable parts of the design. The primary goal of this slight
redesign is to separate the concepts of a hasher's state from a hashing
algorithm itself.
The primary change of this commit is to separate the `Hasher` trait into a
`Hasher` and a `HashState` trait. Conceptually the old `Hasher` trait was
actually just a factory for various states, but hashing had very little control
over how these states were used. Additionally the old `Hasher` trait was
actually fairly unrelated to hashing.
This commit redesigns the existing `Hasher` trait to match what the notion of a
`Hasher` normally implies with the following definition:
trait Hasher {
type Output;
fn reset(&mut self);
fn finish(&self) -> Output;
}
This `Hasher` trait emphasizes that hashing algorithms may produce outputs other
than a `u64`, so the output type is made generic. Other than that, however, very
little is assumed about a particular hasher. It is left up to implementors to
provide specific methods or trait implementations to feed data into a hasher.
The corresponding `Hash` trait becomes:
trait Hash<H: Hasher> {
fn hash(&self, &mut H);
}
The old default of `SipState` was removed from this trait as it's not something
that we're willing to stabilize until the end of time, but the type parameter is
always required to implement `Hasher`. Note that the type parameter `H` remains
on the trait to enable multidispatch for specialization of hashing for
particular hashers.
Note that `Writer` is not mentioned in either of `Hash` or `Hasher`, it is
simply used as part `derive` and the implementations for all primitive types.
With these definitions, the old `Hasher` trait is realized as a new `HashState`
trait in the `collections::hash_state` module as an unstable addition for
now. The current definition looks like:
trait HashState {
type Hasher: Hasher;
fn hasher(&self) -> Hasher;
}
The purpose of this trait is to emphasize that the one piece of functionality
for implementors is that new instances of `Hasher` can be created. This
conceptually represents the two keys from which more instances of a
`SipHasher` can be created, and a `HashState` is what's stored in a
`HashMap`, not a `Hasher`.
Implementors of custom hash algorithms should implement the `Hasher` trait, and
only hash algorithms intended for use in hash maps need to implement or worry
about the `HashState` trait.
The entire module and `HashState` infrastructure remains `#[unstable]` due to it
being recently redesigned, but some other stability decision made for the
`std::hash` module are:
* The `Writer` trait remains `#[experimental]` as it's intended to be replaced
with an `io::Writer` (more details soon).
* The top-level `hash` function is `#[unstable]` as it is intended to be generic
over the hashing algorithm instead of hardwired to `SipHasher`
* The inner `sip` module is now private as its one export, `SipHasher` is
reexported in the `hash` module.
And finally, a few changes were made to the default parameters on `HashMap`.
* The `RandomSipHasher` default type parameter was renamed to `RandomState`.
This renaming emphasizes that it is not a hasher, but rather just state to
generate hashers. It also moves away from the name "sip" as it may not always
be implemented as `SipHasher`. This type lives in the
`std::collections::hash_map` module as `#[unstable]`
* The associated `Hasher` type of `RandomState` is creatively called...
`Hasher`! This concrete structure lives next to `RandomState` as an
implemenation of the "default hashing algorithm" used for a `HashMap`. Under
the hood this is currently implemented as `SipHasher`, but it draws an
explicit interface for now and allows us to modify the implementation over
time if necessary.
There are many breaking changes outlined above, and as a result this commit is
a:
[breaking-change]
2014-12-09 14:37:23 -06:00
|
|
|
use std::hash::{Hasher, Hash, SipHasher};
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2014-09-29 14:11:30 -05:00
|
|
|
pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|
|
|
fn_id: ast::DefId,
|
2014-11-06 01:24:44 -06:00
|
|
|
psubsts: &subst::Substs<'tcx>,
|
2014-09-29 14:11:30 -05:00
|
|
|
ref_id: Option<ast::NodeId>)
|
2015-01-04 10:47:58 -06:00
|
|
|
-> (ValueRef, Ty<'tcx>, bool) {
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("monomorphic_fn(\
|
2013-09-28 00:38:08 -05:00
|
|
|
fn_id={}, \
|
|
|
|
real_substs={}, \
|
2014-12-20 02:09:35 -06:00
|
|
|
ref_id={:?})",
|
2014-03-15 15:29:34 -05:00
|
|
|
fn_id.repr(ccx.tcx()),
|
2014-11-06 01:24:44 -06:00
|
|
|
psubsts.repr(ccx.tcx()),
|
Cleanup substitutions and treatment of generics around traits in a number of ways.
- In a TraitRef, use the self type consistently to refer to the Self type:
- trait ref in `impl Trait<A,B,C> for S` has a self type of `S`.
- trait ref in `A:Trait` has the self type `A`
- trait ref associated with a trait decl has self type `Self`
- trait ref associated with a supertype has self type `Self`
- trait ref in an object type `@Trait` has no self type
- Rewrite `each_bound_traits_and_supertraits` to perform
substitutions as it goes, and thus yield a series of trait refs
that are always in the same 'namespace' as the type parameter
bound given as input. Before, we left this to the caller, but
this doesn't work because the caller lacks adequare information
to perform the type substitutions correctly.
- For provided methods, substitute the generics involved in the provided
method correctly.
- Introduce TypeParameterDef, which tracks the bounds declared on a type
parameter and brings them together with the def_id and (in the future)
other information (maybe even the parameter's name!).
- Introduce Subst trait, which helps to cleanup a lot of the
repetitive code involved with doing type substitution.
- Introduce Repr trait, which makes debug printouts far more convenient.
Fixes #4183. Needed for #5656.
2013-04-09 00:54:49 -05:00
|
|
|
ref_id);
|
|
|
|
|
2014-11-06 01:24:44 -06:00
|
|
|
assert!(psubsts.types.all(|t| {
|
2014-04-20 11:09:11 -05:00
|
|
|
!ty::type_needs_infer(*t) && !ty::type_has_params(*t)
|
|
|
|
}));
|
|
|
|
|
2013-06-16 23:23:24 -05:00
|
|
|
let _icx = push_ctxt("monomorphic_fn");
|
2013-07-08 19:28:36 -05:00
|
|
|
|
2014-04-20 11:29:56 -05:00
|
|
|
let hash_id = MonoId {
|
2014-04-20 11:09:11 -05:00
|
|
|
def: fn_id,
|
2014-11-06 01:24:44 -06:00
|
|
|
params: psubsts.types.clone()
|
2014-04-20 11:09:11 -05:00
|
|
|
};
|
|
|
|
|
2015-01-04 10:47:58 -06:00
|
|
|
let item_ty = ty::lookup_item_type(ccx.tcx(), fn_id).ty;
|
|
|
|
let mono_ty = item_ty.subst(ccx.tcx(), psubsts);
|
|
|
|
|
2014-11-06 11:25:16 -06:00
|
|
|
match ccx.monomorphized().borrow().get(&hash_id) {
|
2014-04-20 11:09:11 -05:00
|
|
|
Some(&val) => {
|
|
|
|
debug!("leaving monomorphic fn {}",
|
|
|
|
ty::item_path_str(ccx.tcx(), fn_id));
|
2015-01-04 10:47:58 -06:00
|
|
|
return (val, mono_ty, false);
|
2014-04-20 11:09:11 -05:00
|
|
|
}
|
|
|
|
None => ()
|
|
|
|
}
|
|
|
|
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("monomorphic_fn(\
|
2013-09-28 00:38:08 -05:00
|
|
|
fn_id={}, \
|
|
|
|
psubsts={}, \
|
2014-12-20 02:09:35 -06:00
|
|
|
hash_id={:?})",
|
2014-03-15 15:29:34 -05:00
|
|
|
fn_id.repr(ccx.tcx()),
|
|
|
|
psubsts.repr(ccx.tcx()),
|
Cleanup substitutions and treatment of generics around traits in a number of ways.
- In a TraitRef, use the self type consistently to refer to the Self type:
- trait ref in `impl Trait<A,B,C> for S` has a self type of `S`.
- trait ref in `A:Trait` has the self type `A`
- trait ref associated with a trait decl has self type `Self`
- trait ref associated with a supertype has self type `Self`
- trait ref in an object type `@Trait` has no self type
- Rewrite `each_bound_traits_and_supertraits` to perform
substitutions as it goes, and thus yield a series of trait refs
that are always in the same 'namespace' as the type parameter
bound given as input. Before, we left this to the caller, but
this doesn't work because the caller lacks adequare information
to perform the type substitutions correctly.
- For provided methods, substitute the generics involved in the provided
method correctly.
- Introduce TypeParameterDef, which tracks the bounds declared on a type
parameter and brings them together with the def_id and (in the future)
other information (maybe even the parameter's name!).
- Introduce Subst trait, which helps to cleanup a lot of the
repetitive code involved with doing type substitution.
- Introduce Repr trait, which makes debug printouts far more convenient.
Fixes #4183. Needed for #5656.
2013-04-09 00:54:49 -05:00
|
|
|
hash_id);
|
2012-08-28 17:54:45 -05:00
|
|
|
|
|
|
|
|
2014-02-13 23:07:09 -06:00
|
|
|
let map_node = session::expect(
|
2014-03-05 08:36:01 -06:00
|
|
|
ccx.sess(),
|
2014-09-05 11:18:53 -05:00
|
|
|
ccx.tcx().map.find(fn_id.node),
|
2014-05-07 18:33:43 -05:00
|
|
|
|| {
|
2014-12-20 02:09:35 -06:00
|
|
|
format!("while monomorphizing {:?}, couldn't find it in \
|
2014-05-27 22:44:58 -05:00
|
|
|
the item map (may have attempted to monomorphize \
|
|
|
|
an item defined in a different crate?)",
|
|
|
|
fn_id)
|
2014-05-07 18:33:43 -05:00
|
|
|
});
|
2013-12-27 18:09:29 -06:00
|
|
|
|
2014-11-29 15:41:21 -06:00
|
|
|
if let ast_map::NodeForeignItem(_) = map_node {
|
|
|
|
if ccx.tcx().map.get_foreign_abi(fn_id.node) != abi::RustIntrinsic {
|
|
|
|
// Foreign externs don't have to be monomorphized.
|
2015-01-04 10:47:58 -06:00
|
|
|
return (get_item_val(ccx, fn_id.node), mono_ty, true);
|
2014-02-13 23:07:09 -06:00
|
|
|
}
|
|
|
|
}
|
2012-10-08 14:39:30 -05:00
|
|
|
|
2015-01-04 10:47:58 -06:00
|
|
|
debug!("monomorphic_fn about to subst into {}", item_ty.repr(ccx.tcx()));
|
2014-12-17 13:16:28 -06:00
|
|
|
|
|
|
|
debug!("mono_ty = {} (post-substitution)", mono_ty.repr(ccx.tcx()));
|
|
|
|
|
|
|
|
let mono_ty = normalize_associated_type(ccx.tcx(), &mono_ty);
|
|
|
|
debug!("mono_ty = {} (post-normalization)", mono_ty.repr(ccx.tcx()));
|
2013-09-10 17:42:01 -05:00
|
|
|
|
2014-09-05 11:18:53 -05:00
|
|
|
ccx.stats().n_monos.set(ccx.stats().n_monos.get() + 1);
|
2012-09-12 16:48:13 -05:00
|
|
|
|
2013-12-18 18:38:25 -06:00
|
|
|
let depth;
|
|
|
|
{
|
2014-09-05 11:18:53 -05:00
|
|
|
let mut monomorphizing = ccx.monomorphizing().borrow_mut();
|
2014-11-06 11:25:16 -06:00
|
|
|
depth = match monomorphizing.get(&fn_id) {
|
2013-12-18 18:38:25 -06:00
|
|
|
Some(&d) => d, None => 0
|
|
|
|
};
|
|
|
|
|
|
|
|
// 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.
|
2014-03-05 08:36:01 -06:00
|
|
|
if depth > ccx.sess().recursion_limit.get() {
|
2014-09-05 11:18:53 -05:00
|
|
|
ccx.sess().span_fatal(ccx.tcx().map.span(fn_id.node),
|
2014-03-06 12:37:24 -06:00
|
|
|
"reached the recursion limit during monomorphization");
|
2013-12-18 18:38:25 -06:00
|
|
|
}
|
2014-03-06 12:37:24 -06:00
|
|
|
|
2014-03-20 21:49:20 -05:00
|
|
|
monomorphizing.insert(fn_id, depth + 1);
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2014-08-01 23:25:41 -05:00
|
|
|
let hash;
|
|
|
|
let s = {
|
std: Stabilize the std::hash module
This commit aims to prepare the `std::hash` module for alpha by formalizing its
current interface whileholding off on adding `#[stable]` to the new APIs. The
current usage with the `HashMap` and `HashSet` types is also reconciled by
separating out composable parts of the design. The primary goal of this slight
redesign is to separate the concepts of a hasher's state from a hashing
algorithm itself.
The primary change of this commit is to separate the `Hasher` trait into a
`Hasher` and a `HashState` trait. Conceptually the old `Hasher` trait was
actually just a factory for various states, but hashing had very little control
over how these states were used. Additionally the old `Hasher` trait was
actually fairly unrelated to hashing.
This commit redesigns the existing `Hasher` trait to match what the notion of a
`Hasher` normally implies with the following definition:
trait Hasher {
type Output;
fn reset(&mut self);
fn finish(&self) -> Output;
}
This `Hasher` trait emphasizes that hashing algorithms may produce outputs other
than a `u64`, so the output type is made generic. Other than that, however, very
little is assumed about a particular hasher. It is left up to implementors to
provide specific methods or trait implementations to feed data into a hasher.
The corresponding `Hash` trait becomes:
trait Hash<H: Hasher> {
fn hash(&self, &mut H);
}
The old default of `SipState` was removed from this trait as it's not something
that we're willing to stabilize until the end of time, but the type parameter is
always required to implement `Hasher`. Note that the type parameter `H` remains
on the trait to enable multidispatch for specialization of hashing for
particular hashers.
Note that `Writer` is not mentioned in either of `Hash` or `Hasher`, it is
simply used as part `derive` and the implementations for all primitive types.
With these definitions, the old `Hasher` trait is realized as a new `HashState`
trait in the `collections::hash_state` module as an unstable addition for
now. The current definition looks like:
trait HashState {
type Hasher: Hasher;
fn hasher(&self) -> Hasher;
}
The purpose of this trait is to emphasize that the one piece of functionality
for implementors is that new instances of `Hasher` can be created. This
conceptually represents the two keys from which more instances of a
`SipHasher` can be created, and a `HashState` is what's stored in a
`HashMap`, not a `Hasher`.
Implementors of custom hash algorithms should implement the `Hasher` trait, and
only hash algorithms intended for use in hash maps need to implement or worry
about the `HashState` trait.
The entire module and `HashState` infrastructure remains `#[unstable]` due to it
being recently redesigned, but some other stability decision made for the
`std::hash` module are:
* The `Writer` trait remains `#[experimental]` as it's intended to be replaced
with an `io::Writer` (more details soon).
* The top-level `hash` function is `#[unstable]` as it is intended to be generic
over the hashing algorithm instead of hardwired to `SipHasher`
* The inner `sip` module is now private as its one export, `SipHasher` is
reexported in the `hash` module.
And finally, a few changes were made to the default parameters on `HashMap`.
* The `RandomSipHasher` default type parameter was renamed to `RandomState`.
This renaming emphasizes that it is not a hasher, but rather just state to
generate hashers. It also moves away from the name "sip" as it may not always
be implemented as `SipHasher`. This type lives in the
`std::collections::hash_map` module as `#[unstable]`
* The associated `Hasher` type of `RandomState` is creatively called...
`Hasher`! This concrete structure lives next to `RandomState` as an
implemenation of the "default hashing algorithm" used for a `HashMap`. Under
the hood this is currently implemented as `SipHasher`, but it draws an
explicit interface for now and allows us to modify the implementation over
time if necessary.
There are many breaking changes outlined above, and as a result this commit is
a:
[breaking-change]
2014-12-09 14:37:23 -06:00
|
|
|
let mut state = SipHasher::new();
|
2014-04-20 11:29:56 -05:00
|
|
|
hash_id.hash(&mut state);
|
|
|
|
mono_ty.hash(&mut state);
|
|
|
|
|
std: Stabilize the std::hash module
This commit aims to prepare the `std::hash` module for alpha by formalizing its
current interface whileholding off on adding `#[stable]` to the new APIs. The
current usage with the `HashMap` and `HashSet` types is also reconciled by
separating out composable parts of the design. The primary goal of this slight
redesign is to separate the concepts of a hasher's state from a hashing
algorithm itself.
The primary change of this commit is to separate the `Hasher` trait into a
`Hasher` and a `HashState` trait. Conceptually the old `Hasher` trait was
actually just a factory for various states, but hashing had very little control
over how these states were used. Additionally the old `Hasher` trait was
actually fairly unrelated to hashing.
This commit redesigns the existing `Hasher` trait to match what the notion of a
`Hasher` normally implies with the following definition:
trait Hasher {
type Output;
fn reset(&mut self);
fn finish(&self) -> Output;
}
This `Hasher` trait emphasizes that hashing algorithms may produce outputs other
than a `u64`, so the output type is made generic. Other than that, however, very
little is assumed about a particular hasher. It is left up to implementors to
provide specific methods or trait implementations to feed data into a hasher.
The corresponding `Hash` trait becomes:
trait Hash<H: Hasher> {
fn hash(&self, &mut H);
}
The old default of `SipState` was removed from this trait as it's not something
that we're willing to stabilize until the end of time, but the type parameter is
always required to implement `Hasher`. Note that the type parameter `H` remains
on the trait to enable multidispatch for specialization of hashing for
particular hashers.
Note that `Writer` is not mentioned in either of `Hash` or `Hasher`, it is
simply used as part `derive` and the implementations for all primitive types.
With these definitions, the old `Hasher` trait is realized as a new `HashState`
trait in the `collections::hash_state` module as an unstable addition for
now. The current definition looks like:
trait HashState {
type Hasher: Hasher;
fn hasher(&self) -> Hasher;
}
The purpose of this trait is to emphasize that the one piece of functionality
for implementors is that new instances of `Hasher` can be created. This
conceptually represents the two keys from which more instances of a
`SipHasher` can be created, and a `HashState` is what's stored in a
`HashMap`, not a `Hasher`.
Implementors of custom hash algorithms should implement the `Hasher` trait, and
only hash algorithms intended for use in hash maps need to implement or worry
about the `HashState` trait.
The entire module and `HashState` infrastructure remains `#[unstable]` due to it
being recently redesigned, but some other stability decision made for the
`std::hash` module are:
* The `Writer` trait remains `#[experimental]` as it's intended to be replaced
with an `io::Writer` (more details soon).
* The top-level `hash` function is `#[unstable]` as it is intended to be generic
over the hashing algorithm instead of hardwired to `SipHasher`
* The inner `sip` module is now private as its one export, `SipHasher` is
reexported in the `hash` module.
And finally, a few changes were made to the default parameters on `HashMap`.
* The `RandomSipHasher` default type parameter was renamed to `RandomState`.
This renaming emphasizes that it is not a hasher, but rather just state to
generate hashers. It also moves away from the name "sip" as it may not always
be implemented as `SipHasher`. This type lives in the
`std::collections::hash_map` module as `#[unstable]`
* The associated `Hasher` type of `RandomState` is creatively called...
`Hasher`! This concrete structure lives next to `RandomState` as an
implemenation of the "default hashing algorithm" used for a `HashMap`. Under
the hood this is currently implemented as `SipHasher`, but it draws an
explicit interface for now and allows us to modify the implementation over
time if necessary.
There are many breaking changes outlined above, and as a result this commit is
a:
[breaking-change]
2014-12-09 14:37:23 -06:00
|
|
|
hash = format!("h{}", state.finish());
|
2014-09-05 11:18:53 -05:00
|
|
|
ccx.tcx().map.with_path(fn_id.node, |path| {
|
2015-01-07 10:58:31 -06:00
|
|
|
exported_name(path, &hash[])
|
2014-08-01 23:25:41 -05:00
|
|
|
})
|
|
|
|
};
|
|
|
|
|
2013-10-21 15:08:31 -05:00
|
|
|
debug!("monomorphize_fn mangled to {}", s);
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2014-04-20 11:29:56 -05:00
|
|
|
// This shouldn't need to option dance.
|
|
|
|
let mut hash_id = Some(hash_id);
|
2014-12-30 19:58:47 -06:00
|
|
|
let mut mk_lldecl = |&mut : abi: abi::Abi| {
|
2014-08-01 23:25:41 -05:00
|
|
|
let lldecl = if abi != abi::Rust {
|
2015-01-07 10:58:31 -06:00
|
|
|
foreign::decl_rust_fn_with_foreign_abi(ccx, mono_ty, &s[])
|
2014-08-01 23:25:41 -05:00
|
|
|
} else {
|
2015-01-07 10:58:31 -06:00
|
|
|
decl_internal_rust_fn(ccx, mono_ty, &s[])
|
2014-08-01 23:25:41 -05:00
|
|
|
};
|
|
|
|
|
2014-09-05 11:18:53 -05:00
|
|
|
ccx.monomorphized().borrow_mut().insert(hash_id.take().unwrap(), lldecl);
|
2012-08-28 17:54:45 -05:00
|
|
|
lldecl
|
|
|
|
};
|
2014-12-30 19:58:47 -06:00
|
|
|
let setup_lldecl = |&: lldecl, attrs: &[ast::Attribute]| {
|
2014-08-01 14:27:12 -05:00
|
|
|
base::update_linkage(ccx, lldecl, None, base::OriginalTranslation);
|
2014-09-05 19:28:24 -05:00
|
|
|
set_llvm_fn_attrs(ccx, attrs, lldecl);
|
2014-08-01 14:27:12 -05:00
|
|
|
|
|
|
|
let is_first = !ccx.available_monomorphizations().borrow().contains(&s);
|
|
|
|
if is_first {
|
|
|
|
ccx.available_monomorphizations().borrow_mut().insert(s.clone());
|
|
|
|
}
|
|
|
|
|
|
|
|
let trans_everywhere = attr::requests_inline(attrs);
|
|
|
|
if trans_everywhere && !is_first {
|
|
|
|
llvm::SetLinkage(lldecl, llvm::AvailableExternallyLinkage);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If `true`, then `lldecl` should be given a function body.
|
|
|
|
// Otherwise, it should be left as a declaration of an external
|
|
|
|
// function, with no definition in the current compilation unit.
|
|
|
|
trans_everywhere || is_first
|
|
|
|
};
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2013-05-05 11:17:59 -05:00
|
|
|
let lldecl = match map_node {
|
2014-02-13 23:07:09 -06:00
|
|
|
ast_map::NodeItem(i) => {
|
2014-01-29 17:44:14 -06:00
|
|
|
match *i {
|
|
|
|
ast::Item {
|
2014-08-01 23:25:41 -05:00
|
|
|
node: ast::ItemFn(ref decl, _, abi, _, ref body),
|
2014-01-29 17:44:14 -06:00
|
|
|
..
|
|
|
|
} => {
|
2014-08-01 23:25:41 -05:00
|
|
|
let d = mk_lldecl(abi);
|
2015-01-07 10:58:31 -06:00
|
|
|
let needs_body = setup_lldecl(d, &i.attrs[]);
|
2014-08-01 14:27:12 -05:00
|
|
|
if needs_body {
|
2014-07-31 18:45:29 -05:00
|
|
|
if abi != abi::Rust {
|
|
|
|
foreign::trans_rust_fn_with_foreign_abi(
|
2014-11-06 01:24:44 -06:00
|
|
|
ccx, &**decl, &**body, &[], d, psubsts, fn_id.node,
|
2015-01-07 10:58:31 -06:00
|
|
|
Some(&hash[]));
|
2014-07-31 18:45:29 -05:00
|
|
|
} else {
|
2014-11-06 01:24:44 -06:00
|
|
|
trans_fn(ccx, &**decl, &**body, d, psubsts, fn_id.node, &[]);
|
2014-07-31 18:45:29 -05:00
|
|
|
}
|
2014-08-01 23:25:41 -05:00
|
|
|
}
|
|
|
|
|
2014-01-27 06:18:36 -06:00
|
|
|
d
|
2014-01-03 17:08:48 -06:00
|
|
|
}
|
|
|
|
_ => {
|
2014-03-05 08:36:01 -06:00
|
|
|
ccx.sess().bug("Can't monomorphize this kind of item")
|
2014-01-03 17:08:48 -06:00
|
|
|
}
|
2014-01-29 17:44:14 -06:00
|
|
|
}
|
|
|
|
}
|
2014-02-13 23:07:09 -06:00
|
|
|
ast_map::NodeVariant(v) => {
|
2014-09-05 11:18:53 -05:00
|
|
|
let parent = ccx.tcx().map.get_parent(fn_id.node);
|
2014-03-15 15:29:34 -05:00
|
|
|
let tvs = ty::enum_variants(ccx.tcx(), local_def(parent));
|
2014-04-21 18:21:52 -05:00
|
|
|
let this_tv = tvs.iter().find(|tv| { tv.id.node == fn_id.node}).unwrap();
|
2014-08-01 23:25:41 -05:00
|
|
|
let d = mk_lldecl(abi::Rust);
|
2014-01-29 17:44:14 -06:00
|
|
|
set_inline_hint(d);
|
|
|
|
match v.node.kind {
|
|
|
|
ast::TupleVariantKind(ref args) => {
|
|
|
|
trans_enum_variant(ccx,
|
2014-02-13 23:07:09 -06:00
|
|
|
parent,
|
2014-05-16 12:15:33 -05:00
|
|
|
&*v,
|
2015-01-07 10:58:31 -06:00
|
|
|
&args[],
|
2014-01-29 17:44:14 -06:00
|
|
|
this_tv.disr_val,
|
2014-11-06 01:24:44 -06:00
|
|
|
psubsts,
|
2014-01-29 17:44:14 -06:00
|
|
|
d);
|
|
|
|
}
|
|
|
|
ast::StructVariantKind(_) =>
|
2014-03-05 08:36:01 -06:00
|
|
|
ccx.sess().bug("can't monomorphize struct variants"),
|
2014-01-29 17:44:14 -06:00
|
|
|
}
|
|
|
|
d
|
|
|
|
}
|
2014-08-04 15:56:56 -05:00
|
|
|
ast_map::NodeImplItem(ii) => {
|
|
|
|
match *ii {
|
2014-09-07 12:09:06 -05:00
|
|
|
ast::MethodImplItem(ref mth) => {
|
2014-08-04 15:56:56 -05:00
|
|
|
let d = mk_lldecl(abi::Rust);
|
2015-01-07 10:58:31 -06:00
|
|
|
let needs_body = setup_lldecl(d, &mth.attrs[]);
|
2014-08-01 14:27:12 -05:00
|
|
|
if needs_body {
|
|
|
|
trans_fn(ccx,
|
2014-09-07 12:09:06 -05:00
|
|
|
mth.pe_fn_decl(),
|
|
|
|
mth.pe_body(),
|
2014-08-01 14:27:12 -05:00
|
|
|
d,
|
2014-11-06 01:24:44 -06:00
|
|
|
psubsts,
|
2014-08-01 14:27:12 -05:00
|
|
|
mth.id,
|
2014-11-17 02:39:01 -06:00
|
|
|
&[]);
|
2014-07-31 18:45:29 -05:00
|
|
|
}
|
2014-08-04 15:56:56 -05:00
|
|
|
d
|
|
|
|
}
|
2014-08-05 21:44:21 -05:00
|
|
|
ast::TypeImplItem(_) => {
|
|
|
|
ccx.sess().bug("can't monomorphize an associated type")
|
|
|
|
}
|
2014-08-04 15:56:56 -05:00
|
|
|
}
|
2014-01-29 17:44:14 -06:00
|
|
|
}
|
2014-08-04 15:56:56 -05:00
|
|
|
ast_map::NodeTraitItem(method) => {
|
2014-01-29 17:44:14 -06:00
|
|
|
match *method {
|
2014-09-07 12:09:06 -05:00
|
|
|
ast::ProvidedMethod(ref mth) => {
|
2014-08-01 23:25:41 -05:00
|
|
|
let d = mk_lldecl(abi::Rust);
|
2015-01-07 10:58:31 -06:00
|
|
|
let needs_body = setup_lldecl(d, &mth.attrs[]);
|
2014-08-01 14:27:12 -05:00
|
|
|
if needs_body {
|
2014-09-07 12:09:06 -05:00
|
|
|
trans_fn(ccx, mth.pe_fn_decl(), mth.pe_body(), d,
|
2014-11-06 01:24:44 -06:00
|
|
|
psubsts, mth.id, &[]);
|
2014-07-31 18:45:29 -05:00
|
|
|
}
|
2014-01-29 17:44:14 -06:00
|
|
|
d
|
|
|
|
}
|
|
|
|
_ => {
|
2015-01-07 10:58:31 -06:00
|
|
|
ccx.sess().bug(&format!("can't monomorphize a {:?}",
|
|
|
|
map_node)[])
|
2014-01-29 17:44:14 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-02-13 23:07:09 -06:00
|
|
|
ast_map::NodeStructCtor(struct_def) => {
|
2014-08-01 23:25:41 -05:00
|
|
|
let d = mk_lldecl(abi::Rust);
|
2014-01-29 17:44:14 -06:00
|
|
|
set_inline_hint(d);
|
|
|
|
base::trans_tuple_struct(ccx,
|
2015-01-07 10:58:31 -06:00
|
|
|
&struct_def.fields[],
|
2014-01-29 17:44:14 -06:00
|
|
|
struct_def.ctor_id.expect("ast-mapped tuple struct \
|
|
|
|
didn't have a ctor id"),
|
2014-11-06 01:24:44 -06:00
|
|
|
psubsts,
|
2014-01-29 17:44:14 -06:00
|
|
|
d);
|
|
|
|
d
|
|
|
|
}
|
2012-10-08 14:39:30 -05:00
|
|
|
|
2014-01-29 17:44:14 -06:00
|
|
|
// Ugh -- but this ensures any new variants won't be forgotten
|
2014-07-09 19:25:52 -05:00
|
|
|
ast_map::NodeForeignItem(..) |
|
2014-04-11 04:28:43 -05:00
|
|
|
ast_map::NodeLifetime(..) |
|
2014-01-29 17:44:14 -06:00
|
|
|
ast_map::NodeExpr(..) |
|
|
|
|
ast_map::NodeStmt(..) |
|
|
|
|
ast_map::NodeArg(..) |
|
|
|
|
ast_map::NodeBlock(..) |
|
2014-05-08 08:50:54 -05:00
|
|
|
ast_map::NodePat(..) |
|
2014-01-29 17:44:14 -06:00
|
|
|
ast_map::NodeLocal(..) => {
|
2015-01-07 10:58:31 -06:00
|
|
|
ccx.sess().bug(&format!("can't monomorphize a {:?}",
|
|
|
|
map_node)[])
|
2014-01-29 17:44:14 -06:00
|
|
|
}
|
2012-08-28 17:54:45 -05:00
|
|
|
};
|
2013-12-18 18:38:25 -06:00
|
|
|
|
2014-09-05 11:18:53 -05:00
|
|
|
ccx.monomorphizing().borrow_mut().insert(fn_id, depth);
|
2012-08-28 17:54:45 -05:00
|
|
|
|
2014-03-15 15:29:34 -05:00
|
|
|
debug!("leaving monomorphic fn {}", ty::item_path_str(ccx.tcx(), fn_id));
|
2015-01-04 10:47:58 -06:00
|
|
|
(lldecl, mono_ty, true)
|
2012-08-28 17:54:45 -05:00
|
|
|
}
|
|
|
|
|
2015-01-28 07:34:18 -06:00
|
|
|
#[derive(PartialEq, Eq, Hash, Debug)]
|
2014-09-29 14:11:30 -05:00
|
|
|
pub struct MonoId<'tcx> {
|
2014-04-20 11:29:56 -05:00
|
|
|
pub def: ast::DefId,
|
2014-09-29 14:11:30 -05:00
|
|
|
pub params: subst::VecPerParamSpace<Ty<'tcx>>
|
2014-04-20 11:29:56 -05:00
|
|
|
}
|
2014-12-17 13:16:28 -06:00
|
|
|
|
|
|
|
/// Monomorphizes a type from the AST by first applying the in-scope
|
|
|
|
/// substitutions and then normalizing any associated types.
|
|
|
|
pub fn apply_param_substs<'tcx,T>(tcx: &ty::ctxt<'tcx>,
|
|
|
|
param_substs: &Substs<'tcx>,
|
|
|
|
value: &T)
|
|
|
|
-> T
|
|
|
|
where T : TypeFoldable<'tcx> + Repr<'tcx> + HasProjectionTypes + Clone
|
|
|
|
{
|
|
|
|
let substituted = value.subst(tcx, param_substs);
|
|
|
|
normalize_associated_type(tcx, &substituted)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Removes associated types, if any. Since this during
|
|
|
|
/// monomorphization, we know that only concrete types are involved,
|
|
|
|
/// and hence we can be sure that all associated types will be
|
|
|
|
/// completely normalized away.
|
2014-12-30 16:42:02 -06:00
|
|
|
pub fn normalize_associated_type<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> T
|
2014-12-17 13:16:28 -06:00
|
|
|
where T : TypeFoldable<'tcx> + Repr<'tcx> + HasProjectionTypes + Clone
|
|
|
|
{
|
2014-12-30 16:42:02 -06:00
|
|
|
debug!("normalize_associated_type(t={})", value.repr(tcx));
|
2014-12-17 13:16:28 -06:00
|
|
|
|
2015-01-07 13:04:37 -06:00
|
|
|
let value = erase_regions(tcx, value);
|
|
|
|
|
2014-12-30 16:42:02 -06:00
|
|
|
if !value.has_projection_types() {
|
2015-01-07 13:04:37 -06:00
|
|
|
return value;
|
2014-12-17 13:16:28 -06:00
|
|
|
}
|
|
|
|
|
2014-12-29 10:03:04 -06:00
|
|
|
// FIXME(#20304) -- cache
|
2014-12-17 13:16:28 -06:00
|
|
|
|
|
|
|
let infcx = infer::new_infer_ctxt(tcx);
|
2015-01-24 14:00:03 -06:00
|
|
|
let typer = NormalizingClosureTyper::new(tcx);
|
2015-01-02 03:09:35 -06:00
|
|
|
let mut selcx = traits::SelectionContext::new(&infcx, &typer);
|
2014-12-30 16:42:02 -06:00
|
|
|
let cause = traits::ObligationCause::dummy();
|
|
|
|
let traits::Normalized { value: result, obligations } =
|
2015-01-07 13:04:37 -06:00
|
|
|
traits::normalize(&mut selcx, cause, &value);
|
2014-12-17 13:16:28 -06:00
|
|
|
|
2014-12-30 16:42:02 -06:00
|
|
|
debug!("normalize_associated_type: result={} obligations={}",
|
|
|
|
result.repr(tcx),
|
|
|
|
obligations.repr(tcx));
|
2014-12-17 13:16:28 -06:00
|
|
|
|
2014-12-31 13:42:06 -06:00
|
|
|
let mut fulfill_cx = traits::FulfillmentContext::new();
|
2015-01-31 19:03:04 -06:00
|
|
|
for obligation in obligations {
|
2014-12-31 13:42:06 -06:00
|
|
|
fulfill_cx.register_predicate_obligation(&infcx, obligation);
|
|
|
|
}
|
2015-01-02 03:09:35 -06:00
|
|
|
let result = drain_fulfillment_cx(DUMMY_SP, &infcx, &mut fulfill_cx, &result);
|
2014-12-17 13:16:28 -06:00
|
|
|
|
2014-12-30 16:42:02 -06:00
|
|
|
result
|
2014-12-17 13:16:28 -06:00
|
|
|
}
|