E0169,
E0170,
E0171,
- E0172
+ E0172,
+ E0173,
+ E0174,
+ E0175,
+ E0176,
+ E0177,
+ E0178,
+ E0179
)
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 {
}
}
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);
+ }
}
}
}
// 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) \
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 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");
+ }
+ }
- for bound in predicate.bounds.iter() {
- self.resolve_type_parameter_bound(predicate.id, bound,
- TraitBoundingTypeParameter);
+ self.resolve_type(&*eq_pred.ty);
+ }
}
}
}
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()
}
}
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);
+ }
+ }
}
}
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);
+ }
+ _ => {}
+ }
}
}
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 }
// 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;
{
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> {
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)
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
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>(
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
{
}
}
- 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;
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<_> =
.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
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
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
}
}
+#[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
// 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,
&trait_def.generics,
self_ty,
types,
- regions);
+ regions,
+ assoc_bindings);
ty::TraitRef::new(trait_def_id, substs)
}
rscope,
trait_def_id,
None,
- path));
+ path,
+ AllowEqConstraints::Allow));
}
_ => {
span_err!(this.tcx().sess, ty.span, E0172, "expected a reference to a trait");
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()));
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) => {
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(
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);
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);
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>>,
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; }
};
/// 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)))
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;
_: 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())
}
}
}
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);
}
}
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) => {
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>)
{
{
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);
}
{
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;
_: 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())
}
}
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))
}
}
}
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.
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;
}
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) => {
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,
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> =
}
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")
}
}
AngleBracketedParameters(AngleBracketedParameterData {
lifetimes: Vec::new(),
types: OwnedSlice::empty(),
+ bindings: OwnedSlice::empty(),
})
}
}
}
}
+
+ 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>`
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()
}
}
}
#[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>> ;
}
}
+// 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 {
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,
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
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()
parameters: ast::AngleBracketedParameters(ast::AngleBracketedParameterData {
lifetimes: lifetimes,
types: OwnedSlice::from_vec(types),
+ bindings: OwnedSlice::from_vec(bindings),
})
});
ast::Path {
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 {
// 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,
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())
}
}
.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)
true,
rand_ident.clone(),
Vec::new(),
+ Vec::new(),
Vec::new());
let rand_name = cx.expr_path(rand_name);
Some(cx.lifetime(sp,
cx.ident_of(
"'static").name)),
- ast::MutImmutable))))
+ ast::MutImmutable)),
+ Vec::new()))
}
Some(s) => {
cx.expr_call_global(sp,
self.fmtsp,
true, Context::rtpath(self.ecx, "Argument"),
vec![static_lifetime],
+ vec![],
vec![]
));
lets.push(Context::item_static_array(self.ecx,
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)
}
})
}
+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),
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,
}
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)
+ })
+ }
}
}
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};
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};
}
}
- /// 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
}
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);
+ }
+
+ /// 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> {
+ 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.
// 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(
parameters: ast::AngleBracketedParameters(ast::AngleBracketedParameterData {
lifetimes: Vec::new(),
types: OwnedSlice::empty(),
+ bindings: OwnedSlice::empty(),
})
});
return segments;
// 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),
}),
});
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) => {
}
}
- 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();
+ if p.look_ahead(1, |t| t == &token::Eq) {
+ None
+ } else {
+ Some(p.parse_ty_sum())
+ }
+ }
+ );
+
+ // 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();
- p.parse_ty_sum()
+ 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, result.into_vec())
+ (lifetimes, types.into_vec(), bindings.into_vec())
}
fn forbid_lifetime(&mut self) {
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");
+ }
- generics.where_clause.predicates.push(ast::WherePredicate {
- id: ast::DUMMY_NODE_ID,
- span: span,
- ident: ident,
- bounds: bounds,
- });
- parsed_something = true;
+ 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");
+ }
if !self.eat(&token::Comma) {
break
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, ">"))
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(())
}
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);
+ }
+ }
}
}
--- /dev/null
+// 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() {}
--- /dev/null
+// 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() {}
--- /dev/null
+// 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`
+}
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());
}
#[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();
}
--- /dev/null
+// 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);
+}