Add support for equality constraints on associated types

This commit is contained in:
Nick Cameron 2014-11-29 17:08:30 +13:00
parent da83ad8e2c
commit 397dda8aa0
29 changed files with 791 additions and 164 deletions

View File

@ -148,5 +148,12 @@ register_diagnostics!(
E0169,
E0170,
E0171,
E0172
E0172,
E0173,
E0174,
E0175,
E0176,
E0177,
E0178,
E0179
)

View File

@ -1405,10 +1405,22 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> {
let new_types = data.types.map(|t| {
self.rebuild_arg_ty_or_output(&**t, lifetime, anon_nums, region_names)
});
let new_bindings = data.bindings.map(|b| {
P(ast::TypeBinding {
id: b.id,
ident: b.ident,
ty: self.rebuild_arg_ty_or_output(&*b.ty,
lifetime,
anon_nums,
region_names),
span: b.span
})
});
ast::AngleBracketedParameters(ast::AngleBracketedParameterData {
lifetimes: new_lts,
types: new_types
})
types: new_types,
bindings: new_bindings,
})
}
};
let new_seg = ast::PathSegment {

View File

@ -1453,8 +1453,15 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> {
}
}
for predicate in generics.where_clause.predicates.iter() {
for bound in predicate.bounds.iter() {
self.check_ty_param_bound(predicate.span, bound)
match predicate {
&ast::BoundPredicate(ref bound_pred) => {
for bound in bound_pred.bounds.iter() {
self.check_ty_param_bound(bound_pred.span, bound)
}
}
&ast::EqPredicate(ref eq_pred) => {
self.visit_ty(&*eq_pred.ty);
}
}
}
}

View File

@ -3407,9 +3407,8 @@ impl<'a> Resolver<'a> {
// This is not a crate-relative path. We resolve the
// first component of the path in the current lexical
// scope and then proceed to resolve below that.
match self.resolve_module_in_lexical_scope(
module_,
module_path[0]) {
match self.resolve_module_in_lexical_scope(module_,
module_path[0]) {
Failed(err) => return Failed(err),
Indeterminate => {
debug!("(resolving module path for import) \
@ -4590,25 +4589,42 @@ impl<'a> Resolver<'a> {
fn resolve_where_clause(&mut self, where_clause: &ast::WhereClause) {
for predicate in where_clause.predicates.iter() {
match self.resolve_identifier(predicate.ident,
TypeNS,
true,
predicate.span) {
Some((def @ DefTyParam(_, _, _), last_private)) => {
self.record_def(predicate.id, (def, last_private));
}
_ => {
self.resolve_error(
predicate.span,
format!("undeclared type parameter `{}`",
token::get_ident(
predicate.ident)).as_slice());
}
}
match predicate {
&ast::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());
}
}
for bound in predicate.bounds.iter() {
self.resolve_type_parameter_bound(predicate.id, bound,
TraitBoundingTypeParameter);
for bound in bound_pred.bounds.iter() {
self.resolve_type_parameter_bound(bound_pred.id, bound,
TraitBoundingTypeParameter);
}
}
&ast::EqPredicate(ref eq_pred) => {
match self.resolve_path(eq_pred.id, &eq_pred.path, TypeNS, true) {
Some((def @ DefTyParam(..), last_private)) => {
self.record_def(eq_pred.id, (def, last_private));
}
_ => {
self.resolve_error(eq_pred.path.span,
"undeclared associated type");
}
}
self.resolve_type(&*eq_pred.ty);
}
}
}
}
@ -5269,15 +5285,19 @@ impl<'a> Resolver<'a> {
path: &Path,
namespace: Namespace,
check_ribs: bool) -> Option<(Def, LastPrivate)> {
// First, resolve the types.
// First, resolve the types and associated type bindings.
for ty in path.segments.iter().flat_map(|s| s.parameters.types().into_iter()) {
self.resolve_type(&**ty);
}
for binding in path.segments.iter().flat_map(|s| s.parameters.bindings().into_iter()) {
self.resolve_type(&*binding.ty);
}
if path.global {
return self.resolve_crate_relative_path(path, namespace);
}
// Try to find a path to an item in a module.
let unqualified_def =
self.resolve_identifier(path.segments
.last().unwrap()

View File

@ -210,8 +210,16 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
}
}
for predicate in generics.where_clause.predicates.iter() {
self.visit_ident(predicate.span, predicate.ident);
visit::walk_ty_param_bounds_helper(self, &predicate.bounds);
match predicate {
&ast::BoundPredicate(ast::WhereBoundPredicate{ident, ref bounds, span, ..}) => {
self.visit_ident(span, ident);
visit::walk_ty_param_bounds_helper(self, bounds);
}
&ast::EqPredicate(ast::WhereEqPredicate{id, ref path, ref ty, ..}) => {
self.visit_path(path, id);
self.visit_ty(&**ty);
}
}
}
}
@ -486,7 +494,12 @@ fn early_bound_lifetime_names(generics: &ast::Generics) -> Vec<ast::Name> {
visit::walk_ty_param_bounds_helper(&mut collector, &ty_param.bounds);
}
for predicate in generics.where_clause.predicates.iter() {
visit::walk_ty_param_bounds_helper(&mut collector, &predicate.bounds);
match predicate {
&ast::BoundPredicate(ast::WhereBoundPredicate{ref bounds, ..}) => {
visit::walk_ty_param_bounds_helper(&mut collector, bounds);
}
_ => {}
}
}
}

View File

@ -123,6 +123,13 @@ pub fn self_ty(&self) -> Option<Ty<'tcx>> {
s
}
pub fn with_assoc_tys(&self, assoc_tys: Vec<Ty<'tcx>>) -> Substs<'tcx> {
assert!(self.types.is_empty_in(AssocSpace));
let mut s = (*self).clone();
s.types.replace(AssocSpace, assoc_tys);
s
}
pub fn erase_regions(self) -> Substs<'tcx> {
let Substs { types, regions: _ } = self;
Substs { types: types, regions: ErasedRegions }

View File

@ -10,7 +10,7 @@
// except according to those terms.
use middle::subst;
use middle::subst::{ParamSpace, Substs, VecPerParamSpace};
use middle::subst::{ParamSpace, Substs, VecPerParamSpace, Subst};
use middle::infer::InferCtxt;
use middle::ty::{mod, Ty};
use std::collections::HashSet;
@ -149,7 +149,18 @@ pub fn fresh_substs_for_impl<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
{
let tcx = infcx.tcx;
let impl_generics = ty::lookup_item_type(tcx, impl_def_id).generics;
infcx.fresh_substs_for_generics(span, &impl_generics)
let input_substs = infcx.fresh_substs_for_generics(span, &impl_generics);
// Add substs for the associated types bound in the impl.
let ref items = tcx.impl_items.borrow()[impl_def_id];
let mut assoc_tys = Vec::new();
for item in items.iter() {
if let &ty::ImplOrTraitItemId::TypeTraitItemId(id) = item {
assoc_tys.push(tcx.tcache.borrow()[id].ty.subst(tcx, &input_substs));
}
}
input_substs.with_assoc_tys(assoc_tys)
}
impl<'tcx, N> fmt::Show for VtableImplData<'tcx, N> {

View File

@ -83,13 +83,18 @@ pub trait AstConv<'tcx> {
trait_id: ast::DefId)
-> bool;
/// Returns the binding of the given associated type for some type.
/// Returns the concrete type bound to the given associated type (indicated
/// by associated_type_id) in the current context. For example,
/// in `trait Foo { type A; }` looking up `A` will give a type variable;
/// in `impl Foo for ... { type A = int; ... }` looking up `A` will give `int`.
fn associated_type_binding(&self,
span: Span,
ty: Option<Ty<'tcx>>,
self_ty: Option<Ty<'tcx>>,
// DefId for the declaration of the trait
// in which the associated type is declared.
trait_id: ast::DefId,
associated_type_id: ast::DefId)
-> Ty<'tcx>;
-> Option<Ty<'tcx>>;
}
pub fn ast_region_to_region(tcx: &ty::ctxt, lifetime: &ast::Lifetime)
@ -207,7 +212,6 @@ fn ast_path_substs_for_ty<'tcx,AC,RS>(
rscope: &RS,
decl_def_id: ast::DefId,
decl_generics: &ty::Generics<'tcx>,
self_ty: Option<Ty<'tcx>>,
path: &ast::Path)
-> Substs<'tcx>
where AC: AstConv<'tcx>, RS: RegionScope
@ -225,19 +229,26 @@ fn ast_path_substs_for_ty<'tcx,AC,RS>(
assert!(decl_generics.regions.all(|d| d.space == TypeSpace));
assert!(decl_generics.types.all(|d| d.space != FnSpace));
let (regions, types) = match path.segments.last().unwrap().parameters {
let (regions, types, assoc_bindings) = match path.segments.last().unwrap().parameters {
ast::AngleBracketedParameters(ref data) => {
convert_angle_bracketed_parameters(this, rscope, data)
}
ast::ParenthesizedParameters(ref data) => {
span_err!(tcx.sess, path.span, E0169,
"parenthesized parameters may only be used with a trait");
(Vec::new(), convert_parenthesized_parameters(this, data))
(Vec::new(), convert_parenthesized_parameters(this, data), Vec::new())
}
};
create_substs_for_ast_path(this, rscope, path.span, decl_def_id,
decl_generics, self_ty, types, regions)
create_substs_for_ast_path(this,
rscope,
path.span,
decl_def_id,
decl_generics,
None,
types,
regions,
assoc_bindings)
}
fn create_substs_for_ast_path<'tcx,AC,RS>(
@ -248,7 +259,8 @@ fn create_substs_for_ast_path<'tcx,AC,RS>(
decl_generics: &ty::Generics<'tcx>,
self_ty: Option<Ty<'tcx>>,
types: Vec<Ty<'tcx>>,
regions: Vec<ty::Region>)
regions: Vec<ty::Region>,
assoc_bindings: Vec<(ast::Ident, Ty<'tcx>)>)
-> Substs<'tcx>
where AC: AstConv<'tcx>, RS: RegionScope
{
@ -355,13 +367,49 @@ fn create_substs_for_ast_path<'tcx,AC,RS>(
}
}
for param in decl_generics.types.get_slice(AssocSpace).iter() {
substs.types.push(
AssocSpace,
this.associated_type_binding(span,
self_ty,
decl_def_id,
param.def_id));
let mut matched_assoc = 0u;
for formal_assoc in decl_generics.types.get_slice(AssocSpace).iter() {
let mut found = false;
for &(ident, ty) in assoc_bindings.iter() {
if formal_assoc.name.ident() == ident {
substs.types.push(AssocSpace, ty);
matched_assoc += 1;
found = true;
break;
}
}
if !found {
match this.associated_type_binding(span,
self_ty,
decl_def_id,
formal_assoc.def_id) {
Some(ty) => {
substs.types.push(AssocSpace, ty);
matched_assoc += 1;
}
None => {
span_err!(this.tcx().sess, span, E0179,
"missing type for associated type `{}`",
token::get_ident(formal_assoc.name.ident()));
}
}
}
}
if decl_generics.types.get_slice(AssocSpace).len() != matched_assoc {
span_err!(tcx.sess, span, E0171,
"wrong number of associated type parameters: expected {}, found {}",
decl_generics.types.get_slice(AssocSpace).len(), matched_assoc);
}
for &(ident, _) in assoc_bindings.iter() {
let mut formal_idents = decl_generics.types.get_slice(AssocSpace)
.iter().map(|t| t.name.ident());
if !formal_idents.any(|i| i == ident) {
span_err!(this.tcx().sess, span, E0177,
"associated type `{}` does not exist",
token::get_ident(ident));
}
}
return substs;
@ -370,7 +418,9 @@ fn create_substs_for_ast_path<'tcx,AC,RS>(
fn convert_angle_bracketed_parameters<'tcx, AC, RS>(this: &AC,
rscope: &RS,
data: &ast::AngleBracketedParameterData)
-> (Vec<ty::Region>, Vec<Ty<'tcx>>)
-> (Vec<ty::Region>,
Vec<Ty<'tcx>>,
Vec<(ast::Ident, Ty<'tcx>)>)
where AC: AstConv<'tcx>, RS: RegionScope
{
let regions: Vec<_> =
@ -383,7 +433,12 @@ fn convert_angle_bracketed_parameters<'tcx, AC, RS>(this: &AC,
.map(|t| ast_ty_to_ty(this, rscope, &**t))
.collect();
(regions, types)
let assoc_bindings: Vec<_> =
data.bindings.iter()
.map(|b| (b.ident, ast_ty_to_ty(this, rscope, &*b.ty)))
.collect();
(regions, types, assoc_bindings)
}
/// Returns the appropriate lifetime to use for any output lifetimes
@ -484,7 +539,8 @@ pub fn instantiate_poly_trait_ref<'tcx,AC,RS>(
pub fn instantiate_trait_ref<'tcx,AC,RS>(this: &AC,
rscope: &RS,
ast_trait_ref: &ast::TraitRef,
self_ty: Option<Ty<'tcx>>)
self_ty: Option<Ty<'tcx>>,
allow_eq: AllowEqConstraints)
-> Rc<ty::TraitRef<'tcx>>
where AC: AstConv<'tcx>,
RS: RegionScope
@ -493,8 +549,12 @@ pub fn instantiate_trait_ref<'tcx,AC,RS>(this: &AC,
ast_trait_ref.path.span,
ast_trait_ref.ref_id) {
def::DefTrait(trait_def_id) => {
let trait_ref = Rc::new(ast_path_to_trait_ref(this, rscope, trait_def_id,
self_ty, &ast_trait_ref.path));
let trait_ref = Rc::new(ast_path_to_trait_ref(this,
rscope,
trait_def_id,
self_ty,
&ast_trait_ref.path,
allow_eq));
this.tcx().trait_refs.borrow_mut().insert(ast_trait_ref.ref_id,
trait_ref.clone());
trait_ref
@ -507,15 +567,23 @@ pub fn instantiate_trait_ref<'tcx,AC,RS>(this: &AC,
}
}
#[deriving(PartialEq,Show)]
pub enum AllowEqConstraints {
Allow,
DontAllow
}
fn ast_path_to_trait_ref<'tcx,AC,RS>(
this: &AC,
rscope: &RS,
trait_def_id: ast::DefId,
self_ty: Option<Ty<'tcx>>,
path: &ast::Path)
path: &ast::Path,
allow_eq: AllowEqConstraints)
-> ty::TraitRef<'tcx>
where AC: AstConv<'tcx>, RS: RegionScope
{
debug!("ast_path_to_trait_ref {}", path);
let trait_def = this.get_trait_def(trait_def_id);
// the trait reference introduces a binding level here, so
@ -525,15 +593,20 @@ fn ast_path_to_trait_ref<'tcx,AC,RS>(
// lifetimes. Oh well, not there yet.
let shifted_rscope = ShiftedRscope::new(rscope);
let (regions, types) = match path.segments.last().unwrap().parameters {
let (regions, types, assoc_bindings) = match path.segments.last().unwrap().parameters {
ast::AngleBracketedParameters(ref data) => {
convert_angle_bracketed_parameters(this, &shifted_rscope, data)
}
ast::ParenthesizedParameters(ref data) => {
(Vec::new(), convert_parenthesized_parameters(this, data))
(Vec::new(), convert_parenthesized_parameters(this, data), Vec::new())
}
};
if allow_eq == AllowEqConstraints::DontAllow && assoc_bindings.len() > 0 {
span_err!(this.tcx().sess, path.span, E0173,
"equality constraints are not allowed in this position");
}
let substs = create_substs_for_ast_path(this,
&shifted_rscope,
path.span,
@ -541,7 +614,8 @@ fn ast_path_to_trait_ref<'tcx,AC,RS>(
&trait_def.generics,
self_ty,
types,
regions);
regions,
assoc_bindings);
ty::TraitRef::new(trait_def_id, substs)
}
@ -693,7 +767,8 @@ fn ast_ty_to_trait_ref<'tcx,AC,RS>(this: &AC,
rscope,
trait_def_id,
None,
path));
path,
AllowEqConstraints::Allow));
}
_ => {
span_err!(this.tcx().sess, ty.span, E0172, "expected a reference to a trait");
@ -772,7 +847,8 @@ fn qpath_to_ty<'tcx,AC,RS>(this: &AC,
let trait_ref = instantiate_trait_ref(this,
rscope,
&*qpath.trait_ref,
Some(self_type));
Some(self_type),
AllowEqConstraints::DontAllow);
debug!("qpath_to_ty: trait_ref={}", trait_ref.repr(this.tcx()));
@ -916,7 +992,8 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
rscope,
trait_def_id,
None,
path);
path,
AllowEqConstraints::Allow);
trait_ref_to_object_type(this, rscope, path.span, result, &[])
}
def::DefTy(did, _) | def::DefStruct(did) => {
@ -1336,7 +1413,11 @@ fn conv_ty_poly_trait_ref<'tcx, AC, RS>(
let main_trait_bound = match partitioned_bounds.trait_bounds.remove(0) {
Some(trait_bound) => {
Some(instantiate_poly_trait_ref(this, rscope, trait_bound, None))
Some(instantiate_trait_ref(this,
rscope,
&trait_bound.trait_ref,
None,
AllowEqConstraints::Allow))
}
None => {
this.tcx().sess.span_err(

View File

@ -318,7 +318,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
substs: rcvr_substs.clone()
});
self.elaborate_bounds(&[trait_ref.clone()], |this, new_trait_ref, m, method_num| {
self.elaborate_bounds(&[trait_ref.clone()], false, |this, new_trait_ref, m, method_num| {
let vtable_index =
get_method_index(tcx, &*new_trait_ref,
trait_ref.clone(), method_num);
@ -365,7 +365,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
let bounds =
self.fcx.inh.param_env.bounds.get(space, index).trait_bounds
.as_slice();
self.elaborate_bounds(bounds, |this, trait_ref, m, method_num| {
self.elaborate_bounds(bounds, true, |this, trait_ref, m, method_num| {
let xform_self_ty =
this.xform_self_ty(&m, &trait_ref.substs);
@ -402,6 +402,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
fn elaborate_bounds(
&mut self,
bounds: &[Rc<ty::TraitRef<'tcx>>],
num_includes_types: bool,
mk_cand: for<'a> |this: &mut ProbeContext<'a, 'tcx>,
tr: Rc<ty::TraitRef<'tcx>>,
m: Rc<ty::Method<'tcx>>,
@ -415,7 +416,10 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
continue;
}
let (pos, method) = match trait_method(tcx, bound_trait_ref.def_id, self.method_name) {
let (pos, method) = match trait_method(tcx,
bound_trait_ref.def_id,
self.method_name,
num_includes_types) {
Some(v) => v,
None => { continue; }
};
@ -988,12 +992,18 @@ fn impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
/// index (or `None`, if no such method).
fn trait_method<'tcx>(tcx: &ty::ctxt<'tcx>,
trait_def_id: ast::DefId,
method_name: ast::Name)
method_name: ast::Name,
num_includes_types: bool)
-> Option<(uint, Rc<ty::Method<'tcx>>)>
{
let trait_items = ty::trait_items(tcx, trait_def_id);
trait_items
.iter()
.filter(|item|
num_includes_types || match *item {
&ty::MethodTraitItem(_) => true,
&ty::TypeTraitItem(_) => false
})
.enumerate()
.find(|&(_, ref item)| item.name() == method_name)
.and_then(|(idx, item)| item.as_opt_method().map(|m| (idx, m)))

View File

@ -112,7 +112,7 @@ use std::collections::hash_map::{Occupied, Vacant};
use std::mem::replace;
use std::rc::Rc;
use syntax::{mod, abi, attr};
use syntax::ast::{mod, ProvidedMethod, RequiredMethod, TypeTraitItem};
use syntax::ast::{mod, ProvidedMethod, RequiredMethod, TypeTraitItem, DefId};
use syntax::ast_util::{mod, local_def, PostExpansionMethod};
use syntax::codemap::{mod, Span};
use syntax::owned_slice::OwnedSlice;
@ -1585,9 +1585,9 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
_: Option<Ty<'tcx>>,
_: ast::DefId,
_: ast::DefId)
-> Ty<'tcx> {
-> Option<Ty<'tcx>> {
self.tcx().sess.span_err(span, "unsupported associated type binding");
ty::mk_err()
Some(ty::mk_err())
}
}
@ -5152,12 +5152,18 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
}
Some(space) => {
let trait_def_id = match def {
def::DefTrait(did) => Some(did),
_ => None
};
push_explicit_parameters_from_segment_to_substs(fcx,
space,
path.span,
type_defs,
region_defs,
segment,
trait_def_id,
path.span,
&mut substs);
}
}
@ -5244,12 +5250,14 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
type_defs: &VecPerParamSpace<ty::TypeParameterDef<'tcx>>,
region_defs: &VecPerParamSpace<ty::RegionParameterDef>,
segment: &ast::PathSegment,
trait_def_id: Option<DefId>,
path_span: Span,
substs: &mut Substs<'tcx>)
{
match segment.parameters {
ast::AngleBracketedParameters(ref data) => {
push_explicit_angle_bracketed_parameters_from_segment_to_substs(
fcx, space, type_defs, region_defs, data, substs);
fcx, space, type_defs, region_defs, data, trait_def_id, path_span, substs);
}
ast::ParenthesizedParameters(ref data) => {
@ -5265,6 +5273,8 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
type_defs: &VecPerParamSpace<ty::TypeParameterDef<'tcx>>,
region_defs: &VecPerParamSpace<ty::RegionParameterDef>,
data: &ast::AngleBracketedParameterData,
trait_def_id: Option<DefId>,
path_span: Span,
substs: &mut Substs<'tcx>)
{
{
@ -5281,10 +5291,56 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
found {} parameter(s)",
type_count, data.types.len());
substs.types.truncate(space, 0);
break;
}
}
}
if let Some(trait_def_id) = trait_def_id {
let ref items = fcx.tcx().trait_item_def_ids.borrow()[trait_def_id];
let mut assoc_tys = Vec::new();
for item in items.iter() {
if let &ty::ImplOrTraitItemId::TypeTraitItemId(id) = item {
if let ty::ImplOrTraitItem::TypeTraitItem(ref ty) =
fcx.tcx().impl_or_trait_items.borrow()[id] {
assoc_tys.push(ty.clone());
}
}
}
if data.bindings.len() > assoc_tys.len() {
span_err!(fcx.tcx().sess, data.bindings[assoc_tys.len()].span, E0174,
"too many type equality constraints provided: \
expected at most {} constraint(s), \
found {} constraint(s)",
assoc_tys.len(), data.types.len());
substs.types.truncate(space, 0);
} else if data.bindings.len() > 0 {
for assoc_ty in assoc_tys.iter() {
let mut matched = false;
for binding in data.bindings.iter() {
if assoc_ty.name.ident() == binding.ident {
let t = fcx.to_ty(&*binding.ty);
substs.types.push(space, t);
matched = true;
break;
}
}
if !matched {
span_err!(fcx.tcx().sess, path_span, E0176,
"missing type equality constraint for associated type: {}",
assoc_ty.name);
substs.types.truncate(space, 0);
break;
}
}
}
} else if data.bindings.len() > 0 {
span_err!(fcx.tcx().sess, path_span, E0175,
"type equality constraints provided on a non-trait type");
substs.types.truncate(space, 0);
}
{
let region_count = region_defs.len(space);
assert_eq!(substs.regions().len(space), 0);

View File

@ -32,7 +32,7 @@ as `ty_param()` instances.
use self::ConvertMethodContext::*;
use self::CreateTypeParametersForAssociatedTypesFlag::*;
use astconv::{AstConv, ty_of_arg};
use astconv::{AstConv, ty_of_arg, AllowEqConstraints};
use astconv::{ast_ty_to_ty, ast_region_to_region};
use astconv;
use metadata::csearch;
@ -197,10 +197,10 @@ impl<'a, 'tcx> AstConv<'tcx> for CrateCtxt<'a, 'tcx> {
_: Option<Ty<'tcx>>,
_: ast::DefId,
_: ast::DefId)
-> Ty<'tcx> {
-> Option<Ty<'tcx>> {
self.tcx().sess.span_err(span, "associated types may not be \
referenced here");
ty::mk_err()
Some(ty::mk_err())
}
}
@ -782,7 +782,7 @@ impl<'a,'tcx> AstConv<'tcx> for ImplCtxt<'a,'tcx> {
ast::MethodImplItem(_) => {}
ast::TypeImplItem(ref typedef) => {
if associated_type.name() == typedef.ident.name {
return self.ccx.to_ty(&ExplicitRscope, &*typedef.typ)
return Some(self.ccx.to_ty(&ExplicitRscope, &*typedef.typ))
}
}
}
@ -943,10 +943,10 @@ impl<'a,'tcx> AstConv<'tcx> for TraitMethodCtxt<'a,'tcx> {
fn associated_type_binding(&self,
span: Span,
ty: Option<Ty<'tcx>>,
self_ty: Option<Ty<'tcx>>,
trait_id: ast::DefId,
associated_type_id: ast::DefId)
-> Ty<'tcx> {
-> Option<Ty<'tcx>> {
debug!("collect::TraitMethodCtxt::associated_type_binding()");
// If this is one of our own associated types, return it.
@ -957,10 +957,10 @@ impl<'a,'tcx> AstConv<'tcx> for TraitMethodCtxt<'a,'tcx> {
ast::RequiredMethod(_) | ast::ProvidedMethod(_) => {}
ast::TypeTraitItem(ref item) => {
if local_def(item.ty_param.id) == associated_type_id {
return ty::mk_param(self.tcx(),
subst::AssocSpace,
index,
associated_type_id)
return Some(ty::mk_param(self.tcx(),
subst::AssocSpace,
index,
associated_type_id))
}
index += 1;
}
@ -1142,8 +1142,11 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::Item) {
parent_visibility);
for trait_ref in opt_trait_ref.iter() {
astconv::instantiate_trait_ref(&icx, &ExplicitRscope, trait_ref,
Some(selfty));
astconv::instantiate_trait_ref(&icx,
&ExplicitRscope,
trait_ref,
Some(selfty),
AllowEqConstraints::DontAllow);
}
},
ast::ItemTrait(_, _, _, ref trait_methods) => {
@ -1838,8 +1841,17 @@ fn ty_generics<'tcx,AC>(this: &AC,
let trait_def = ty::lookup_trait_def(this.tcx(), trait_def_id);
let associated_type_defs = trait_def.generics.types.get_slice(subst::AssocSpace);
// Find any assocaited type bindings in the bound.
let ref segments = ast_trait_ref.trait_ref.path.segments;
let bindings = segments[segments.len() -1].parameters.bindings();
// Iterate over each associated type `Elem`
for associated_type_def in associated_type_defs.iter() {
if bindings.iter().any(|b| associated_type_def.name.ident() == b.ident) {
// Don't add a variable for a bound associated type.
continue;
}
// Create the fresh type parameter `A`
let def = ty::TypeParameterDef {
name: associated_type_def.name,
@ -1998,10 +2010,11 @@ fn conv_param_bounds<'tcx,AC>(this: &AC,
let trait_bounds: Vec<Rc<ty::TraitRef>> =
trait_bounds.into_iter()
.map(|bound| {
astconv::instantiate_poly_trait_ref(this,
&ExplicitRscope,
bound,
Some(param_ty.to_ty(this.tcx())))
astconv::instantiate_trait_ref(this,
&ExplicitRscope,
&bound.trait_ref,
Some(param_ty.to_ty(this.tcx())),
AllowEqConstraints::Allow)
})
.collect();
let region_bounds: Vec<ty::Region> =
@ -2029,18 +2042,23 @@ fn merge_param_bounds<'a>(tcx: &ty::ctxt,
}
for predicate in where_clause.predicates.iter() {
let predicate_param_id =
tcx.def_map
.borrow()
.get(&predicate.id)
.expect("compute_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 predicate.bounds.iter() {
result.push(bound);
match predicate {
&ast::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::EqPredicate(_) => panic!("not implemented")
}
}

View File

@ -255,6 +255,7 @@ impl PathParameters {
AngleBracketedParameters(AngleBracketedParameterData {
lifetimes: Vec::new(),
types: OwnedSlice::empty(),
bindings: OwnedSlice::empty(),
})
}
@ -307,6 +308,17 @@ impl PathParameters {
}
}
}
pub fn bindings(&self) -> Vec<&P<TypeBinding>> {
match *self {
AngleBracketedParameters(ref data) => {
data.bindings.iter().collect()
}
ParenthesizedParameters(_) => {
Vec::new()
}
}
}
}
/// A path like `Foo<'a, T>`
@ -316,11 +328,14 @@ pub struct AngleBracketedParameterData {
pub lifetimes: Vec<Lifetime>,
/// The type parameters for this path segment, if present.
pub types: OwnedSlice<P<Ty>>,
/// Bindings (equality constraints) on associated types, if present.
/// E.g., `Foo<A=Bar>`.
pub bindings: OwnedSlice<P<TypeBinding>>,
}
impl AngleBracketedParameterData {
fn is_empty(&self) -> bool {
self.lifetimes.is_empty() && self.types.is_empty()
self.lifetimes.is_empty() && self.types.is_empty() && self.bindings.is_empty()
}
}
@ -406,13 +421,27 @@ pub struct WhereClause {
}
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
pub struct WherePredicate {
pub enum WherePredicate {
BoundPredicate(WhereBoundPredicate),
EqPredicate(WhereEqPredicate)
}
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
pub struct WhereBoundPredicate {
pub id: NodeId,
pub span: Span,
pub ident: Ident,
pub bounds: OwnedSlice<TyParamBound>,
}
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
pub struct WhereEqPredicate {
pub id: NodeId,
pub span: Span,
pub path: Path,
pub ty: P<Ty>,
}
/// The set of MetaItems that define the compilation environment of the crate,
/// used to drive conditional compilation
pub type CrateConfig = Vec<P<MetaItem>> ;
@ -1118,6 +1147,16 @@ impl FloatTy {
}
}
// Bind a type to an associated type: `A=Foo`.
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
pub struct TypeBinding {
pub id: NodeId,
pub ident: Ident,
pub ty: P<Ty>,
pub span: Span,
}
// NB PartialEq method appears below.
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
pub struct Ty {

View File

@ -174,12 +174,28 @@ pub fn ident_to_path(s: Span, identifier: Ident) -> Path {
parameters: ast::AngleBracketedParameters(ast::AngleBracketedParameterData {
lifetimes: Vec::new(),
types: OwnedSlice::empty(),
bindings: OwnedSlice::empty(),
})
}
),
}
}
// If path is a single segment ident path, return that ident. Otherwise, return
// None.
pub fn path_to_ident(path: &Path) -> Option<Ident> {
if path.segments.len() != 1 {
return None;
}
let segment = &path.segments[0];
if !segment.parameters.is_empty() {
return None;
}
Some(segment.identifier)
}
pub fn ident_to_pat(id: NodeId, s: Span, i: Ident) -> P<Pat> {
P(Pat {
id: id,

View File

@ -37,7 +37,8 @@ pub trait AstBuilder {
global: bool,
idents: Vec<ast::Ident> ,
lifetimes: Vec<ast::Lifetime>,
types: Vec<P<ast::Ty>> )
types: Vec<P<ast::Ty>>,
bindings: Vec<P<ast::TypeBinding>> )
-> ast::Path;
// types
@ -293,20 +294,21 @@ pub trait AstBuilder {
impl<'a> AstBuilder for ExtCtxt<'a> {
fn path(&self, span: Span, strs: Vec<ast::Ident> ) -> ast::Path {
self.path_all(span, false, strs, Vec::new(), Vec::new())
self.path_all(span, false, strs, Vec::new(), Vec::new(), Vec::new())
}
fn path_ident(&self, span: Span, id: ast::Ident) -> ast::Path {
self.path(span, vec!(id))
}
fn path_global(&self, span: Span, strs: Vec<ast::Ident> ) -> ast::Path {
self.path_all(span, true, strs, Vec::new(), Vec::new())
self.path_all(span, true, strs, Vec::new(), Vec::new(), Vec::new())
}
fn path_all(&self,
sp: Span,
global: bool,
mut idents: Vec<ast::Ident> ,
lifetimes: Vec<ast::Lifetime>,
types: Vec<P<ast::Ty>> )
types: Vec<P<ast::Ty>>,
bindings: Vec<P<ast::TypeBinding>> )
-> ast::Path {
let last_identifier = idents.pop().unwrap();
let mut segments: Vec<ast::PathSegment> = idents.into_iter()
@ -321,6 +323,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
parameters: ast::AngleBracketedParameters(ast::AngleBracketedParameterData {
lifetimes: lifetimes,
types: OwnedSlice::from_vec(types),
bindings: OwnedSlice::from_vec(bindings),
})
});
ast::Path {
@ -391,7 +394,8 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
self.ident_of("Option")
),
Vec::new(),
vec!( ty )))
vec!( ty ),
Vec::new()))
}
fn ty_field_imm(&self, span: Span, name: Ident, ty: P<ast::Ty>) -> ast::TypeField {

View File

@ -444,7 +444,7 @@ impl<'a> TraitDef<'a> {
// Create the type of `self`.
let self_type = cx.ty_path(
cx.path_all(self.span, false, vec!( type_ident ), self_lifetimes,
self_ty_params.into_vec()));
self_ty_params.into_vec(), Vec::new()));
let attr = cx.attribute(
self.span,

View File

@ -80,7 +80,7 @@ impl<'a> Path<'a> {
let lt = mk_lifetimes(cx, span, &self.lifetime);
let tys = self.params.iter().map(|t| t.to_ty(cx, span, self_ty, self_generics)).collect();
cx.path_all(span, self.global, idents, lt, tys)
cx.path_all(span, self.global, idents, lt, tys, Vec::new())
}
}
@ -177,7 +177,7 @@ impl<'a> Ty<'a> {
.collect();
cx.path_all(span, false, vec!(self_ty), lifetimes,
self_params.into_vec())
self_params.into_vec(), Vec::new())
}
Literal(ref p) => {
p.to_path(cx, span, self_ty, self_generics)

View File

@ -88,6 +88,7 @@ fn rand_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure)
true,
rand_ident.clone(),
Vec::new(),
Vec::new(),
Vec::new());
let rand_name = cx.expr_path(rand_name);

View File

@ -45,7 +45,8 @@ pub fn expand_option_env<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenT
Some(cx.lifetime(sp,
cx.ident_of(
"'static").name)),
ast::MutImmutable))))
ast::MutImmutable)),
Vec::new()))
}
Some(s) => {
cx.expr_call_global(sp,

View File

@ -530,6 +530,7 @@ impl<'a, 'b> Context<'a, 'b> {
self.fmtsp,
true, Context::rtpath(self.ecx, "Argument"),
vec![static_lifetime],
vec![],
vec![]
));
lets.push(Context::item_static_array(self.ecx,

View File

@ -146,6 +146,10 @@ pub trait Folder {
noop_fold_qpath(t, self)
}
fn fold_ty_binding(&mut self, t: P<TypeBinding>) -> P<TypeBinding> {
noop_fold_ty_binding(t, self)
}
fn fold_mod(&mut self, m: Mod) -> Mod {
noop_fold_mod(m, self)
}
@ -391,6 +395,15 @@ pub fn noop_fold_decl<T: Folder>(d: P<Decl>, fld: &mut T) -> SmallVector<P<Decl>
})
}
pub fn noop_fold_ty_binding<T: Folder>(b: P<TypeBinding>, fld: &mut T) -> P<TypeBinding> {
b.map(|TypeBinding { id, ident, ty, span }| TypeBinding {
id: fld.new_id(id),
ident: ident,
ty: fld.fold_ty(ty),
span: fld.new_span(span),
})
}
pub fn noop_fold_ty<T: Folder>(t: P<Ty>, fld: &mut T) -> P<Ty> {
t.map(|Ty {id, node, span}| Ty {
id: fld.new_id(id),
@ -533,9 +546,10 @@ pub fn noop_fold_angle_bracketed_parameter_data<T: Folder>(data: AngleBracketedP
fld: &mut T)
-> AngleBracketedParameterData
{
let AngleBracketedParameterData { lifetimes, types } = data;
let AngleBracketedParameterData { lifetimes, types, bindings } = data;
AngleBracketedParameterData { lifetimes: fld.fold_lifetimes(lifetimes),
types: types.move_map(|ty| fld.fold_ty(ty)) }
types: types.move_map(|ty| fld.fold_ty(ty)),
bindings: bindings.move_map(|b| fld.fold_ty_binding(b)) }
}
pub fn noop_fold_parenthesized_parameter_data<T: Folder>(data: ParenthesizedParameterData,
@ -807,14 +821,32 @@ pub fn noop_fold_where_clause<T: Folder>(
}
pub fn noop_fold_where_predicate<T: Folder>(
WherePredicate {id, ident, bounds, span}: WherePredicate,
pred: WherePredicate,
fld: &mut T)
-> WherePredicate {
WherePredicate {
id: fld.new_id(id),
ident: fld.fold_ident(ident),
bounds: bounds.move_map(|x| fld.fold_ty_param_bound(x)),
span: fld.new_span(span)
match pred {
ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{id,
ident,
bounds,
span}) => {
ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
id: fld.new_id(id),
ident: fld.fold_ident(ident),
bounds: bounds.move_map(|x| fld.fold_ty_param_bound(x)),
span: fld.new_span(span)
})
}
ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{id,
path,
ty,
span}) => {
ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{
id: fld.new_id(id),
path: fld.fold_path(path),
ty:fld.fold_ty(ty),
span: fld.new_span(span)
})
}
}
}

View File

@ -53,7 +53,7 @@ use ast::{StructVariantKind, BiSub, StrStyle};
use ast::{SelfExplicit, SelfRegion, SelfStatic, SelfValue};
use ast::{Delimited, SequenceRepetition, TokenTree, TraitItem, TraitRef};
use ast::{TtDelimited, TtSequence, TtToken};
use ast::{TupleVariantKind, Ty, Ty_};
use ast::{TupleVariantKind, Ty, Ty_, TypeBinding};
use ast::{TypeField, TyFixedLengthVec, TyClosure, TyProc, TyBareFn};
use ast::{TyTypeof, TyInfer, TypeMethod};
use ast::{TyParam, TyParamBound, TyParen, TyPath, TyPolyTraitRef, TyPtr, TyQPath};
@ -62,7 +62,7 @@ use ast::{TypeImplItem, TypeTraitItem, Typedef, UnboxedClosureKind};
use ast::{UnnamedField, UnsafeBlock};
use ast::{UnsafeFn, ViewItem, ViewItem_, ViewItemExternCrate, ViewItemUse};
use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple};
use ast::{Visibility, WhereClause, WherePredicate};
use ast::{Visibility, WhereClause};
use ast;
use ast_util::{mod, as_prec, ident_to_path, operator_prec};
use codemap::{mod, Span, BytePos, Spanned, spanned, mk_sp};
@ -769,13 +769,10 @@ impl<'a> Parser<'a> {
}
}
/// Parse a sequence bracketed by '<' and '>', stopping
/// before the '>'.
pub fn parse_seq_to_before_gt<T>(
&mut self,
sep: Option<token::Token>,
f: |&mut Parser| -> T)
-> OwnedSlice<T> {
pub fn parse_seq_to_before_gt_or_return<T>(&mut self,
sep: Option<token::Token>,
f: |&mut Parser| -> Option<T>)
-> (OwnedSlice<T>, bool) {
let mut v = Vec::new();
// This loop works by alternating back and forth between parsing types
// and commas. For example, given a string `A, B,>`, the parser would
@ -792,24 +789,48 @@ impl<'a> Parser<'a> {
}
if i % 2 == 0 {
v.push(f(self));
match f(self) {
Some(result) => v.push(result),
None => return (OwnedSlice::from_vec(v), true)
}
} else {
sep.as_ref().map(|t| self.expect(t));
}
}
return OwnedSlice::from_vec(v);
return (OwnedSlice::from_vec(v), false);
}
pub fn parse_seq_to_gt<T>(
&mut self,
sep: Option<token::Token>,
f: |&mut Parser| -> T)
-> OwnedSlice<T> {
/// Parse a sequence bracketed by '<' and '>', stopping
/// before the '>'.
pub fn parse_seq_to_before_gt<T>(&mut self,
sep: Option<token::Token>,
f: |&mut Parser| -> T)
-> OwnedSlice<T> {
let (result, returned) = self.parse_seq_to_before_gt_or_return(sep, |p| Some(f(p)));
assert!(!returned);
return result;
}
pub fn parse_seq_to_gt<T>(&mut self,
sep: Option<token::Token>,
f: |&mut Parser| -> T)
-> OwnedSlice<T> {
let v = self.parse_seq_to_before_gt(sep, f);
self.expect_gt();
return v;
}
pub fn parse_seq_to_gt_or_return<T>(&mut self,
sep: Option<token::Token>,
f: |&mut Parser| -> Option<T>)
-> (OwnedSlice<T>, bool) {
let (v, returned) = self.parse_seq_to_before_gt_or_return(sep, f);
if !returned {
self.expect_gt();
}
return (v, returned);
}
/// Parse a sequence, including the closing delimiter. The function
/// f must consume tokens until reaching the next separator or
/// closing bracket.
@ -1842,11 +1863,12 @@ impl<'a> Parser<'a> {
// Parse types, optionally.
let parameters = if self.eat_lt(false) {
let (lifetimes, types) = self.parse_generic_values_after_lt();
let (lifetimes, types, bindings) = self.parse_generic_values_after_lt();
ast::AngleBracketedParameters(ast::AngleBracketedParameterData {
lifetimes: lifetimes,
types: OwnedSlice::from_vec(types),
bindings: OwnedSlice::from_vec(bindings),
})
} else if self.eat(&token::OpenDelim(token::Paren)) {
let inputs = self.parse_seq_to_end(
@ -1894,6 +1916,7 @@ impl<'a> Parser<'a> {
parameters: ast::AngleBracketedParameters(ast::AngleBracketedParameterData {
lifetimes: Vec::new(),
types: OwnedSlice::empty(),
bindings: OwnedSlice::empty(),
})
});
return segments;
@ -1902,12 +1925,13 @@ impl<'a> Parser<'a> {
// Check for a type segment.
if self.eat_lt(false) {
// Consumed `a::b::<`, go look for types
let (lifetimes, types) = self.parse_generic_values_after_lt();
let (lifetimes, types, bindings) = self.parse_generic_values_after_lt();
segments.push(ast::PathSegment {
identifier: identifier,
parameters: ast::AngleBracketedParameters(ast::AngleBracketedParameterData {
lifetimes: lifetimes,
types: OwnedSlice::from_vec(types),
bindings: OwnedSlice::from_vec(bindings),
}),
});
@ -2435,13 +2459,18 @@ impl<'a> Parser<'a> {
let dot = self.last_span.hi;
hi = self.span.hi;
self.bump();
let (_, tys) = if self.eat(&token::ModSep) {
let (_, tys, bindings) = if self.eat(&token::ModSep) {
self.expect_lt();
self.parse_generic_values_after_lt()
} else {
(Vec::new(), Vec::new())
(Vec::new(), Vec::new(), Vec::new())
};
if bindings.len() > 0 {
let last_span = self.last_span;
self.span_err(last_span, "type bindings are only permitted on trait paths");
}
// expr.f() method call
match self.token {
token::OpenDelim(token::Paren) => {
@ -4041,16 +4070,51 @@ impl<'a> Parser<'a> {
}
}
fn parse_generic_values_after_lt(&mut self) -> (Vec<ast::Lifetime>, Vec<P<Ty>> ) {
fn parse_generic_values_after_lt(&mut self)
-> (Vec<ast::Lifetime>, Vec<P<Ty>>, Vec<P<TypeBinding>>) {
let lifetimes = self.parse_lifetimes(token::Comma);
let result = self.parse_seq_to_gt(
// First parse types.
let (types, returned) = self.parse_seq_to_gt_or_return(
Some(token::Comma),
|p| {
p.forbid_lifetime();
p.parse_ty_sum()
if p.look_ahead(1, |t| t == &token::Eq) {
None
} else {
Some(p.parse_ty_sum())
}
}
);
(lifetimes, result.into_vec())
// If we found the `>`, don't continue.
if !returned {
return (lifetimes, types.into_vec(), Vec::new());
}
// Then parse type bindings.
let bindings = self.parse_seq_to_gt(
Some(token::Comma),
|p| {
p.forbid_lifetime();
let lo = p.span.lo;
let ident = p.parse_ident();
let found_eq = p.eat(&token::Eq);
if !found_eq {
let span = p.span;
p.span_warn(span, "whoops, no =?");
}
let ty = p.parse_ty();
let hi = p.span.hi;
let span = mk_sp(lo, hi);
return P(TypeBinding{id: ast::DUMMY_NODE_ID,
ident: ident,
ty: ty,
span: span,
});
}
);
(lifetimes, types.into_vec(), bindings.into_vec())
}
fn forbid_lifetime(&mut self) {
@ -4070,30 +4134,59 @@ impl<'a> Parser<'a> {
let mut parsed_something = false;
loop {
let lo = self.span.lo;
let ident = match self.token {
token::Ident(..) => self.parse_ident(),
let path = match self.token {
token::Ident(..) => self.parse_path(NoTypesAllowed),
_ => break,
};
self.expect(&token::Colon);
let bounds = self.parse_ty_param_bounds();
let hi = self.span.hi;
let span = mk_sp(lo, hi);
if self.eat(&token::Colon) {
let bounds = self.parse_ty_param_bounds();
let hi = self.span.hi;
let span = mk_sp(lo, hi);
if bounds.len() == 0 {
self.span_err(span,
"each predicate in a `where` clause must have \
at least one bound in it");
if bounds.len() == 0 {
self.span_err(span,
"each predicate in a `where` clause must have \
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,
span: span,
ident: ident,
bounds: bounds,
}));
parsed_something = true;
} else if self.eat(&token::Eq) {
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");
} else {
let last_span = self.last_span;
self.span_err(last_span,
"unexpected token in `where` clause");
}
generics.where_clause.predicates.push(ast::WherePredicate {
id: ast::DUMMY_NODE_ID,
span: span,
ident: ident,
bounds: bounds,
});
parsed_something = true;
if !self.eat(&token::Comma) {
break
}

View File

@ -1976,6 +1976,18 @@ impl<'a> State<'a> {
Inconsistent,
data.types.as_slice(),
|s, ty| s.print_type(&**ty)));
comma = true;
}
for binding in data.bindings.iter() {
if comma {
try!(self.word_space(","))
}
try!(self.print_ident(binding.ident));
try!(space(&mut self.s));
try!(self.word_space("="));
try!(self.print_type(&*binding.ty));
comma = true;
}
try!(word(&mut self.s, ">"))
@ -2437,8 +2449,20 @@ impl<'a> State<'a> {
try!(self.word_space(","));
}
try!(self.print_ident(predicate.ident));
try!(self.print_bounds(":", predicate.bounds.as_slice()));
match predicate {
&ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{ident,
ref bounds,
..}) => {
try!(self.print_ident(ident));
try!(self.print_bounds(":", bounds.as_slice()));
}
&ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{ref path, ref ty, ..}) => {
try!(self.print_path(path, false));
try!(space(&mut self.s));
try!(self.word_space("="));
try!(self.print_type(&**ty));
}
}
}
Ok(())

View File

@ -573,8 +573,22 @@ 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() {
visitor.visit_ident(predicate.span, predicate.ident);
walk_ty_param_bounds_helper(visitor, &predicate.bounds);
match predicate {
&ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{span,
ident,
ref bounds,
..}) => {
visitor.visit_ident(span, ident);
walk_ty_param_bounds_helper(visitor, bounds);
}
&ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{id,
ref path,
ref ty,
..}) => {
visitor.visit_path(path, id);
visitor.visit_ty(&**ty);
}
}
}
}

View File

@ -0,0 +1,27 @@
// 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 equality constraints on associated types. Check that unsupported syntax
// does not ICE.
#![feature(associated_types)]
pub trait Foo {
type A;
fn boo(&self) -> <Self as Foo>::A;
}
fn foo2<I: Foo>(x: I) {
let _: A = x.boo(); //~ERROR use of undeclared
let _: I::A = x.boo(); //~ERROR failed to resolve
//~^ERROR use of undeclared type name `I::A`
}
pub 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.
// Test equality constraints on associated types. Check we get an error when an
// equality constraint is used in a qualified path.
#![feature(associated_types)]
pub trait Foo {
type A;
fn boo(&self) -> <Self as Foo>::A;
}
struct Bar;
impl Foo for int {
type A = uint;
fn boo(&self) -> uint { 42 }
}
fn baz<I: Foo>(x: &<I as Foo<A=Bar>>::A) {} //~ERROR equality constraints are not allowed in this
pub fn main() {}

View File

@ -0,0 +1,48 @@
// 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 equality constraints on associated types. Check we get type errors
// where we should.
#![feature(associated_types)]
pub trait Foo {
type A;
fn boo(&self) -> <Self as Foo>::A;
}
struct Bar;
impl Foo for int {
type A = uint;
fn boo(&self) -> uint {
42
}
}
fn foo1<I: Foo<A=Bar>>(x: I) {
let _: Bar = x.boo();
}
fn foo2<I: Foo>(x: I) {
let _: Bar = x.boo(); //~ERROR mismatched types
}
pub fn baz(x: &Foo<A=Bar>) {
let _: Bar = x.boo();
}
pub fn main() {
let a = 42i;
foo1(a); //~ERROR the trait `Foo` is not implemented for the type `int`
baz(&a); //~ERROR the trait `Foo` is not implemented for the type `int`
}

View File

@ -31,6 +31,6 @@ impl ToString_ for Point {
fn main() {
let p = Point::new(0.0, 0.0);
//~^ ERROR unresolved name `Point::new`
//~^^ ERROR failed to resolve. Use of undeclared module `Point`
//~^^ ERROR failed to resolve. Use of undeclared type or module `Point`
println!("{}", p.to_string());
}

View File

@ -25,7 +25,7 @@ test!(b,
#[qux]
fn main() {
a::bar();
//~^ ERROR failed to resolve. Use of undeclared module `a`
//~^ ERROR failed to resolve. Use of undeclared type or module `a`
//~^^ ERROR unresolved name `a::bar`
b::bar();
}

View File

@ -0,0 +1,55 @@
// 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 equality constraints on associated types.
#![feature(associated_types)]
pub trait Foo {
type A;
fn boo(&self) -> <Self as Foo>::A;
}
struct Bar;
impl Foo for int {
type A = uint;
fn boo(&self) -> uint { 42 }
}
impl Foo for Bar {
type A = int;
fn boo(&self) -> int { 43 }
}
impl Foo for char {
type A = Bar;
fn boo(&self) -> Bar { Bar }
}
fn foo1<I: Foo<A=Bar>>(x: I) -> Bar {
x.boo()
}
fn foo2<I: Foo>(x: I) -> <I as Foo>::A {
x.boo()
}
fn baz(x: &Foo<A=Bar>) -> Bar {
x.boo()
}
pub fn main() {
let a = 42i;
assert!(foo2(a) == 42u);
let a = Bar;
assert!(foo2(a) == 43i);
let a = 'a';
foo1(a);
baz(&a);
}