Add parser support for generalized where clauses

Implement support in the parser for generalized where clauses,
as well as the conversion of ast::WherePredicates to
ty::Predicate in `collect.rs`.
This commit is contained in:
Jared Roesch 2014-12-20 02:29:19 -08:00
parent 8f51ad2420
commit e0cac488ac
25 changed files with 507 additions and 152 deletions

View File

@ -1505,6 +1505,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);
}

View File

@ -206,13 +206,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,
@ -545,9 +551,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!()
}
}

View File

@ -4360,27 +4360,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)) => {

View File

@ -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)
@ -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) {
@ -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) {

View File

@ -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 {
@ -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());
@ -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()),
@ -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>(
@ -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>
@ -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) => {
@ -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,
@ -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| {
@ -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,

View File

@ -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>
}
@ -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!();
}
}

View File

@ -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(())
}

View File

@ -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,

View File

@ -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,

View File

@ -814,17 +814,24 @@ pub fn noop_fold_where_predicate<T: Folder>(
fld: &mut T)
-> WherePredicate {
match pred {
ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{id,
ident,
ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{bounded_ty,
bounds,
span}) => {
ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
id: fld.new_id(id),
ident: fld.fold_ident(ident),
bounded_ty: fld.fold_ty(bounded_ty),
bounds: bounds.move_map(|x| fld.fold_ty_param_bound(x)),
span: fld.new_span(span)
})
}
ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate{lifetime,
bound,
span}) => {
ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
span: fld.new_span(span),
lifetime: fld.fold_lifetime(lifetime),
bound: fld.fold_lifetime(bound)
})
}
ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{id,
path,
ty,

View File

@ -1497,9 +1497,6 @@ impl<'a> Parser<'a> {
}
/// Parse a type.
///
/// The second parameter specifies whether the `+` binary operator is
/// allowed in the type grammar.
pub fn parse_ty(&mut self) -> P<Ty> {
maybe_whole!(no_clone self, NtTy);
@ -4179,6 +4176,10 @@ impl<'a> Parser<'a> {
}
/// Parses an optional `where` clause and places it in `generics`.
///
/// ```
/// where T : Trait<U, V> + 'b, 'a : 'b
/// ```
fn parse_where_clause(&mut self, generics: &mut ast::Generics) {
if !self.eat_keyword(keywords::Where) {
return
@ -4187,10 +4188,37 @@ impl<'a> Parser<'a> {
let mut parsed_something = false;
loop {
let lo = self.span.lo;
let path = match self.token {
token::Ident(..) => self.parse_path(NoTypesAllowed),
_ => break,
};
match self.token {
token::OpenDelim(token::Brace) => {
break
}
token::Lifetime(..) => {
let bounded_lifetime =
self.parse_lifetime();
self.eat(&token::Colon);
// FIXME(#20049)
let bounding_lifetime =
self.parse_lifetime();
let hi = self.span.hi;
let span = mk_sp(lo, hi);
generics.where_clause.predicates.push(ast::WherePredicate::RegionPredicate(
ast::WhereRegionPredicate {
span: span,
lifetime: bounded_lifetime,
bound: bounding_lifetime
}
));
parsed_something = true;
}
_ => {
let bounded_ty = self.parse_ty();
if self.eat(&token::Colon) {
let bounds = self.parse_ty_param_bounds();
@ -4203,42 +4231,37 @@ impl<'a> Parser<'a> {
at least one bound in it");
}
let ident = match ast_util::path_to_ident(&path) {
Some(ident) => ident,
None => {
self.span_err(path.span, "expected a single identifier \
in bound where clause");
break;
}
};
generics.where_clause.predicates.push(
ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
id: ast::DUMMY_NODE_ID,
generics.where_clause.predicates.push(ast::WherePredicate::BoundPredicate(
ast::WhereBoundPredicate {
span: span,
ident: ident,
bounded_ty: bounded_ty,
bounds: bounds,
}));
parsed_something = true;
} else if self.eat(&token::Eq) {
let ty = self.parse_ty();
// let ty = self.parse_ty();
let hi = self.span.hi;
let span = mk_sp(lo, hi);
generics.where_clause.predicates.push(
ast::WherePredicate::EqPredicate(ast::WhereEqPredicate {
id: ast::DUMMY_NODE_ID,
span: span,
path: path,
ty: ty,
}));
parsed_something = true;
// FIXME(#18433)
self.span_err(span, "equality constraints are not yet supported in where clauses");
// generics.where_clause.predicates.push(
// ast::WherePredicate::EqPredicate(ast::WhereEqPredicate {
// id: ast::DUMMY_NODE_ID,
// span: span,
// path: panic!("NYI"), //bounded_ty,
// ty: ty,
// }));
// parsed_something = true;
// // FIXME(#18433)
self.span_err(span,
"equality constraints are not yet supported \
in where clauses (#20041)");
} else {
let last_span = self.last_span;
self.span_err(last_span,
"unexpected token in `where` clause");
}
}
};
if !self.eat(&token::Comma) {
break

View File

@ -2437,12 +2437,19 @@ impl<'a> State<'a> {
}
match predicate {
&ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{ident,
&ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{ref bounded_ty,
ref bounds,
..}) => {
try!(self.print_ident(ident));
try!(self.print_type(&**bounded_ty));
try!(self.print_bounds(":", bounds.as_slice()));
}
&ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate{ref lifetime,
ref bound,
..}) => {
try!(self.print_lifetime(lifetime));
try!(word(&mut self.s, ":"));
try!(self.print_lifetime(bound));
}
&ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{ref path, ref ty, ..}) => {
try!(self.print_path(path, false));
try!(space(&mut self.s));

View File

@ -583,13 +583,18 @@ pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics
walk_lifetime_decls_helper(visitor, &generics.lifetimes);
for predicate in generics.where_clause.predicates.iter() {
match predicate {
&ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{span,
ident,
&ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{ref bounded_ty,
ref bounds,
..}) => {
visitor.visit_ident(span, ident);
visitor.visit_ty(&**bounded_ty);
walk_ty_param_bounds_helper(visitor, bounds);
}
&ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate{ref lifetime,
ref bound,
..}) => {
visitor.visit_lifetime_ref(lifetime);
visitor.visit_lifetime_ref(bound);
}
&ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{id,
ref path,
ref ty,

View File

@ -0,0 +1,39 @@
// 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.
fn a<'a, 'b>(x: &mut &'a int, y: &mut &'b int) where 'b: 'a {
// Note: this is legal because of the `'b:'a` declaration.
*x = *y;
}
fn b<'a, 'b>(x: &mut &'a int, y: &mut &'b int) {
// Illegal now because there is no `'b:'a` declaration.
*x = *y; //~ ERROR mismatched types
}
fn c<'a,'b>(x: &mut &'a int, y: &mut &'b int) {
// Here we try to call `foo` but do not know that `'a` and `'b` are
// related as required.
a(x, y); //~ ERROR cannot infer
}
fn d() {
// 'a and 'b are early bound in the function `a` because they appear
// inconstraints:
let _: fn(&mut &int, &mut &int) = a; //~ ERROR mismatched types
}
fn e() {
// 'a and 'b are late bound in the function `b` because there are
// no constraints:
let _: fn(&mut &int, &mut &int) = b;
}
fn main() { }

View File

@ -0,0 +1,28 @@
// 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.
fn require_copy<T: Copy>(x: T) {}
struct Foo<T> { x: T }
// Ensure constraints are only attached to methods locally
impl<T> Foo<T> {
fn needs_copy(self) where T: Copy {
require_copy(self.x);
}
fn fails_copy(self) {
require_copy(self.x);
//~^ ERROR the trait `core::kinds::Copy` is not implemented for the type `T`
}
}
fn main() {}

View File

@ -0,0 +1,33 @@
// 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.
fn require_copy<T: Copy>(x: T) {}
struct Bar<T> { x: T }
trait Foo<T> {
fn needs_copy(self) where T: Copy;
fn fails_copy(self);
}
// Ensure constraints are only attached to methods locally
impl<T> Foo<T> for Bar<T> {
fn needs_copy(self) where T: Copy {
require_copy(self.x);
}
fn fails_copy(self) {
require_copy(self.x);
//~^ ERROR the trait `core::kinds::Copy` is not implemented for the type `T`
}
}
fn main() {}

View File

@ -0,0 +1,30 @@
// 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.
trait Foo<T> {}
trait Bar<A> {
fn method<B>(&self) where A: Foo<B>;
}
struct S;
struct X;
// Remove this impl causing the below resolution to fail // impl Foo<S> for X {}
impl Bar<X> for int {
fn method<U>(&self) where X: Foo<U> {
}
}
fn main() {
1.method::<X>();
//~^ ERROR the trait `Foo<_>` is not implemented for the type `X`
}

View File

@ -0,0 +1,30 @@
// 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.
// Test that a where clause attached to a method allows us to add
// additional constraints to a parameter out of scope.
struct Foo<T> {
value: T
}
struct Bar; // does not implement Eq
impl<T> Foo<T> {
fn equals(&self, u: &Foo<T>) -> bool where T : Eq {
self.value == u.value
}
}
fn main() {
let x = Foo { value: Bar };
x.equals(&x);
//~^ ERROR the trait `core::cmp::Eq` is not not implemented
}

View File

@ -8,10 +8,17 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
fn equal<T>(_: &T, _: &T) -> bool where int : Eq {
//~^ ERROR undeclared type parameter
struct A;
trait U {}
// impl U for A {}
fn equal<T>(_: &T, _: &T) -> bool where A : U {
true
}
fn main() {
equal(&0i, &0i);
//~^ ERROR the trait `U` is not implemented for the type `A`
}

View File

@ -0,0 +1,15 @@
// Copyright 2013 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.
// pp-exact
fn f<T, 'a, 'b) -> int where T : 'a, 'a: 'b, T: Eq {
0
}

View File

@ -0,0 +1,23 @@
// 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.
trait TheTrait { }
impl TheTrait for &'static int { }
fn foo<'a,T>(_: &'a T) where &'a T : TheTrait { }
fn bar<T>(_: &'static T) where &'static T : TheTrait { }
fn main() {
static x: int = 1;
foo(&x);
bar(&x);
}

View File

@ -0,0 +1,30 @@
// 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.
trait Foo<T> {}
trait Bar<A> {
fn method<B>(&self) where A: Foo<B>;
}
struct S;
struct X;
impl Foo<S> for X {}
impl Bar<X> for int {
fn method<U>(&self) where X: Foo<U> {
}
}
fn main() {
1.method::<S>();
}

View File

@ -0,0 +1,17 @@
// 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.
struct A<'a, 'b> where 'a : 'b { x: &'a int, y: &'b int }
fn main() {
let x = 1i;
let y = 1i;
let a = A { x: &x, y: &y };
}

View File

@ -0,0 +1,29 @@
// 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.
// Test that a where clause attached to a method allows us to add
// additional constraints to a parameter out of scope.
struct Foo<T> {
value: T
}
impl<T> Foo<T> {
fn equals(&self, u: &Foo<T>) -> bool where T : Eq {
self.value == u.value
}
}
fn main() {
let x = Foo { value: 1i };
let y = Foo { value: 2i };
println!("{}", x.equals(&x));
println!("{}", x.equals(&y));
}

View File

@ -0,0 +1,17 @@
// 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.
fn equal<T>(_: &T, _: &T) -> bool where int : Eq {
true
}
fn main() {
equal(&0i, &0i);
}