Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Track constness while lowering bounds
  • Loading branch information
ecstatic-morse committed Jan 20, 2020
1 parent d2aefbb commit adbd01e
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 26 deletions.
2 changes: 1 addition & 1 deletion src/librustc_privacy/lib.rs
Expand Up @@ -1237,7 +1237,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
// The traits' privacy in bodies is already checked as a part of trait object types.
let bounds = rustc_typeck::hir_trait_to_predicates(self.tcx, trait_ref);

for (trait_predicate, _) in bounds.trait_bounds {
for (trait_predicate, _, _) in bounds.trait_bounds {
if self.visit_trait(*trait_predicate.skip_binder()) {
return;
}
Expand Down
54 changes: 35 additions & 19 deletions src/librustc_typeck/astconv.rs
Expand Up @@ -31,7 +31,7 @@ use rustc_span::symbol::sym;
use rustc_span::{MultiSpan, Span, DUMMY_SP};
use rustc_target::spec::abi;
use smallvec::SmallVec;
use syntax::ast;
use syntax::ast::{self, Constness};
use syntax::util::lev_distance::find_best_match_for_name;

use std::collections::BTreeSet;
Expand All @@ -49,6 +49,8 @@ pub trait AstConv<'tcx> {

fn item_def_id(&self) -> Option<DefId>;

fn default_constness_for_trait_bounds(&self) -> Constness;

/// Returns predicates in scope of the form `X: Foo`, where `X` is
/// a type parameter `X` with the given id `def_id`. This is a
/// subset of the full set of predicates.
Expand Down Expand Up @@ -919,6 +921,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
&self,
trait_ref: &hir::TraitRef<'_>,
span: Span,
constness: Constness,
self_ty: Ty<'tcx>,
bounds: &mut Bounds<'tcx>,
speculative: bool,
Expand Down Expand Up @@ -947,7 +950,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
);
let poly_trait_ref = ty::Binder::bind(ty::TraitRef::new(trait_def_id, substs));

bounds.trait_bounds.push((poly_trait_ref, span));
bounds.trait_bounds.push((poly_trait_ref, span, constness));

let mut dup_bindings = FxHashMap::default();
for binding in &assoc_bindings {
Expand Down Expand Up @@ -993,12 +996,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
pub fn instantiate_poly_trait_ref(
&self,
poly_trait_ref: &hir::PolyTraitRef<'_>,
constness: Constness,
self_ty: Ty<'tcx>,
bounds: &mut Bounds<'tcx>,
) -> Option<Vec<Span>> {
self.instantiate_poly_trait_ref_inner(
&poly_trait_ref.trait_ref,
poly_trait_ref.span,
constness,
self_ty,
bounds,
false,
Expand Down Expand Up @@ -1181,18 +1186,22 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let mut trait_bounds = Vec::new();
let mut region_bounds = Vec::new();

let constness = self.default_constness_for_trait_bounds();
for ast_bound in ast_bounds {
match *ast_bound {
hir::GenericBound::Trait(ref b, hir::TraitBoundModifier::None) => {
trait_bounds.push(b)
trait_bounds.push((b, constness))
}
hir::GenericBound::Trait(ref b, hir::TraitBoundModifier::MaybeConst) => {
trait_bounds.push((b, Constness::NotConst))
}
hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe) => {}
hir::GenericBound::Outlives(ref l) => region_bounds.push(l),
}
}

for bound in trait_bounds {
let _ = self.instantiate_poly_trait_ref(bound, param_ty, bounds);
for (bound, constness) in trait_bounds {
let _ = self.instantiate_poly_trait_ref(bound, constness, param_ty, bounds);
}

bounds.region_bounds.extend(
Expand Down Expand Up @@ -1226,7 +1235,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let mut bounds = Bounds::default();

self.add_bounds(param_ty, ast_bounds, &mut bounds);
bounds.trait_bounds.sort_by_key(|(t, _)| t.def_id());
bounds.trait_bounds.sort_by_key(|(t, _, _)| t.def_id());

bounds.implicitly_sized = if let SizedByDefault::Yes = sized_by_default {
if !self.is_unsized(ast_bounds, span) { Some(span) } else { None }
Expand Down Expand Up @@ -1417,15 +1426,21 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let mut potential_assoc_types = Vec::new();
let dummy_self = self.tcx().types.trait_object_dummy_self;
for trait_bound in trait_bounds.iter().rev() {
let cur_potential_assoc_types =
self.instantiate_poly_trait_ref(trait_bound, dummy_self, &mut bounds);
let cur_potential_assoc_types = self.instantiate_poly_trait_ref(
trait_bound,
Constness::NotConst,
dummy_self,
&mut bounds,
);
potential_assoc_types.extend(cur_potential_assoc_types.into_iter().flatten());
}

// Expand trait aliases recursively and check that only one regular (non-auto) trait
// is used and no 'maybe' bounds are used.
let expanded_traits =
traits::expand_trait_aliases(tcx, bounds.trait_bounds.iter().cloned());
let expanded_traits = traits::expand_trait_aliases(
tcx,
bounds.trait_bounds.iter().map(|&(a, b, _)| (a.clone(), b)),
);
let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) =
expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
if regular_traits.len() > 1 {
Expand Down Expand Up @@ -1481,16 +1496,18 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let regular_traits_refs_spans = bounds
.trait_bounds
.into_iter()
.filter(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id()));
.filter(|(trait_ref, _, _)| !tcx.trait_is_auto(trait_ref.def_id()));

for (base_trait_ref, span, constness) in regular_traits_refs_spans {
assert_eq!(constness, ast::Constness::NotConst);

for (base_trait_ref, span) in regular_traits_refs_spans {
for trait_ref in traits::elaborate_trait_ref(tcx, base_trait_ref) {
debug!(
"conv_object_ty_poly_trait_ref: observing object predicate `{:?}`",
trait_ref
);
match trait_ref {
ty::Predicate::Trait(pred, constness) => {
ty::Predicate::Trait(pred, _) => {
associated_types.entry(span).or_default().extend(
tcx.associated_items(pred.def_id())
.filter(|item| item.kind == ty::AssocKind::Type)
Expand Down Expand Up @@ -2949,7 +2966,7 @@ pub struct Bounds<'tcx> {

/// A list of trait bounds. So if you had `T: Debug` this would be
/// `T: Debug`. Note that the self-type is explicit here.
pub trait_bounds: Vec<(ty::PolyTraitRef<'tcx>, Span)>,
pub trait_bounds: Vec<(ty::PolyTraitRef<'tcx>, Span, Constness)>,

/// A list of projection equality bounds. So if you had `T:
/// Iterator<Item = u32>` this would include `<T as
Expand Down Expand Up @@ -2997,11 +3014,10 @@ impl<'tcx> Bounds<'tcx> {
let outlives = ty::OutlivesPredicate(param_ty, region_bound);
(ty::Binder::bind(outlives).to_predicate(), span)
})
.chain(
self.trait_bounds
.iter()
.map(|&(bound_trait_ref, span)| (bound_trait_ref.to_predicate(), span)),
)
.chain(self.trait_bounds.iter().map(|&(bound_trait_ref, span, constness)| {
let predicate = bound_trait_ref.with_constness(constness).to_predicate();
(predicate, span)
}))
.chain(
self.projection_bounds
.iter()
Expand Down
11 changes: 11 additions & 0 deletions src/librustc_typeck/check/mod.rs
Expand Up @@ -90,6 +90,7 @@ pub mod writeback;
use crate::astconv::{AstConv, PathSeg};
use crate::middle::lang_items;
use crate::namespace::Namespace;
use rustc::hir::map::blocks::FnLikeNode;
use rustc::hir::map::Map;
use rustc::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
use rustc::infer::error_reporting::TypeAnnotationNeeded::E0282;
Expand Down Expand Up @@ -2612,6 +2613,16 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
None
}

fn default_constness_for_trait_bounds(&self) -> ast::Constness {
// FIXME: refactor this into a method
let node = self.tcx.hir().get(self.body_id);
if let Some(fn_like) = FnLikeNode::from_node(node) {
fn_like.constness()
} else {
ast::Constness::NotConst
}
}

fn get_type_parameter_bounds(&self, _: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> {
let tcx = self.tcx;
let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
Expand Down
44 changes: 38 additions & 6 deletions src/librustc_typeck/collect.rs
Expand Up @@ -20,6 +20,7 @@ use crate::constrained_generic_params as cgp;
use crate::lint;
use crate::middle::resolve_lifetime as rl;
use crate::middle::weak_lang_items;
use rustc::hir::map::blocks::FnLikeNode;
use rustc::hir::map::Map;
use rustc::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
use rustc::mir::mono::Linkage;
Expand Down Expand Up @@ -288,6 +289,22 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> {
Some(self.item_def_id)
}

fn default_constness_for_trait_bounds(&self) -> ast::Constness {
// FIXME: refactor this into a method
let hir_id = self
.tcx
.hir()
.as_local_hir_id(self.item_def_id)
.expect("Non-local call to local provider is_const_fn");

let node = self.tcx.hir().get(hir_id);
if let Some(fn_like) = FnLikeNode::from_node(node) {
fn_like.constness()
} else {
ast::Constness::NotConst
}
}

fn get_type_parameter_bounds(&self, span: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> {
self.tcx.at(span).type_param_predicates((self.item_def_id, def_id))
}
Expand Down Expand Up @@ -454,6 +471,7 @@ impl ItemCtxt<'tcx> {
ty: Ty<'tcx>,
only_self_bounds: OnlySelfBounds,
) -> Vec<(ty::Predicate<'tcx>, Span)> {
let constness = self.default_constness_for_trait_bounds();
let from_ty_params = ast_generics
.params
.iter()
Expand All @@ -462,7 +480,7 @@ impl ItemCtxt<'tcx> {
_ => None,
})
.flat_map(|bounds| bounds.iter())
.flat_map(|b| predicates_from_bound(self, ty, b));
.flat_map(|b| predicates_from_bound(self, ty, b, constness));

let from_where_clauses = ast_generics
.where_clause
Expand All @@ -482,7 +500,7 @@ impl ItemCtxt<'tcx> {
};
bp.bounds.iter().filter_map(move |b| bt.map(|bt| (bt, b)))
})
.flat_map(|(bt, b)| predicates_from_bound(self, bt, b));
.flat_map(|(bt, b)| predicates_from_bound(self, bt, b, constness));

from_ty_params.chain(from_where_clauses).collect()
}
Expand Down Expand Up @@ -2107,6 +2125,7 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat
let mut is_default_impl_trait = None;

let icx = ItemCtxt::new(tcx, def_id);
let constness = icx.default_constness_for_trait_bounds();

const NO_GENERICS: &hir::Generics<'_> = &hir::Generics::empty();

Expand Down Expand Up @@ -2308,11 +2327,18 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat

for bound in bound_pred.bounds.iter() {
match bound {
&hir::GenericBound::Trait(ref poly_trait_ref, _) => {
&hir::GenericBound::Trait(ref poly_trait_ref, modifier) => {
let constness = match modifier {
hir::TraitBoundModifier::MaybeConst => ast::Constness::NotConst,
hir::TraitBoundModifier::None => constness,
hir::TraitBoundModifier::Maybe => bug!("this wasn't handled"),
};

let mut bounds = Bounds::default();
let _ = AstConv::instantiate_poly_trait_ref(
&icx,
poly_trait_ref,
constness,
ty,
&mut bounds,
);
Expand Down Expand Up @@ -2488,19 +2514,25 @@ fn predicates_from_bound<'tcx>(
astconv: &dyn AstConv<'tcx>,
param_ty: Ty<'tcx>,
bound: &'tcx hir::GenericBound<'tcx>,
constness: ast::Constness,
) -> Vec<(ty::Predicate<'tcx>, Span)> {
match *bound {
hir::GenericBound::Trait(ref tr, hir::TraitBoundModifier::None) => {
hir::GenericBound::Trait(ref tr, modifier) => {
let constness = match modifier {
hir::TraitBoundModifier::Maybe => return vec![],
hir::TraitBoundModifier::MaybeConst => ast::Constness::NotConst,
hir::TraitBoundModifier::None => constness,
};

let mut bounds = Bounds::default();
let _ = astconv.instantiate_poly_trait_ref(tr, param_ty, &mut bounds);
let _ = astconv.instantiate_poly_trait_ref(tr, constness, param_ty, &mut bounds);
bounds.predicates(astconv.tcx(), param_ty)
}
hir::GenericBound::Outlives(ref lifetime) => {
let region = astconv.ast_region_to_region(lifetime, None);
let pred = ty::Binder::bind(ty::OutlivesPredicate(param_ty, region));
vec![(ty::Predicate::TypeOutlives(pred), lifetime.span)]
}
hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe) => vec![],
}
}

Expand Down
1 change: 1 addition & 0 deletions src/librustc_typeck/lib.rs
Expand Up @@ -382,6 +382,7 @@ pub fn hir_trait_to_predicates<'tcx>(
&item_cx,
hir_trait,
DUMMY_SP,
syntax::ast::Constness::NotConst,
tcx.types.err,
&mut bounds,
true,
Expand Down

0 comments on commit adbd01e

Please sign in to comment.