Skip to content

Commit

Permalink
Add parser support for generalized where clauses
Browse files Browse the repository at this point in the history
Implement support in the parser for generalized where clauses,
as well as the conversion of ast::WherePredicates to
ty::Predicate in `collect.rs`.
  • Loading branch information
jroesch committed Dec 20, 2014
1 parent cbe9fb4 commit cee12ab
Show file tree
Hide file tree
Showing 25 changed files with 506 additions and 149 deletions.
1 change: 1 addition & 0 deletions src/librustc/middle/privacy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1459,6 +1459,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> {
self.check_ty_param_bound(bound_pred.span, bound)
}
}
&ast::WherePredicate::RegionPredicate(_) => {}
&ast::WherePredicate::EqPredicate(ref eq_pred) => {
self.visit_ty(&*eq_pred.ty);
}
Expand Down
19 changes: 3 additions & 16 deletions src/librustc/middle/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4570,27 +4570,14 @@ impl<'a> Resolver<'a> {
for predicate in where_clause.predicates.iter() {
match predicate {
&ast::WherePredicate::BoundPredicate(ref bound_pred) => {
match self.resolve_identifier(bound_pred.ident,
TypeNS,
true,
bound_pred.span) {
Some((def @ DefTyParam(..), last_private)) => {
self.record_def(bound_pred.id, (def, last_private));
}
_ => {
self.resolve_error(
bound_pred.span,
format!("undeclared type parameter `{}`",
token::get_ident(
bound_pred.ident)).as_slice());
}
}
self.resolve_type(&*bound_pred.bounded_ty);

for bound in bound_pred.bounds.iter() {
self.resolve_type_parameter_bound(bound_pred.id, bound,
self.resolve_type_parameter_bound(bound_pred.bounded_ty.id, bound,
TraitBoundingTypeParameter);
}
}
&ast::WherePredicate::RegionPredicate(_) => {}
&ast::WherePredicate::EqPredicate(ref eq_pred) => {
match self.resolve_path(eq_pred.id, &eq_pred.path, TypeNS, true) {
Some((def @ DefTyParam(..), last_private)) => {
Expand Down
23 changes: 19 additions & 4 deletions src/librustc/middle/resolve_lifetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,13 +207,19 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
}
for predicate in generics.where_clause.predicates.iter() {
match predicate {
&ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{ ident,
&ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{ ref bounded_ty,
ref bounds,
span,
.. }) => {
self.visit_ident(span, ident);
self.visit_ty(&**bounded_ty);
visit::walk_ty_param_bounds_helper(self, bounds);
}
&ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate{ref lifetime,
ref bound,
.. }) => {

self.visit_lifetime_ref(lifetime);
self.visit_lifetime_ref(bound);
}
&ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{ id,
ref path,
ref ty,
Expand Down Expand Up @@ -546,9 +552,18 @@ fn early_bound_lifetime_names(generics: &ast::Generics) -> Vec<ast::Name> {
}
for predicate in generics.where_clause.predicates.iter() {
match predicate {
&ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{ref bounds, ..}) => {
&ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{ref bounds,
ref bounded_ty,
..}) => {
collector.visit_ty(&**bounded_ty);
visit::walk_ty_param_bounds_helper(&mut collector, bounds);
}
&ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate{ref lifetime,
ref bound,
..}) => {
collector.visit_lifetime_ref(lifetime);
collector.visit_lifetime_ref(bound);
}
&ast::WherePredicate::EqPredicate(_) => unimplemented!()
}
}
Expand Down
10 changes: 3 additions & 7 deletions src/librustc_typeck/astconv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1437,11 +1437,8 @@ pub fn conv_existential_bounds<'tcx, AC: AstConv<'tcx>, RS:RegionScope>(
ast_bounds: &[ast::TyParamBound])
-> ty::ExistentialBounds
{
let ast_bound_refs: Vec<&ast::TyParamBound> =
ast_bounds.iter().collect();

let partitioned_bounds =
partition_bounds(this.tcx(), span, ast_bound_refs.as_slice());
partition_bounds(this.tcx(), span, ast_bounds);

conv_existential_bounds_from_partitioned_bounds(
this, rscope, span, principal_trait_ref, partitioned_bounds)
Expand All @@ -1455,7 +1452,6 @@ fn conv_ty_poly_trait_ref<'tcx, AC, RS>(
-> Ty<'tcx>
where AC: AstConv<'tcx>, RS:RegionScope
{
let ast_bounds: Vec<&ast::TyParamBound> = ast_bounds.iter().collect();
let mut partitioned_bounds = partition_bounds(this.tcx(), span, ast_bounds[]);

let main_trait_bound = match partitioned_bounds.trait_bounds.remove(0) {
Expand Down Expand Up @@ -1620,14 +1616,14 @@ pub struct PartitionedBounds<'a> {
/// general trait bounds, and region bounds.
pub fn partition_bounds<'a>(tcx: &ty::ctxt,
_span: Span,
ast_bounds: &'a [&ast::TyParamBound])
ast_bounds: &'a [ast::TyParamBound])
-> PartitionedBounds<'a>
{
let mut builtin_bounds = ty::empty_builtin_bounds();
let mut region_bounds = Vec::new();
let mut trait_bounds = Vec::new();
let mut trait_def_ids = DefIdMap::new();
for &ast_bound in ast_bounds.iter() {
for ast_bound in ast_bounds.iter() {
match *ast_bound {
ast::TraitTyParamBound(ref b) => {
match ::lookup_def_tcx(tcx, b.trait_ref.path.span, b.trait_ref.ref_id) {
Expand Down
108 changes: 54 additions & 54 deletions src/librustc_typeck/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1364,8 +1364,7 @@ pub fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
self_param_ty,
bounds.as_slice(),
unbound,
it.span,
&generics.where_clause);
it.span);

let substs = mk_item_substs(ccx, &ty_generics);
let trait_def = Rc::new(ty::TraitDef {
Expand Down Expand Up @@ -1619,7 +1618,6 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
subst::AssocSpace,
&associated_type.ty_param,
generics.types.len(subst::AssocSpace),
&ast_generics.where_clause,
Some(local_def(trait_id)));
ccx.tcx.ty_param_defs.borrow_mut().insert(associated_type.ty_param.id,
def.clone());
Expand Down Expand Up @@ -1774,7 +1772,6 @@ fn ty_generics<'tcx,AC>(this: &AC,
space,
param,
i,
where_clause,
None);
debug!("ty_generics: def for type param: {}, {}",
def.repr(this.tcx()),
Expand All @@ -1798,6 +1795,52 @@ fn ty_generics<'tcx,AC>(this: &AC,
// into the predicates list. This is currently kind of non-DRY.
create_predicates(this.tcx(), &mut result, space);

// Add the bounds not associated with a type parameter
for predicate in where_clause.predicates.iter() {
match predicate {
&ast::WherePredicate::BoundPredicate(ref bound_pred) => {
let ty = ast_ty_to_ty(this, &ExplicitRscope, &*bound_pred.bounded_ty);

for bound in bound_pred.bounds.iter() {
match bound {
&ast::TyParamBound::TraitTyParamBound(ref poly_trait_ref) => {
let trait_ref = astconv::instantiate_poly_trait_ref(
this,
&ExplicitRscope,
//@jroesch: for now trait_ref, poly_trait_ref?
poly_trait_ref,
Some(ty),
AllowEqConstraints::Allow
);

result.predicates.push(space, ty::Predicate::Trait(trait_ref));
}

&ast::TyParamBound::RegionTyParamBound(ref lifetime) => {
let region = ast_region_to_region(this.tcx(), lifetime);
let pred = ty::Binder(ty::OutlivesPredicate(ty, region));
result.predicates.push(space, ty::Predicate::TypeOutlives(pred))
}
}
}
}

&ast::WherePredicate::RegionPredicate(ref region_pred) => {
let r1 = ast_region_to_region(this.tcx(), &region_pred.lifetime);
let r2 = ast_region_to_region(this.tcx(), &region_pred.bound);
let pred = ty::Binder(ty::OutlivesPredicate(r1, r2));
result.predicates.push(space, ty::Predicate::RegionOutlives(pred))
}

&ast::WherePredicate::EqPredicate(ref eq_pred) => {
// FIXME(#20041)
this.tcx().sess.span_bug(eq_pred.span,
"Equality constraints are not yet \
implemented (#20041)")
}
}
}

return result;

fn create_type_parameters_for_associated_types<'tcx, AC>(
Expand Down Expand Up @@ -1915,7 +1958,6 @@ fn get_or_create_type_parameter_def<'tcx,AC>(this: &AC,
space: subst::ParamSpace,
param: &ast::TyParam,
index: uint,
where_clause: &ast::WhereClause,
associated_with: Option<ast::DefId>)
-> ty::TypeParameterDef<'tcx>
where AC: AstConv<'tcx>
Expand All @@ -1931,8 +1973,7 @@ fn get_or_create_type_parameter_def<'tcx,AC>(this: &AC,
param_ty,
param.bounds.as_slice(),
&param.unbound,
param.span,
where_clause);
param.span);
let default = match param.default {
None => None,
Some(ref path) => {
Expand Down Expand Up @@ -1977,15 +2018,13 @@ fn compute_bounds<'tcx,AC>(this: &AC,
param_ty: ty::ParamTy,
ast_bounds: &[ast::TyParamBound],
unbound: &Option<ast::TraitRef>,
span: Span,
where_clause: &ast::WhereClause)
span: Span)
-> ty::ParamBounds<'tcx>
where AC: AstConv<'tcx> {
let mut param_bounds = conv_param_bounds(this,
span,
param_ty,
ast_bounds,
where_clause);
ast_bounds);


add_unsized_bound(this,
Expand Down Expand Up @@ -2031,16 +2070,14 @@ fn check_bounds_compatible<'tcx>(tcx: &ty::ctxt<'tcx>,
fn conv_param_bounds<'tcx,AC>(this: &AC,
span: Span,
param_ty: ty::ParamTy,
ast_bounds: &[ast::TyParamBound],
where_clause: &ast::WhereClause)
ast_bounds: &[ast::TyParamBound])
-> ty::ParamBounds<'tcx>
where AC: AstConv<'tcx> {
let all_bounds =
merge_param_bounds(this.tcx(), param_ty, ast_bounds, where_clause);
where AC: AstConv<'tcx>
{
let astconv::PartitionedBounds { builtin_bounds,
trait_bounds,
region_bounds } =
astconv::partition_bounds(this.tcx(), span, all_bounds.as_slice());
astconv::partition_bounds(this.tcx(), span, ast_bounds.as_slice());
let trait_bounds: Vec<Rc<ty::PolyTraitRef>> =
trait_bounds.into_iter()
.map(|bound| {
Expand All @@ -2062,43 +2099,6 @@ fn conv_param_bounds<'tcx,AC>(this: &AC,
}
}

/// Merges the bounds declared on a type parameter with those found from where clauses into a
/// single list.
fn merge_param_bounds<'a>(tcx: &ty::ctxt,
param_ty: ty::ParamTy,
ast_bounds: &'a [ast::TyParamBound],
where_clause: &'a ast::WhereClause)
-> Vec<&'a ast::TyParamBound> {
let mut result = Vec::new();

for ast_bound in ast_bounds.iter() {
result.push(ast_bound);
}

for predicate in where_clause.predicates.iter() {
match predicate {
&ast::WherePredicate::BoundPredicate(ref bound_pred) => {
let predicate_param_id =
tcx.def_map
.borrow()
.get(&bound_pred.id)
.expect("merge_param_bounds(): resolve didn't resolve the \
type parameter identifier in a `where` clause")
.def_id();
if param_ty.def_id != predicate_param_id {
continue
}
for bound in bound_pred.bounds.iter() {
result.push(bound);
}
}
&ast::WherePredicate::EqPredicate(_) => panic!("not implemented")
}
}

result
}

pub fn ty_of_foreign_fn_decl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
decl: &ast::FnDecl,
def_id: ast::DefId,
Expand Down
7 changes: 4 additions & 3 deletions src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -693,7 +693,7 @@ impl Clean<Option<Lifetime>> for ty::Region {

#[deriving(Clone, Encodable, Decodable, PartialEq)]
pub struct WherePredicate {
pub name: String,
pub ty: Type,
pub bounds: Vec<TyParamBound>
}

Expand All @@ -702,11 +702,12 @@ impl Clean<WherePredicate> for ast::WherePredicate {
match *self {
ast::WherePredicate::BoundPredicate(ref wbp) => {
WherePredicate {
name: wbp.ident.clean(cx),
ty: wbp.bounded_ty.clean(cx),
bounds: wbp.bounds.clean(cx)
}
}
ast::WherePredicate::EqPredicate(_) => {
// FIXME(#20048)
_ => {
unimplemented!();
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/html/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ impl<'a> fmt::Show for WhereClause<'a> {
try!(f.write(", ".as_bytes()));
}
let bounds = pred.bounds.as_slice();
try!(write!(f, "{}: {}", pred.name, TyParamBounds(bounds)));
try!(write!(f, "{}: {}", pred.ty, TyParamBounds(bounds)));
}
Ok(())
}
Expand Down
13 changes: 11 additions & 2 deletions src/libsyntax/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -415,17 +415,26 @@ pub struct WhereClause {
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
pub enum WherePredicate {
BoundPredicate(WhereBoundPredicate),
RegionPredicate(WhereRegionPredicate),
EqPredicate(WhereEqPredicate)
}

#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
pub struct WhereBoundPredicate {
pub id: NodeId,
pub span: Span,
pub ident: Ident,
pub bounded_ty: P<Ty>,
pub bounds: OwnedSlice<TyParamBound>,
}

#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
pub struct WhereRegionPredicate {
pub span: Span,
pub lifetime: Lifetime,
pub bound: Lifetime
}

impl Copy for WhereRegionPredicate {}

#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
pub struct WhereEqPredicate {
pub id: NodeId,
Expand Down
10 changes: 8 additions & 2 deletions src/libsyntax/ext/deriving/generic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -426,12 +426,18 @@ impl<'a> TraitDef<'a> {
match *clause {
ast::WherePredicate::BoundPredicate(ref wb) => {
ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
id: ast::DUMMY_NODE_ID,
span: self.span,
ident: wb.ident,
bounded_ty: wb.bounded_ty.clone(),
bounds: OwnedSlice::from_vec(wb.bounds.iter().map(|b| b.clone()).collect())
})
}
ast::WherePredicate::RegionPredicate(ref rb) => {
ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
span: self.span,
lifetime: rb.lifetime,
bound: rb.bound
})
}
ast::WherePredicate::EqPredicate(ref we) => {
ast::WherePredicate::EqPredicate(ast::WhereEqPredicate {
id: ast::DUMMY_NODE_ID,
Expand Down
Loading

0 comments on commit cee12ab

Please sign in to comment.