summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Fitzgerald <fitzgen@gmail.com>2017-04-17 15:07:59 -0700
committerNick Fitzgerald <fitzgen@gmail.com>2017-04-17 16:01:58 -0700
commit1c78209eea25c79676945af371a523ed023ce46a (patch)
tree6e34340448a885cb4720a17ba28eda021f764336
parentbce13307645172be62e8895e82d9362f0c4e4fd6 (diff)
Factor the `UsedTemplateParameters::constrain` method into smaller functions
The method was getting fairly large, and it is a little easier to read if we break it down into smaller parts.
-rw-r--r--src/ir/named.rs197
1 files changed, 108 insertions, 89 deletions
diff --git a/src/ir/named.rs b/src/ir/named.rs
index 17f46eca..855da005 100644
--- a/src/ir/named.rs
+++ b/src/ir/named.rs
@@ -127,8 +127,8 @@
//! [spa]: https://cs.au.dk/~amoeller/spa/spa.pdf
use super::context::{BindgenContext, ItemId};
-use super::item::ItemSet;
-use super::template::AsNamed;
+use super::item::{Item, ItemSet};
+use super::template::{AsNamed, TemplateInstantiation};
use super::traversal::{EdgeKind, Trace};
use super::ty::{TemplateDeclaration, TypeKind};
use std::collections::{HashMap, HashSet};
@@ -307,6 +307,103 @@ impl<'ctx, 'gen> UsedTemplateParameters<'ctx, 'gen> {
EdgeKind::Generic => false,
}
}
+
+ fn take_this_id_usage_set(&mut self, this_id: ItemId) -> ItemSet {
+ self.used
+ .get_mut(&this_id)
+ .expect("Should have a set of used template params for every item \
+ id")
+ .take()
+ .expect("Should maintain the invariant that all used template param \
+ sets are `Some` upon entry of `constrain`")
+ }
+
+ /// We say that blacklisted items use all of their template parameters. The
+ /// blacklisted type is most likely implemented explicitly by the user,
+ /// since it won't be in the generated bindings, and we don't know exactly
+ /// what they'll to with template parameters, but we can push the issue down
+ /// the line to them.
+ fn constrain_instantiation_of_blacklisted_template(&self,
+ used_by_this_id: &mut ItemSet,
+ instantiation: &TemplateInstantiation) {
+ debug!(" instantiation of blacklisted template, uses all template \
+ arguments");
+
+ let args = instantiation.template_arguments()
+ .iter()
+ .filter_map(|a| a.as_named(self.ctx, &()));
+ used_by_this_id.extend(args);
+ }
+
+ /// A template instantiation's concrete template argument is only used if
+ /// the template definition uses the corresponding template parameter.
+ fn constrain_instantiation(&self,
+ used_by_this_id: &mut ItemSet,
+ instantiation: &TemplateInstantiation) {
+ debug!(" template instantiation");
+
+ let decl = self.ctx.resolve_type(instantiation.template_definition());
+ let args = instantiation.template_arguments();
+
+ let params = decl.self_template_params(self.ctx)
+ .unwrap_or(vec![]);
+
+ let used_by_def = self.used[&instantiation.template_definition()]
+ .as_ref()
+ .unwrap();
+
+ for (arg, param) in args.iter().zip(params.iter()) {
+ debug!(" instantiation's argument {:?} is used if definition's \
+ parameter {:?} is used",
+ arg,
+ param);
+
+ if used_by_def.contains(param) {
+ debug!(" param is used by template definition");
+
+ let arg = arg.into_resolver()
+ .through_type_refs()
+ .through_type_aliases()
+ .resolve(self.ctx);
+ if let Some(named) = arg.as_named(self.ctx, &()) {
+ debug!(" arg is a type parameter, marking used");
+ used_by_this_id.insert(named);
+ }
+ }
+ }
+ }
+
+ /// The join operation on our lattice: the set union of all of this id's
+ /// successors.
+ fn constrain_join(&self, used_by_this_id: &mut ItemSet, item: &Item) {
+ debug!(" other item: join with successors' usage");
+
+ item.trace(self.ctx, &mut |sub_id, edge_kind| {
+ // Ignore ourselves, since union with ourself is a
+ // no-op. Ignore edges that aren't relevant to the
+ // analysis. Ignore edges to blacklisted items.
+ if sub_id == item.id() ||
+ !Self::consider_edge(edge_kind) ||
+ !self.whitelisted_items.contains(&sub_id) {
+ return;
+ }
+
+ let used_by_sub_id = self.used[&sub_id]
+ .as_ref()
+ .expect("Because sub_id != id, and all used template \
+ param sets other than id's are `Some`, \
+ sub_id's used template param set should be \
+ `Some`")
+ .iter()
+ .cloned();
+
+ debug!(" union with {:?}'s usage: {:?}",
+ sub_id,
+ used_by_sub_id.clone().collect::<Vec<_>>());
+
+ used_by_this_id.extend(used_by_sub_id);
+ }, &());
+ }
}
impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> {
@@ -418,13 +515,7 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> {
// on other hash map entries. We *must* put it back into the hash map at
// the end of this method. This allows us to side-step HashMap's lack of
// an analog to slice::split_at_mut.
- let mut used_by_this_id = self.used
- .get_mut(&id)
- .expect("Should have a set of used template params for every item \
- id")
- .take()
- .expect("Should maintain the invariant that all used template param \
- sets are `Some` upon entry of `constrain`");
+ let mut used_by_this_id = self.take_this_id_usage_set(id);
debug!("constrain {:?}", id);
debug!(" initially, used set is {:?}", used_by_this_id);
@@ -439,91 +530,19 @@ impl<'ctx, 'gen> MonotoneFramework for UsedTemplateParameters<'ctx, 'gen> {
debug!(" named type, trivially uses itself");
used_by_this_id.insert(id);
}
-
- // We say that blacklisted items use all of their template
- // parameters. The blacklisted type is most likely implemented
- // explicitly by the user, since it won't be in the generated
- // bindings, and we don't know exactly what they'll to with template
- // parameters, but we can push the issue down the line to them.
- Some(&TypeKind::TemplateInstantiation(ref inst))
- if !self.whitelisted_items.contains(&inst.template_definition()) => {
- debug!(" instantiation of blacklisted template, uses all template \
- arguments");
-
- let args = inst.template_arguments()
- .iter()
- .filter_map(|a| a.as_named(self.ctx, &()));
- used_by_this_id.extend(args);
- }
-
- // A template instantiation's concrete template argument is
- // only used if the template declaration uses the
- // corresponding template parameter.
+ // Template instantiations only use their template arguments if the
+ // template definition uses the corresponding template parameter.
Some(&TypeKind::TemplateInstantiation(ref inst)) => {
- debug!(" template instantiation");
-
- let decl = self.ctx.resolve_type(inst.template_definition());
- let args = inst.template_arguments();
-
- let params = decl.self_template_params(self.ctx)
- .unwrap_or(vec![]);
-
- let used_by_def = self.used[&inst.template_definition()]
- .as_ref()
- .unwrap();
-
- for (arg, param) in args.iter().zip(params.iter()) {
- debug!(" instantiation's argument {:?} is used if definition's \
- parameter {:?} is used",
- arg,
- param);
-
- if used_by_def.contains(param) {
- debug!(" param is used by template definition");
-
- let arg = arg.into_resolver()
- .through_type_refs()
- .through_type_aliases()
- .resolve(self.ctx);
- if let Some(named) = arg.as_named(self.ctx, &()) {
- debug!(" arg is a type parameter, marking used");
- used_by_this_id.insert(named);
- }
- }
+ if self.whitelisted_items.contains(&inst.template_definition()) {
+ self.constrain_instantiation(&mut used_by_this_id, inst);
+ } else {
+ self.constrain_instantiation_of_blacklisted_template(&mut used_by_this_id,
+ inst);
}
}
-
// Otherwise, add the union of each of its referent item's template
// parameter usage.
- _ => {
- debug!(" other item: join with successors' usage");
-
- item.trace(self.ctx, &mut |sub_id, edge_kind| {
- // Ignore ourselves, since union with ourself is a
- // no-op. Ignore edges that aren't relevant to the
- // analysis. Ignore edges to blacklisted items.
- if sub_id == id ||
- !Self::consider_edge(edge_kind) ||
- !self.whitelisted_items.contains(&sub_id) {
- return;
- }
-
- let used_by_sub_id = self.used[&sub_id]
- .as_ref()
- .expect("Because sub_id != id, and all used template \
- param sets other than id's are `Some`, \
- sub_id's used template param set should be \
- `Some`")
- .iter()
- .cloned();
-
- debug!(" union with {:?}'s usage: {:?}",
- sub_id,
- used_by_sub_id.clone().collect::<Vec<_>>());
-
- used_by_this_id.extend(used_by_sub_id);
- }, &());
- }
+ _ => self.constrain_join(&mut used_by_this_id, item),
}
debug!(" finally, used set is {:?}", used_by_this_id);