rustc_typeck: support functions in variance computation.
This commit is contained in:
parent
33ecf72e8e
commit
a9d4069975
@ -291,7 +291,7 @@ fn relate<'a, 'gcx, R>(relation: &mut R,
|
|||||||
if a.def_id != b.def_id {
|
if a.def_id != b.def_id {
|
||||||
Err(TypeError::Traits(expected_found(relation, &a.def_id, &b.def_id)))
|
Err(TypeError::Traits(expected_found(relation, &a.def_id, &b.def_id)))
|
||||||
} else {
|
} else {
|
||||||
let substs = relation.relate_item_substs(a.def_id, a.substs, b.substs)?;
|
let substs = relate_substs(relation, None, a.substs, b.substs)?;
|
||||||
Ok(ty::TraitRef { def_id: a.def_id, substs: substs })
|
Ok(ty::TraitRef { def_id: a.def_id, substs: substs })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -308,7 +308,7 @@ fn relate<'a, 'gcx, R>(relation: &mut R,
|
|||||||
if a.def_id != b.def_id {
|
if a.def_id != b.def_id {
|
||||||
Err(TypeError::Traits(expected_found(relation, &a.def_id, &b.def_id)))
|
Err(TypeError::Traits(expected_found(relation, &a.def_id, &b.def_id)))
|
||||||
} else {
|
} else {
|
||||||
let substs = relation.relate_item_substs(a.def_id, a.substs, b.substs)?;
|
let substs = relate_substs(relation, None, a.substs, b.substs)?;
|
||||||
Ok(ty::ExistentialTraitRef { def_id: a.def_id, substs: substs })
|
Ok(ty::ExistentialTraitRef { def_id: a.def_id, substs: substs })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -443,7 +443,7 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
|
|||||||
(&ty::TyFnDef(a_def_id, a_substs), &ty::TyFnDef(b_def_id, b_substs))
|
(&ty::TyFnDef(a_def_id, a_substs), &ty::TyFnDef(b_def_id, b_substs))
|
||||||
if a_def_id == b_def_id =>
|
if a_def_id == b_def_id =>
|
||||||
{
|
{
|
||||||
let substs = relate_substs(relation, None, a_substs, b_substs)?;
|
let substs = relation.relate_item_substs(a_def_id, a_substs, b_substs)?;
|
||||||
Ok(tcx.mk_fn_def(a_def_id, substs))
|
Ok(tcx.mk_fn_def(a_def_id, substs))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -524,7 +524,11 @@ fn encode_enum_variant_info(&mut self,
|
|||||||
|
|
||||||
ty: Some(self.encode_item_type(def_id)),
|
ty: Some(self.encode_item_type(def_id)),
|
||||||
inherent_impls: LazySeq::empty(),
|
inherent_impls: LazySeq::empty(),
|
||||||
variances: LazySeq::empty(),
|
variances: if variant.ctor_kind == CtorKind::Fn {
|
||||||
|
self.encode_variances_of(def_id)
|
||||||
|
} else {
|
||||||
|
LazySeq::empty()
|
||||||
|
},
|
||||||
generics: Some(self.encode_generics(def_id)),
|
generics: Some(self.encode_generics(def_id)),
|
||||||
predicates: Some(self.encode_predicates(def_id)),
|
predicates: Some(self.encode_predicates(def_id)),
|
||||||
|
|
||||||
@ -652,7 +656,11 @@ fn encode_struct_ctor(&mut self, (adt_def_id, def_id): (DefId, DefId)) -> Entry<
|
|||||||
|
|
||||||
ty: Some(self.encode_item_type(def_id)),
|
ty: Some(self.encode_item_type(def_id)),
|
||||||
inherent_impls: LazySeq::empty(),
|
inherent_impls: LazySeq::empty(),
|
||||||
variances: LazySeq::empty(),
|
variances: if variant.ctor_kind == CtorKind::Fn {
|
||||||
|
self.encode_variances_of(def_id)
|
||||||
|
} else {
|
||||||
|
LazySeq::empty()
|
||||||
|
},
|
||||||
generics: Some(self.encode_generics(def_id)),
|
generics: Some(self.encode_generics(def_id)),
|
||||||
predicates: Some(self.encode_predicates(def_id)),
|
predicates: Some(self.encode_predicates(def_id)),
|
||||||
|
|
||||||
@ -744,7 +752,11 @@ fn encode_info_for_trait_item(&mut self, def_id: DefId) -> Entry<'tcx> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
inherent_impls: LazySeq::empty(),
|
inherent_impls: LazySeq::empty(),
|
||||||
variances: LazySeq::empty(),
|
variances: if trait_item.kind == ty::AssociatedKind::Method {
|
||||||
|
self.encode_variances_of(def_id)
|
||||||
|
} else {
|
||||||
|
LazySeq::empty()
|
||||||
|
},
|
||||||
generics: Some(self.encode_generics(def_id)),
|
generics: Some(self.encode_generics(def_id)),
|
||||||
predicates: Some(self.encode_predicates(def_id)),
|
predicates: Some(self.encode_predicates(def_id)),
|
||||||
|
|
||||||
@ -821,7 +833,11 @@ fn encode_info_for_impl_item(&mut self, def_id: DefId) -> Entry<'tcx> {
|
|||||||
|
|
||||||
ty: Some(self.encode_item_type(def_id)),
|
ty: Some(self.encode_item_type(def_id)),
|
||||||
inherent_impls: LazySeq::empty(),
|
inherent_impls: LazySeq::empty(),
|
||||||
variances: LazySeq::empty(),
|
variances: if impl_item.kind == ty::AssociatedKind::Method {
|
||||||
|
self.encode_variances_of(def_id)
|
||||||
|
} else {
|
||||||
|
LazySeq::empty()
|
||||||
|
},
|
||||||
generics: Some(self.encode_generics(def_id)),
|
generics: Some(self.encode_generics(def_id)),
|
||||||
predicates: Some(self.encode_predicates(def_id)),
|
predicates: Some(self.encode_predicates(def_id)),
|
||||||
|
|
||||||
@ -1055,7 +1071,7 @@ fn encode_info_for_item(&mut self, (def_id, item): (DefId, &'tcx hir::Item)) ->
|
|||||||
hir::ItemEnum(..) |
|
hir::ItemEnum(..) |
|
||||||
hir::ItemStruct(..) |
|
hir::ItemStruct(..) |
|
||||||
hir::ItemUnion(..) |
|
hir::ItemUnion(..) |
|
||||||
hir::ItemTrait(..) => self.encode_variances_of(def_id),
|
hir::ItemFn(..) => self.encode_variances_of(def_id),
|
||||||
_ => LazySeq::empty(),
|
_ => LazySeq::empty(),
|
||||||
},
|
},
|
||||||
generics: match item.node {
|
generics: match item.node {
|
||||||
@ -1400,7 +1416,10 @@ fn encode_info_for_foreign_item(&mut self,
|
|||||||
|
|
||||||
ty: Some(self.encode_item_type(def_id)),
|
ty: Some(self.encode_item_type(def_id)),
|
||||||
inherent_impls: LazySeq::empty(),
|
inherent_impls: LazySeq::empty(),
|
||||||
variances: LazySeq::empty(),
|
variances: match nitem.node {
|
||||||
|
hir::ForeignItemFn(..) => self.encode_variances_of(def_id),
|
||||||
|
_ => LazySeq::empty(),
|
||||||
|
},
|
||||||
generics: Some(self.encode_generics(def_id)),
|
generics: Some(self.encode_generics(def_id)),
|
||||||
predicates: Some(self.encode_predicates(def_id)),
|
predicates: Some(self.encode_predicates(def_id)),
|
||||||
|
|
||||||
|
@ -14,11 +14,9 @@
|
|||||||
//! We walk the set of items and, for each member, generate new constraints.
|
//! We walk the set of items and, for each member, generate new constraints.
|
||||||
|
|
||||||
use hir::def_id::DefId;
|
use hir::def_id::DefId;
|
||||||
use middle::resolve_lifetime as rl;
|
|
||||||
use rustc::dep_graph::{AssertDepGraphSafe, DepKind};
|
use rustc::dep_graph::{AssertDepGraphSafe, DepKind};
|
||||||
use rustc::ty::subst::Substs;
|
use rustc::ty::subst::Substs;
|
||||||
use rustc::ty::{self, Ty, TyCtxt};
|
use rustc::ty::{self, Ty, TyCtxt};
|
||||||
use rustc::hir::map as hir_map;
|
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use rustc::hir;
|
use rustc::hir;
|
||||||
use rustc::hir::itemlikevisit::ItemLikeVisitor;
|
use rustc::hir::itemlikevisit::ItemLikeVisitor;
|
||||||
@ -61,10 +59,10 @@ pub struct Constraint<'a> {
|
|||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// then while we are visiting `Bar<T>`, the `CurrentItem` would have
|
/// then while we are visiting `Bar<T>`, the `CurrentItem` would have
|
||||||
/// the def-id and generics of `Foo`.
|
/// the def-id and the start of `Foo`'s inferreds.
|
||||||
pub struct CurrentItem<'a> {
|
pub struct CurrentItem {
|
||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
generics: &'a ty::Generics,
|
inferred_start: InferredIndex,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_constraints_from_crate<'a, 'tcx>(terms_cx: TermsContext<'a, 'tcx>)
|
pub fn add_constraints_from_crate<'a, 'tcx>(terms_cx: TermsContext<'a, 'tcx>)
|
||||||
@ -91,8 +89,59 @@ pub fn add_constraints_from_crate<'a, 'tcx>(terms_cx: TermsContext<'a, 'tcx>)
|
|||||||
|
|
||||||
impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> {
|
impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> {
|
||||||
fn visit_item(&mut self, item: &hir::Item) {
|
fn visit_item(&mut self, item: &hir::Item) {
|
||||||
|
match item.node {
|
||||||
|
hir::ItemStruct(ref struct_def, _) |
|
||||||
|
hir::ItemUnion(ref struct_def, _) => {
|
||||||
|
self.visit_node_helper(item.id);
|
||||||
|
|
||||||
|
if let hir::VariantData::Tuple(..) = *struct_def {
|
||||||
|
self.visit_node_helper(struct_def.id());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hir::ItemEnum(ref enum_def, _) => {
|
||||||
|
self.visit_node_helper(item.id);
|
||||||
|
|
||||||
|
for variant in &enum_def.variants {
|
||||||
|
if let hir::VariantData::Tuple(..) = variant.node.data {
|
||||||
|
self.visit_node_helper(variant.node.data.id());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hir::ItemFn(..) => {
|
||||||
|
self.visit_node_helper(item.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
hir::ItemForeignMod(ref foreign_mod) => {
|
||||||
|
for foreign_item in &foreign_mod.items {
|
||||||
|
if let hir::ForeignItemFn(..) = foreign_item.node {
|
||||||
|
self.visit_node_helper(foreign_item.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) {
|
||||||
|
if let hir::TraitItemKind::Method(..) = trait_item.node {
|
||||||
|
self.visit_node_helper(trait_item.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) {
|
||||||
|
if let hir::ImplItemKind::Method(..) = impl_item.node {
|
||||||
|
self.visit_node_helper(impl_item.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
||||||
|
fn visit_node_helper(&mut self, id: ast::NodeId) {
|
||||||
let tcx = self.terms_cx.tcx;
|
let tcx = self.terms_cx.tcx;
|
||||||
let def_id = tcx.hir.local_def_id(item.id);
|
let def_id = tcx.hir.local_def_id(id);
|
||||||
|
|
||||||
// Encapsulate constructing the constraints into a task we can
|
// Encapsulate constructing the constraints into a task we can
|
||||||
// reference later. This can go away once the red-green
|
// reference later. This can go away once the red-green
|
||||||
@ -100,20 +149,11 @@ fn visit_item(&mut self, item: &hir::Item) {
|
|||||||
//
|
//
|
||||||
// See README.md for a detailed discussion
|
// See README.md for a detailed discussion
|
||||||
// on dep-graph management.
|
// on dep-graph management.
|
||||||
match item.node {
|
let dep_node = def_id.to_dep_node(tcx, DepKind::ItemVarianceConstraints);
|
||||||
hir::ItemEnum(..) |
|
tcx.dep_graph.with_task(dep_node,
|
||||||
hir::ItemStruct(..) |
|
AssertDepGraphSafe(self),
|
||||||
hir::ItemUnion(..) => {
|
def_id,
|
||||||
let dep_node = def_id.to_dep_node(tcx, DepKind::ItemVarianceConstraints);
|
visit_item_task);
|
||||||
tcx.dep_graph.with_task(dep_node,
|
|
||||||
AssertDepGraphSafe(self),
|
|
||||||
def_id,
|
|
||||||
visit_item_task);
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
// Nothing to do here, skip the task.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_item_task<'a, 'tcx>(ccx: AssertDepGraphSafe<&mut ConstraintContext<'a, 'tcx>>,
|
fn visit_item_task<'a, 'tcx>(ccx: AssertDepGraphSafe<&mut ConstraintContext<'a, 'tcx>>,
|
||||||
def_id: DefId)
|
def_id: DefId)
|
||||||
@ -122,197 +162,57 @@ fn visit_item_task<'a, 'tcx>(ccx: AssertDepGraphSafe<&mut ConstraintContext<'a,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Is `param_id` a lifetime according to `map`?
|
|
||||||
fn is_lifetime(map: &hir_map::Map, param_id: ast::NodeId) -> bool {
|
|
||||||
match map.find(param_id) {
|
|
||||||
Some(hir_map::NodeLifetime(..)) => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
|
||||||
fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> {
|
fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> {
|
||||||
self.terms_cx.tcx
|
self.terms_cx.tcx
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_constraints_for_item(&mut self, def_id: DefId) {
|
fn build_constraints_for_item(&mut self, def_id: DefId) {
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
let id = self.tcx().hir.as_local_node_id(def_id).unwrap();
|
debug!("build_constraints_for_item({})", tcx.item_path_str(def_id));
|
||||||
let item = tcx.hir.expect_item(id);
|
|
||||||
debug!("visit_item item={}", tcx.hir.node_to_string(item.id));
|
|
||||||
|
|
||||||
match item.node {
|
// Skip items with no generics - there's nothing to infer in them.
|
||||||
hir::ItemEnum(..) |
|
if tcx.generics_of(def_id).count() == 0 {
|
||||||
hir::ItemStruct(..) |
|
return;
|
||||||
hir::ItemUnion(..) => {
|
}
|
||||||
let generics = tcx.generics_of(def_id);
|
|
||||||
let current_item = &CurrentItem { def_id, generics };
|
|
||||||
|
|
||||||
|
let id = tcx.hir.as_local_node_id(def_id).unwrap();
|
||||||
|
let inferred_start = self.terms_cx.inferred_starts[&id];
|
||||||
|
let current_item = &CurrentItem { def_id, inferred_start };
|
||||||
|
match tcx.type_of(def_id).sty {
|
||||||
|
ty::TyAdt(def, _) => {
|
||||||
// Not entirely obvious: constraints on structs/enums do not
|
// Not entirely obvious: constraints on structs/enums do not
|
||||||
// affect the variance of their type parameters. See discussion
|
// affect the variance of their type parameters. See discussion
|
||||||
// in comment at top of module.
|
// in comment at top of module.
|
||||||
//
|
//
|
||||||
// self.add_constraints_from_generics(generics);
|
// self.add_constraints_from_generics(generics);
|
||||||
|
|
||||||
for field in tcx.adt_def(def_id).all_fields() {
|
for field in def.all_fields() {
|
||||||
self.add_constraints_from_ty(current_item,
|
self.add_constraints_from_ty(current_item,
|
||||||
tcx.type_of(field.did),
|
tcx.type_of(field.did),
|
||||||
self.covariant);
|
self.covariant);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hir::ItemTrait(..) |
|
ty::TyFnDef(..) => {
|
||||||
hir::ItemExternCrate(_) |
|
self.add_constraints_from_sig(current_item,
|
||||||
hir::ItemUse(..) |
|
tcx.fn_sig(def_id),
|
||||||
hir::ItemStatic(..) |
|
self.covariant);
|
||||||
hir::ItemConst(..) |
|
|
||||||
hir::ItemFn(..) |
|
|
||||||
hir::ItemMod(..) |
|
|
||||||
hir::ItemForeignMod(..) |
|
|
||||||
hir::ItemGlobalAsm(..) |
|
|
||||||
hir::ItemTy(..) |
|
|
||||||
hir::ItemImpl(..) |
|
|
||||||
hir::ItemDefaultImpl(..) => {
|
|
||||||
span_bug!(item.span, "`build_constraints_for_item` invoked for non-type-def");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Load the generics for another item, adding a corresponding
|
|
||||||
/// relation into the dependencies to indicate that the variance
|
|
||||||
/// for `current` relies on `def_id`.
|
|
||||||
fn read_generics(&mut self, current: &CurrentItem, def_id: DefId) -> &'tcx ty::Generics {
|
|
||||||
let generics = self.tcx().generics_of(def_id);
|
|
||||||
if self.tcx().dep_graph.is_fully_enabled() {
|
|
||||||
self.dependencies.add(current.def_id, def_id);
|
|
||||||
}
|
|
||||||
generics
|
|
||||||
}
|
|
||||||
|
|
||||||
fn opt_inferred_index(&self, param_id: ast::NodeId) -> Option<&InferredIndex> {
|
|
||||||
self.terms_cx.inferred_map.get(¶m_id)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_binding_for_lifetime(&self, param_id: ast::NodeId) -> ast::NodeId {
|
|
||||||
let tcx = self.terms_cx.tcx;
|
|
||||||
assert!(is_lifetime(&tcx.hir, param_id));
|
|
||||||
match tcx.named_region_map.defs.get(¶m_id) {
|
|
||||||
Some(&rl::Region::EarlyBound(_, lifetime_decl_id)) => lifetime_decl_id,
|
|
||||||
Some(_) => bug!("should not encounter non early-bound cases"),
|
|
||||||
|
|
||||||
// The lookup should only fail when `param_id` is
|
|
||||||
// itself a lifetime binding: use it as the decl_id.
|
|
||||||
None => param_id,
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Is `param_id` a type parameter for which we infer variance?
|
|
||||||
fn is_to_be_inferred(&self, param_id: ast::NodeId) -> bool {
|
|
||||||
let result = self.terms_cx.inferred_map.contains_key(¶m_id);
|
|
||||||
|
|
||||||
// To safe-guard against invalid inferred_map constructions,
|
|
||||||
// double-check if variance is inferred at some use of a type
|
|
||||||
// parameter (by inspecting parent of its binding declaration
|
|
||||||
// to see if it is introduced by a type or by a fn/impl).
|
|
||||||
|
|
||||||
let check_result = |this: &ConstraintContext| -> bool {
|
|
||||||
let tcx = this.terms_cx.tcx;
|
|
||||||
let decl_id = this.find_binding_for_lifetime(param_id);
|
|
||||||
// Currently only called on lifetimes; double-checking that.
|
|
||||||
assert!(is_lifetime(&tcx.hir, param_id));
|
|
||||||
let parent_id = tcx.hir.get_parent(decl_id);
|
|
||||||
let parent = tcx.hir
|
|
||||||
.find(parent_id)
|
|
||||||
.unwrap_or_else(|| bug!("tcx.hir missing entry for id: {}", parent_id));
|
|
||||||
|
|
||||||
let is_inferred;
|
|
||||||
macro_rules! cannot_happen { () => { {
|
|
||||||
bug!("invalid parent: {} for {}",
|
|
||||||
tcx.hir.node_to_string(parent_id),
|
|
||||||
tcx.hir.node_to_string(param_id));
|
|
||||||
} } }
|
|
||||||
|
|
||||||
match parent {
|
|
||||||
hir_map::NodeItem(p) => {
|
|
||||||
match p.node {
|
|
||||||
hir::ItemTy(..) |
|
|
||||||
hir::ItemEnum(..) |
|
|
||||||
hir::ItemStruct(..) |
|
|
||||||
hir::ItemUnion(..) |
|
|
||||||
hir::ItemTrait(..) => is_inferred = true,
|
|
||||||
hir::ItemFn(..) => is_inferred = false,
|
|
||||||
_ => cannot_happen!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
hir_map::NodeTraitItem(..) => is_inferred = false,
|
|
||||||
hir_map::NodeImplItem(..) => is_inferred = false,
|
|
||||||
_ => cannot_happen!(),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return is_inferred;
|
_ => {
|
||||||
};
|
span_bug!(tcx.def_span(def_id),
|
||||||
|
"`build_constraints_for_item` unsupported for this item");
|
||||||
assert_eq!(result, check_result(self));
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a variance term representing the declared variance of the type/region parameter
|
|
||||||
/// with the given id.
|
|
||||||
fn declared_variance(&self,
|
|
||||||
param_def_id: DefId,
|
|
||||||
item_def_id: DefId,
|
|
||||||
index: usize)
|
|
||||||
-> VarianceTermPtr<'a> {
|
|
||||||
assert_eq!(param_def_id.krate, item_def_id.krate);
|
|
||||||
|
|
||||||
if let Some(param_node_id) = self.tcx().hir.as_local_node_id(param_def_id) {
|
|
||||||
// Parameter on an item defined within current crate:
|
|
||||||
// variance not yet inferred, so return a symbolic
|
|
||||||
// variance.
|
|
||||||
if let Some(&InferredIndex(index)) = self.opt_inferred_index(param_node_id) {
|
|
||||||
self.terms_cx.inferred_infos[index].term
|
|
||||||
} else {
|
|
||||||
// If there is no inferred entry for a type parameter,
|
|
||||||
// it must be declared on a (locally defiend) trait -- they don't
|
|
||||||
// get inferreds because they are always invariant.
|
|
||||||
if cfg!(debug_assertions) {
|
|
||||||
let item_node_id = self.tcx().hir.as_local_node_id(item_def_id).unwrap();
|
|
||||||
let item = self.tcx().hir.expect_item(item_node_id);
|
|
||||||
let success = match item.node {
|
|
||||||
hir::ItemTrait(..) => true,
|
|
||||||
_ => false,
|
|
||||||
};
|
|
||||||
if !success {
|
|
||||||
bug!("parameter {:?} has no inferred, but declared on non-trait: {:?}",
|
|
||||||
item_def_id,
|
|
||||||
item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.invariant
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// Parameter on an item defined within another crate:
|
|
||||||
// variance already inferred, just look it up.
|
|
||||||
let variances = self.tcx().variances_of(item_def_id);
|
|
||||||
self.constant_term(variances[index])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_constraint(&mut self,
|
fn add_constraint(&mut self,
|
||||||
InferredIndex(index): InferredIndex,
|
current: &CurrentItem,
|
||||||
|
index: u32,
|
||||||
variance: VarianceTermPtr<'a>) {
|
variance: VarianceTermPtr<'a>) {
|
||||||
debug!("add_constraint(index={}, variance={:?})", index, variance);
|
debug!("add_constraint(index={}, variance={:?})", index, variance);
|
||||||
self.constraints.push(Constraint {
|
self.constraints.push(Constraint {
|
||||||
inferred: InferredIndex(index),
|
inferred: InferredIndex(current.inferred_start.0 + index as usize),
|
||||||
variance: variance,
|
variance: variance,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -354,15 +254,26 @@ fn add_constraints_from_trait_ref(&mut self,
|
|||||||
debug!("add_constraints_from_trait_ref: trait_ref={:?} variance={:?}",
|
debug!("add_constraints_from_trait_ref: trait_ref={:?} variance={:?}",
|
||||||
trait_ref,
|
trait_ref,
|
||||||
variance);
|
variance);
|
||||||
|
self.add_constraints_from_invariant_substs(current, trait_ref.substs, variance);
|
||||||
|
}
|
||||||
|
|
||||||
let trait_generics = self.tcx().generics_of(trait_ref.def_id);
|
fn add_constraints_from_invariant_substs(&mut self,
|
||||||
|
current: &CurrentItem,
|
||||||
|
substs: &Substs<'tcx>,
|
||||||
|
variance: VarianceTermPtr<'a>) {
|
||||||
|
debug!("add_constraints_from_invariant_substs: substs={:?} variance={:?}",
|
||||||
|
substs,
|
||||||
|
variance);
|
||||||
|
|
||||||
self.add_constraints_from_substs(current,
|
// Trait are always invariant so we can take advantage of that.
|
||||||
trait_ref.def_id,
|
let variance_i = self.invariant(variance);
|
||||||
&trait_generics.types,
|
for ty in substs.types() {
|
||||||
&trait_generics.regions,
|
self.add_constraints_from_ty(current, ty, variance_i);
|
||||||
trait_ref.substs,
|
}
|
||||||
variance);
|
|
||||||
|
for region in substs.regions() {
|
||||||
|
self.add_constraints_from_region(current, region, variance_i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds constraints appropriate for an instance of `ty` appearing
|
/// Adds constraints appropriate for an instance of `ty` appearing
|
||||||
@ -383,8 +294,7 @@ fn add_constraints_from_ty(&mut self,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ty::TyFnDef(..) |
|
ty::TyFnDef(..) |
|
||||||
ty::TyClosure(..) |
|
ty::TyClosure(..) => {
|
||||||
ty::TyAnon(..) => {
|
|
||||||
bug!("Unexpected closure type in variance computation");
|
bug!("Unexpected closure type in variance computation");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -410,26 +320,15 @@ fn add_constraints_from_ty(&mut self,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ty::TyAdt(def, substs) => {
|
ty::TyAdt(def, substs) => {
|
||||||
let adt_generics = self.read_generics(current, def.did);
|
self.add_constraints_from_substs(current, def.did, substs, variance);
|
||||||
|
|
||||||
self.add_constraints_from_substs(current,
|
|
||||||
def.did,
|
|
||||||
&adt_generics.types,
|
|
||||||
&adt_generics.regions,
|
|
||||||
substs,
|
|
||||||
variance);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::TyProjection(ref data) => {
|
ty::TyProjection(ref data) => {
|
||||||
let trait_ref = &data.trait_ref;
|
self.add_constraints_from_trait_ref(current, data.trait_ref, variance);
|
||||||
let trait_generics = self.tcx().generics_of(trait_ref.def_id);
|
}
|
||||||
|
|
||||||
self.add_constraints_from_substs(current,
|
ty::TyAnon(_, substs) => {
|
||||||
trait_ref.def_id,
|
self.add_constraints_from_invariant_substs(current, substs, variance);
|
||||||
&trait_generics.types,
|
|
||||||
&trait_generics.regions,
|
|
||||||
trait_ref.substs,
|
|
||||||
variance);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::TyDynamic(ref data, r) => {
|
ty::TyDynamic(ref data, r) => {
|
||||||
@ -448,23 +347,7 @@ fn add_constraints_from_ty(&mut self,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ty::TyParam(ref data) => {
|
ty::TyParam(ref data) => {
|
||||||
assert_eq!(current.generics.parent, None);
|
self.add_constraint(current, data.idx, variance);
|
||||||
let mut i = data.idx as usize;
|
|
||||||
if !current.generics.has_self || i > 0 {
|
|
||||||
i -= current.generics.regions.len();
|
|
||||||
}
|
|
||||||
let def_id = current.generics.types[i].def_id;
|
|
||||||
let node_id = self.tcx().hir.as_local_node_id(def_id).unwrap();
|
|
||||||
match self.terms_cx.inferred_map.get(&node_id) {
|
|
||||||
Some(&index) => {
|
|
||||||
self.add_constraint(index, variance);
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
// We do not infer variance for type parameters
|
|
||||||
// declared on methods. They will not be present
|
|
||||||
// in the inferred_map.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::TyFnPtr(sig) => {
|
ty::TyFnPtr(sig) => {
|
||||||
@ -489,8 +372,6 @@ fn add_constraints_from_ty(&mut self,
|
|||||||
fn add_constraints_from_substs(&mut self,
|
fn add_constraints_from_substs(&mut self,
|
||||||
current: &CurrentItem,
|
current: &CurrentItem,
|
||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
type_param_defs: &[ty::TypeParameterDef],
|
|
||||||
region_param_defs: &[ty::RegionParameterDef],
|
|
||||||
substs: &Substs<'tcx>,
|
substs: &Substs<'tcx>,
|
||||||
variance: VarianceTermPtr<'a>) {
|
variance: VarianceTermPtr<'a>) {
|
||||||
debug!("add_constraints_from_substs(def_id={:?}, substs={:?}, variance={:?})",
|
debug!("add_constraints_from_substs(def_id={:?}, substs={:?}, variance={:?})",
|
||||||
@ -498,21 +379,45 @@ fn add_constraints_from_substs(&mut self,
|
|||||||
substs,
|
substs,
|
||||||
variance);
|
variance);
|
||||||
|
|
||||||
for p in type_param_defs {
|
// We don't record `inferred_starts` entries for empty generics.
|
||||||
let variance_decl = self.declared_variance(p.def_id, def_id, p.index as usize);
|
if substs.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a corresponding relation into the dependencies to
|
||||||
|
// indicate that the variance for `current` relies on `def_id`.
|
||||||
|
if self.tcx().dep_graph.is_fully_enabled() {
|
||||||
|
self.dependencies.add(current.def_id, def_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
let (local, remote) = if let Some(id) = self.tcx().hir.as_local_node_id(def_id) {
|
||||||
|
(Some(self.terms_cx.inferred_starts[&id]), None)
|
||||||
|
} else {
|
||||||
|
(None, Some(self.tcx().variances_of(def_id)))
|
||||||
|
};
|
||||||
|
|
||||||
|
for (i, k) in substs.iter().enumerate() {
|
||||||
|
let variance_decl = if let Some(InferredIndex(start)) = local {
|
||||||
|
// Parameter on an item defined within current crate:
|
||||||
|
// variance not yet inferred, so return a symbolic
|
||||||
|
// variance.
|
||||||
|
self.terms_cx.inferred_terms[start + i]
|
||||||
|
} else {
|
||||||
|
// Parameter on an item defined within another crate:
|
||||||
|
// variance already inferred, just look it up.
|
||||||
|
self.constant_term(remote.as_ref().unwrap()[i])
|
||||||
|
};
|
||||||
let variance_i = self.xform(variance, variance_decl);
|
let variance_i = self.xform(variance, variance_decl);
|
||||||
let substs_ty = substs.type_for_def(p);
|
|
||||||
debug!("add_constraints_from_substs: variance_decl={:?} variance_i={:?}",
|
debug!("add_constraints_from_substs: variance_decl={:?} variance_i={:?}",
|
||||||
variance_decl,
|
variance_decl,
|
||||||
variance_i);
|
variance_i);
|
||||||
self.add_constraints_from_ty(current, substs_ty, variance_i);
|
if let Some(ty) = k.as_type() {
|
||||||
}
|
self.add_constraints_from_ty(current, ty, variance_i);
|
||||||
|
} else if let Some(r) = k.as_region() {
|
||||||
for p in region_param_defs {
|
self.add_constraints_from_region(current, r, variance_i);
|
||||||
let variance_decl = self.declared_variance(p.def_id, def_id, p.index as usize);
|
} else {
|
||||||
let variance_i = self.xform(variance, variance_decl);
|
bug!();
|
||||||
let substs_r = substs.region_for_def(p);
|
}
|
||||||
self.add_constraints_from_region(current, substs_r, variance_i);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -537,21 +442,14 @@ fn add_constraints_from_region(&mut self,
|
|||||||
variance: VarianceTermPtr<'a>) {
|
variance: VarianceTermPtr<'a>) {
|
||||||
match *region {
|
match *region {
|
||||||
ty::ReEarlyBound(ref data) => {
|
ty::ReEarlyBound(ref data) => {
|
||||||
assert_eq!(current.generics.parent, None);
|
self.add_constraint(current, data.index, variance);
|
||||||
let i = data.index as usize - current.generics.has_self as usize;
|
|
||||||
let def_id = current.generics.regions[i].def_id;
|
|
||||||
let node_id = self.tcx().hir.as_local_node_id(def_id).unwrap();
|
|
||||||
if self.is_to_be_inferred(node_id) {
|
|
||||||
let &index = self.opt_inferred_index(node_id).unwrap();
|
|
||||||
self.add_constraint(index, variance);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::ReStatic => {}
|
ty::ReStatic => {}
|
||||||
|
|
||||||
ty::ReLateBound(..) => {
|
ty::ReLateBound(..) => {
|
||||||
// We do not infer variance for region parameters on
|
// Late-bound regions do not get substituted the same
|
||||||
// methods or in fn types.
|
// way early-bound regions do, so we skip them here.
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::ReFree(..) |
|
ty::ReFree(..) |
|
||||||
|
@ -54,45 +54,63 @@ fn crate_variances<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum)
|
|||||||
|
|
||||||
fn variances_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_def_id: DefId)
|
fn variances_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_def_id: DefId)
|
||||||
-> Rc<Vec<ty::Variance>> {
|
-> Rc<Vec<ty::Variance>> {
|
||||||
let item_id = tcx.hir.as_local_node_id(item_def_id).expect("expected local def-id");
|
let id = tcx.hir.as_local_node_id(item_def_id).expect("expected local def-id");
|
||||||
let item = tcx.hir.expect_item(item_id);
|
let unsupported = || {
|
||||||
match item.node {
|
// Variance not relevant.
|
||||||
hir::ItemTrait(..) => {
|
span_bug!(tcx.hir.span(id), "asked to compute variance for wrong kind of item")
|
||||||
// Traits are always invariant.
|
};
|
||||||
let generics = tcx.generics_of(item_def_id);
|
match tcx.hir.get(id) {
|
||||||
assert!(generics.parent.is_none());
|
hir::map::NodeItem(item) => match item.node {
|
||||||
Rc::new(vec![ty::Variance::Invariant; generics.count()])
|
hir::ItemEnum(..) |
|
||||||
}
|
hir::ItemStruct(..) |
|
||||||
|
hir::ItemUnion(..) |
|
||||||
|
hir::ItemFn(..) => {}
|
||||||
|
|
||||||
hir::ItemEnum(..) |
|
_ => unsupported()
|
||||||
hir::ItemStruct(..) |
|
},
|
||||||
hir::ItemUnion(..) => {
|
|
||||||
// Everything else must be inferred.
|
|
||||||
|
|
||||||
// Lacking red/green, we read the variances for all items here
|
hir::map::NodeTraitItem(item) => match item.node {
|
||||||
// but ignore the dependencies, then re-synthesize the ones we need.
|
hir::TraitItemKind::Method(..) => {}
|
||||||
let crate_map = tcx.dep_graph.with_ignore(|| tcx.crate_variances(LOCAL_CRATE));
|
|
||||||
let dep_node = item_def_id.to_dep_node(tcx, DepKind::ItemVarianceConstraints);
|
_ => unsupported()
|
||||||
|
},
|
||||||
|
|
||||||
|
hir::map::NodeImplItem(item) => match item.node {
|
||||||
|
hir::ImplItemKind::Method(..) => {}
|
||||||
|
|
||||||
|
_ => unsupported()
|
||||||
|
},
|
||||||
|
|
||||||
|
hir::map::NodeForeignItem(item) => match item.node {
|
||||||
|
hir::ForeignItemFn(..) => {}
|
||||||
|
|
||||||
|
_ => unsupported()
|
||||||
|
},
|
||||||
|
|
||||||
|
hir::map::NodeVariant(_) | hir::map::NodeStructCtor(_) => {}
|
||||||
|
|
||||||
|
_ => unsupported()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Everything else must be inferred.
|
||||||
|
|
||||||
|
// Lacking red/green, we read the variances for all items here
|
||||||
|
// but ignore the dependencies, then re-synthesize the ones we need.
|
||||||
|
let crate_map = tcx.dep_graph.with_ignore(|| tcx.crate_variances(LOCAL_CRATE));
|
||||||
|
let dep_node = item_def_id.to_dep_node(tcx, DepKind::ItemVarianceConstraints);
|
||||||
|
tcx.dep_graph.read(dep_node);
|
||||||
|
for &dep_def_id in crate_map.dependencies.less_than(&item_def_id) {
|
||||||
|
if dep_def_id.is_local() {
|
||||||
|
let dep_node = dep_def_id.to_dep_node(tcx, DepKind::ItemVarianceConstraints);
|
||||||
|
tcx.dep_graph.read(dep_node);
|
||||||
|
} else {
|
||||||
|
let dep_node = dep_def_id.to_dep_node(tcx, DepKind::ItemVariances);
|
||||||
tcx.dep_graph.read(dep_node);
|
tcx.dep_graph.read(dep_node);
|
||||||
for &dep_def_id in crate_map.dependencies.less_than(&item_def_id) {
|
|
||||||
if dep_def_id.is_local() {
|
|
||||||
let dep_node = dep_def_id.to_dep_node(tcx, DepKind::ItemVarianceConstraints);
|
|
||||||
tcx.dep_graph.read(dep_node);
|
|
||||||
} else {
|
|
||||||
let dep_node = dep_def_id.to_dep_node(tcx, DepKind::ItemVariances);
|
|
||||||
tcx.dep_graph.read(dep_node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
crate_map.variances.get(&item_def_id)
|
|
||||||
.unwrap_or(&crate_map.empty_variance)
|
|
||||||
.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => {
|
|
||||||
// Variance not relevant.
|
|
||||||
span_bug!(item.span, "asked to compute variance for wrong kind of item")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
crate_map.variances.get(&item_def_id)
|
||||||
|
.unwrap_or(&crate_map.empty_variance)
|
||||||
|
.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,15 +36,18 @@ struct SolveContext<'a, 'tcx: 'a> {
|
|||||||
pub fn solve_constraints(constraints_cx: ConstraintContext) -> ty::CrateVariancesMap {
|
pub fn solve_constraints(constraints_cx: ConstraintContext) -> ty::CrateVariancesMap {
|
||||||
let ConstraintContext { terms_cx, dependencies, constraints, .. } = constraints_cx;
|
let ConstraintContext { terms_cx, dependencies, constraints, .. } = constraints_cx;
|
||||||
|
|
||||||
let solutions = terms_cx.inferred_infos
|
let mut solutions = vec![ty::Bivariant; terms_cx.inferred_terms.len()];
|
||||||
.iter()
|
for &(id, ref variances) in &terms_cx.lang_items {
|
||||||
.map(|ii| ii.initial_variance)
|
let InferredIndex(start) = terms_cx.inferred_starts[&id];
|
||||||
.collect();
|
for (i, &variance) in variances.iter().enumerate() {
|
||||||
|
solutions[start + i] = variance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut solutions_cx = SolveContext {
|
let mut solutions_cx = SolveContext {
|
||||||
terms_cx: terms_cx,
|
terms_cx,
|
||||||
constraints: constraints,
|
constraints,
|
||||||
solutions: solutions,
|
solutions,
|
||||||
};
|
};
|
||||||
solutions_cx.solve();
|
solutions_cx.solve();
|
||||||
let variances = solutions_cx.create_map();
|
let variances = solutions_cx.create_map();
|
||||||
@ -71,12 +74,9 @@ fn solve(&mut self) {
|
|||||||
let old_value = self.solutions[inferred];
|
let old_value = self.solutions[inferred];
|
||||||
let new_value = glb(variance, old_value);
|
let new_value = glb(variance, old_value);
|
||||||
if old_value != new_value {
|
if old_value != new_value {
|
||||||
debug!("Updating inferred {} (node {}) \
|
debug!("Updating inferred {} \
|
||||||
from {:?} to {:?} due to {:?}",
|
from {:?} to {:?} due to {:?}",
|
||||||
inferred,
|
inferred,
|
||||||
self.terms_cx
|
|
||||||
.inferred_infos[inferred]
|
|
||||||
.param_id,
|
|
||||||
old_value,
|
old_value,
|
||||||
new_value,
|
new_value,
|
||||||
term);
|
term);
|
||||||
@ -89,49 +89,28 @@ fn solve(&mut self) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn create_map(&self) -> FxHashMap<DefId, Rc<Vec<ty::Variance>>> {
|
fn create_map(&self) -> FxHashMap<DefId, Rc<Vec<ty::Variance>>> {
|
||||||
// Collect all the variances for a particular item and stick
|
|
||||||
// them into the variance map. We rely on the fact that we
|
|
||||||
// generate all the inferreds for a particular item
|
|
||||||
// consecutively (that is, we collect solutions for an item
|
|
||||||
// until we see a new item id, and we assume (1) the solutions
|
|
||||||
// are in the same order as the type parameters were declared
|
|
||||||
// and (2) all solutions or a given item appear before a new
|
|
||||||
// item id).
|
|
||||||
|
|
||||||
let tcx = self.terms_cx.tcx;
|
let tcx = self.terms_cx.tcx;
|
||||||
|
|
||||||
let mut map = FxHashMap();
|
|
||||||
|
|
||||||
let solutions = &self.solutions;
|
let solutions = &self.solutions;
|
||||||
let inferred_infos = &self.terms_cx.inferred_infos;
|
self.terms_cx.inferred_starts.iter().map(|(&id, &InferredIndex(start))| {
|
||||||
let mut index = 0;
|
let def_id = tcx.hir.local_def_id(id);
|
||||||
let num_inferred = self.terms_cx.num_inferred();
|
let generics = tcx.generics_of(def_id);
|
||||||
while index < num_inferred {
|
|
||||||
let item_id = inferred_infos[index].item_id;
|
|
||||||
|
|
||||||
let mut item_variances = vec![];
|
let mut variances = solutions[start..start+generics.count()].to_vec();
|
||||||
|
|
||||||
while index < num_inferred && inferred_infos[index].item_id == item_id {
|
debug!("id={} variances={:?}", id, variances);
|
||||||
let info = &inferred_infos[index];
|
|
||||||
let variance = solutions[index];
|
|
||||||
debug!("Index {} Info {} Variance {:?}",
|
|
||||||
index,
|
|
||||||
info.index,
|
|
||||||
variance);
|
|
||||||
|
|
||||||
assert_eq!(item_variances.len(), info.index);
|
// Functions can have unused type parameters: make those invariant.
|
||||||
item_variances.push(variance);
|
if let ty::TyFnDef(..) = tcx.type_of(def_id).sty {
|
||||||
index += 1;
|
for variance in &mut variances {
|
||||||
|
if *variance == ty::Bivariant {
|
||||||
|
*variance = ty::Invariant;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("item_id={} item_variances={:?}", item_id, item_variances);
|
(def_id, Rc::new(variances))
|
||||||
|
}).collect()
|
||||||
let item_def_id = tcx.hir.local_def_id(item_id);
|
|
||||||
|
|
||||||
map.insert(item_def_id, Rc::new(item_variances));
|
|
||||||
}
|
|
||||||
|
|
||||||
map
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn evaluate(&self, term: VarianceTermPtr<'a>) -> ty::Variance {
|
fn evaluate(&self, term: VarianceTermPtr<'a>) -> ty::Variance {
|
||||||
|
@ -22,7 +22,6 @@
|
|||||||
use arena::TypedArena;
|
use arena::TypedArena;
|
||||||
use rustc::ty::{self, TyCtxt};
|
use rustc::ty::{self, TyCtxt};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::rc::Rc;
|
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use rustc::hir;
|
use rustc::hir;
|
||||||
use rustc::hir::itemlikevisit::ItemLikeVisitor;
|
use rustc::hir::itemlikevisit::ItemLikeVisitor;
|
||||||
@ -63,31 +62,17 @@ pub struct TermsContext<'a, 'tcx: 'a> {
|
|||||||
pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
pub arena: &'a TypedArena<VarianceTerm<'a>>,
|
pub arena: &'a TypedArena<VarianceTerm<'a>>,
|
||||||
|
|
||||||
pub empty_variances: Rc<Vec<ty::Variance>>,
|
|
||||||
|
|
||||||
// For marker types, UnsafeCell, and other lang items where
|
// For marker types, UnsafeCell, and other lang items where
|
||||||
// variance is hardcoded, records the item-id and the hardcoded
|
// variance is hardcoded, records the item-id and the hardcoded
|
||||||
// variance.
|
// variance.
|
||||||
pub lang_items: Vec<(ast::NodeId, Vec<ty::Variance>)>,
|
pub lang_items: Vec<(ast::NodeId, Vec<ty::Variance>)>,
|
||||||
|
|
||||||
// Maps from the node id of a type/generic parameter to the
|
// Maps from the node id of an item to the first inferred index
|
||||||
// corresponding inferred index.
|
// used for its type & region parameters.
|
||||||
pub inferred_map: NodeMap<InferredIndex>,
|
pub inferred_starts: NodeMap<InferredIndex>,
|
||||||
|
|
||||||
// Maps from an InferredIndex to the info for that variable.
|
// Maps from an InferredIndex to the term for that variable.
|
||||||
pub inferred_infos: Vec<InferredInfo<'a>>,
|
pub inferred_terms: Vec<VarianceTermPtr<'a>>,
|
||||||
}
|
|
||||||
|
|
||||||
pub struct InferredInfo<'a> {
|
|
||||||
pub item_id: ast::NodeId,
|
|
||||||
pub index: usize,
|
|
||||||
pub param_id: ast::NodeId,
|
|
||||||
pub term: VarianceTermPtr<'a>,
|
|
||||||
|
|
||||||
// Initial value to use for this parameter when inferring
|
|
||||||
// variance. For most parameters, this is Bivariant. But for lang
|
|
||||||
// items and input type parameters on traits, it is different.
|
|
||||||
pub initial_variance: ty::Variance,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn determine_parameters_to_be_inferred<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
pub fn determine_parameters_to_be_inferred<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
@ -96,14 +81,10 @@ pub fn determine_parameters_to_be_inferred<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>
|
|||||||
let mut terms_cx = TermsContext {
|
let mut terms_cx = TermsContext {
|
||||||
tcx: tcx,
|
tcx: tcx,
|
||||||
arena: arena,
|
arena: arena,
|
||||||
inferred_map: NodeMap(),
|
inferred_starts: NodeMap(),
|
||||||
inferred_infos: Vec::new(),
|
inferred_terms: vec![],
|
||||||
|
|
||||||
lang_items: lang_items(tcx),
|
lang_items: lang_items(tcx),
|
||||||
|
|
||||||
// cache and share the variance struct used for items with
|
|
||||||
// no type/region parameters
|
|
||||||
empty_variances: Rc::new(vec![]),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// See README.md for a discussion on dep-graph management.
|
// See README.md for a discussion on dep-graph management.
|
||||||
@ -135,67 +116,28 @@ fn lang_items(tcx: TyCtxt) -> Vec<(ast::NodeId, Vec<ty::Variance>)> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> TermsContext<'a, 'tcx> {
|
impl<'a, 'tcx> TermsContext<'a, 'tcx> {
|
||||||
fn add_inferreds_for_item(&mut self,
|
fn add_inferreds_for_item(&mut self, id: ast::NodeId) {
|
||||||
item_id: ast::NodeId,
|
let tcx = self.tcx;
|
||||||
generics: &hir::Generics) {
|
let def_id = tcx.hir.local_def_id(id);
|
||||||
//! Add "inferreds" for the generic parameters declared on this
|
let count = tcx.generics_of(def_id).count();
|
||||||
//! item. This has a lot of annoying parameters because we are
|
|
||||||
//! trying to drive this from the AST, rather than the
|
if count == 0 {
|
||||||
//! ty::Generics, so that we can get span info -- but this
|
return;
|
||||||
//! means we must accommodate syntactic distinctions.
|
}
|
||||||
//!
|
|
||||||
|
// Record the start of this item's inferreds.
|
||||||
|
let start = self.inferred_terms.len();
|
||||||
|
let newly_added = self.inferred_starts.insert(id, InferredIndex(start)).is_none();
|
||||||
|
assert!(newly_added);
|
||||||
|
|
||||||
// NB: In the code below for writing the results back into the
|
// NB: In the code below for writing the results back into the
|
||||||
// `CrateVariancesMap`, we rely on the fact that all inferreds
|
// `CrateVariancesMap`, we rely on the fact that all inferreds
|
||||||
// for a particular item are assigned continuous indices.
|
// for a particular item are assigned continuous indices.
|
||||||
|
|
||||||
for (p, i) in generics.lifetimes.iter().zip(0..) {
|
let arena = self.arena;
|
||||||
let id = p.lifetime.id;
|
self.inferred_terms.extend((start..start+count).map(|i| {
|
||||||
self.add_inferred(item_id, i, id);
|
&*arena.alloc(InferredTerm(InferredIndex(i)))
|
||||||
}
|
}));
|
||||||
|
|
||||||
for (p, i) in generics.ty_params.iter().zip(generics.lifetimes.len()..) {
|
|
||||||
self.add_inferred(item_id, i, p.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_inferred(&mut self, item_id: ast::NodeId, index: usize, param_id: ast::NodeId) {
|
|
||||||
let inf_index = InferredIndex(self.inferred_infos.len());
|
|
||||||
let term = self.arena.alloc(InferredTerm(inf_index));
|
|
||||||
let initial_variance = self.pick_initial_variance(item_id, index);
|
|
||||||
self.inferred_infos.push(InferredInfo {
|
|
||||||
item_id: item_id,
|
|
||||||
index: index,
|
|
||||||
param_id: param_id,
|
|
||||||
term: term,
|
|
||||||
initial_variance: initial_variance,
|
|
||||||
});
|
|
||||||
let newly_added = self.inferred_map.insert(param_id, inf_index).is_none();
|
|
||||||
assert!(newly_added);
|
|
||||||
|
|
||||||
debug!("add_inferred(item_path={}, \
|
|
||||||
item_id={}, \
|
|
||||||
index={}, \
|
|
||||||
param_id={}, \
|
|
||||||
inf_index={:?}, \
|
|
||||||
initial_variance={:?})",
|
|
||||||
self.tcx.item_path_str(self.tcx.hir.local_def_id(item_id)),
|
|
||||||
item_id,
|
|
||||||
index,
|
|
||||||
param_id,
|
|
||||||
inf_index,
|
|
||||||
initial_variance);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pick_initial_variance(&self, item_id: ast::NodeId, index: usize) -> ty::Variance {
|
|
||||||
match self.lang_items.iter().find(|&&(n, _)| n == item_id) {
|
|
||||||
Some(&(_, ref variances)) => variances[index],
|
|
||||||
None => ty::Bivariant,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn num_inferred(&self) -> usize {
|
|
||||||
self.inferred_infos.len()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,30 +147,50 @@ fn visit_item(&mut self, item: &hir::Item) {
|
|||||||
self.tcx.hir.node_to_string(item.id));
|
self.tcx.hir.node_to_string(item.id));
|
||||||
|
|
||||||
match item.node {
|
match item.node {
|
||||||
hir::ItemEnum(_, ref generics) |
|
hir::ItemStruct(ref struct_def, _) |
|
||||||
hir::ItemStruct(_, ref generics) |
|
hir::ItemUnion(ref struct_def, _) => {
|
||||||
hir::ItemUnion(_, ref generics) => {
|
self.add_inferreds_for_item(item.id);
|
||||||
self.add_inferreds_for_item(item.id, generics);
|
|
||||||
|
if let hir::VariantData::Tuple(..) = *struct_def {
|
||||||
|
self.add_inferreds_for_item(struct_def.id());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hir::ItemTrait(..) |
|
hir::ItemEnum(ref enum_def, _) => {
|
||||||
hir::ItemExternCrate(_) |
|
self.add_inferreds_for_item(item.id);
|
||||||
hir::ItemUse(..) |
|
|
||||||
hir::ItemDefaultImpl(..) |
|
for variant in &enum_def.variants {
|
||||||
hir::ItemImpl(..) |
|
if let hir::VariantData::Tuple(..) = variant.node.data {
|
||||||
hir::ItemStatic(..) |
|
self.add_inferreds_for_item(variant.node.data.id());
|
||||||
hir::ItemConst(..) |
|
}
|
||||||
hir::ItemFn(..) |
|
}
|
||||||
hir::ItemMod(..) |
|
}
|
||||||
hir::ItemForeignMod(..) |
|
|
||||||
hir::ItemGlobalAsm(..) |
|
hir::ItemFn(..) => {
|
||||||
hir::ItemTy(..) => {}
|
self.add_inferreds_for_item(item.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
hir::ItemForeignMod(ref foreign_mod) => {
|
||||||
|
for foreign_item in &foreign_mod.items {
|
||||||
|
if let hir::ForeignItemFn(..) = foreign_item.node {
|
||||||
|
self.add_inferreds_for_item(foreign_item.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
|
fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) {
|
||||||
|
if let hir::TraitItemKind::Method(..) = trait_item.node {
|
||||||
|
self.add_inferreds_for_item(trait_item.id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
|
fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) {
|
||||||
|
if let hir::ImplItemKind::Method(..) = impl_item.node {
|
||||||
|
self.add_inferreds_for_item(impl_item.id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,25 +0,0 @@
|
|||||||
// 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.
|
|
||||||
|
|
||||||
// Check that `T:'a` is contravariant in T.
|
|
||||||
|
|
||||||
#![feature(rustc_attrs)]
|
|
||||||
|
|
||||||
#[rustc_variance]
|
|
||||||
trait Foo: 'static { //~ ERROR [o]
|
|
||||||
}
|
|
||||||
|
|
||||||
#[rustc_variance]
|
|
||||||
trait Bar<T> { //~ ERROR [o, o]
|
|
||||||
fn do_it(&self)
|
|
||||||
where T: 'static;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() { }
|
|
@ -14,13 +14,11 @@
|
|||||||
// Check that bounds on type parameters (other than `Self`) do not
|
// Check that bounds on type parameters (other than `Self`) do not
|
||||||
// influence variance.
|
// influence variance.
|
||||||
|
|
||||||
#[rustc_variance]
|
trait Getter<T> {
|
||||||
trait Getter<T> { //~ ERROR [o, o]
|
|
||||||
fn get(&self) -> T;
|
fn get(&self) -> T;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rustc_variance]
|
trait Setter<T> {
|
||||||
trait Setter<T> { //~ ERROR [o, o]
|
|
||||||
fn get(&self, T);
|
fn get(&self, T);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,20 +32,6 @@ enum TestEnum<U,T:Setter<U>> { //~ ERROR [*, +]
|
|||||||
Foo(T)
|
Foo(T)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rustc_variance]
|
|
||||||
trait TestTrait<U,T:Setter<U>> { //~ ERROR [o, o, o]
|
|
||||||
fn getter(&self, u: U) -> T;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[rustc_variance]
|
|
||||||
trait TestTrait2<U> : Getter<U> { //~ ERROR [o, o]
|
|
||||||
}
|
|
||||||
|
|
||||||
#[rustc_variance]
|
|
||||||
trait TestTrait3<U> { //~ ERROR [o, o]
|
|
||||||
fn getter<T:Getter<U>>(&self);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[rustc_variance]
|
#[rustc_variance]
|
||||||
struct TestContraStruct<U,T:Setter<U>> { //~ ERROR [*, +]
|
struct TestContraStruct<U,T:Setter<U>> { //~ ERROR [*, +]
|
||||||
t: T
|
t: T
|
||||||
|
@ -36,37 +36,14 @@ struct TestIndirect2<A:'static, B:'static> { //~ ERROR [o, o]
|
|||||||
m: TestMut<B, A>
|
m: TestMut<B, A>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rustc_variance]
|
trait Getter<A> {
|
||||||
trait Getter<A> { //~ ERROR [o, o]
|
|
||||||
fn get(&self) -> A;
|
fn get(&self) -> A;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rustc_variance]
|
trait Setter<A> {
|
||||||
trait Setter<A> { //~ ERROR [o, o]
|
|
||||||
fn set(&mut self, a: A);
|
fn set(&mut self, a: A);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rustc_variance]
|
|
||||||
trait GetterSetter<A> { //~ ERROR [o, o]
|
|
||||||
fn get(&self) -> A;
|
|
||||||
fn set(&mut self, a: A);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[rustc_variance]
|
|
||||||
trait GetterInTypeBound<A> { //~ ERROR [o, o]
|
|
||||||
// Here, the use of `A` in the method bound *does* affect
|
|
||||||
// variance. Think of it as if the method requested a dictionary
|
|
||||||
// for `T:Getter<A>`. Since this dictionary is an input, it is
|
|
||||||
// contravariant, and the Getter is covariant w/r/t A, yielding an
|
|
||||||
// overall contravariant result.
|
|
||||||
fn do_it<T:Getter<A>>(&self);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[rustc_variance]
|
|
||||||
trait SetterInTypeBound<A> { //~ ERROR [o, o]
|
|
||||||
fn do_it<T:Setter<A>>(&self);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[rustc_variance]
|
#[rustc_variance]
|
||||||
struct TestObject<A, R> { //~ ERROR [o, o]
|
struct TestObject<A, R> { //~ ERROR [o, o]
|
||||||
n: Box<Setter<A>+Send>,
|
n: Box<Setter<A>+Send>,
|
||||||
|
Loading…
Reference in New Issue
Block a user