From 397dda8aa08ee540cffd36f542ebd1140227d0bd Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Sat, 29 Nov 2014 17:08:30 +1300 Subject: [PATCH 1/3] Add support for equality constraints on associated types --- src/librustc/diagnostics.rs | 9 +- src/librustc/middle/infer/error_reporting.rs | 16 +- src/librustc/middle/privacy.rs | 11 +- src/librustc/middle/resolve.rs | 62 +++--- src/librustc/middle/resolve_lifetime.rs | 19 +- src/librustc/middle/subst.rs | 7 + src/librustc/middle/traits/util.rs | 15 +- src/librustc_typeck/astconv.rs | 139 +++++++++++--- src/librustc_typeck/check/method/probe.rs | 18 +- src/librustc_typeck/check/mod.rs | 64 ++++++- src/librustc_typeck/collect.rs | 74 +++++--- src/libsyntax/ast.rs | 43 ++++- src/libsyntax/ast_util.rs | 16 ++ src/libsyntax/ext/build.rs | 14 +- src/libsyntax/ext/deriving/generic/mod.rs | 2 +- src/libsyntax/ext/deriving/generic/ty.rs | 4 +- src/libsyntax/ext/deriving/rand.rs | 1 + src/libsyntax/ext/env.rs | 3 +- src/libsyntax/ext/format.rs | 1 + src/libsyntax/fold.rs | 48 ++++- src/libsyntax/parse/parser.rs | 177 +++++++++++++----- src/libsyntax/print/pprust.rs | 28 ++- src/libsyntax/visit.rs | 18 +- src/test/compile-fail/assoc-eq-1.rs | 27 +++ src/test/compile-fail/assoc-eq-2.rs | 30 +++ src/test/compile-fail/assoc-eq-3.rs | 48 +++++ src/test/compile-fail/issue-3973.rs | 2 +- .../compile-fail/macro-inner-attributes.rs | 2 +- src/test/run-pass/assoc-eq.rs | 55 ++++++ 29 files changed, 790 insertions(+), 163 deletions(-) create mode 100644 src/test/compile-fail/assoc-eq-1.rs create mode 100644 src/test/compile-fail/assoc-eq-2.rs create mode 100644 src/test/compile-fail/assoc-eq-3.rs create mode 100644 src/test/run-pass/assoc-eq.rs diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 81209763a0c5a..641d1e1f2992b 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -148,5 +148,12 @@ register_diagnostics!( E0169, E0170, E0171, - E0172 + E0172, + E0173, + E0174, + E0175, + E0176, + E0177, + E0178, + E0179 ) diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs index 657ee088758d1..d24eddf9ab05b 100644 --- a/src/librustc/middle/infer/error_reporting.rs +++ b/src/librustc/middle/infer/error_reporting.rs @@ -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 { diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index 5770b601a69ce..37b7053530604 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -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); + } } } } diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 36b87bbd42392..e36fefe578def 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -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 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); + } } } } @@ -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() diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 2ba9ba5631d6a..b822e658c0dff 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -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 { 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); + } + _ => {} + } } } diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index bcc762a9640f7..fccb45f872413 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -123,6 +123,13 @@ pub fn self_ty(&self) -> Option> { s } + pub fn with_assoc_tys(&self, assoc_tys: Vec>) -> 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 } diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs index 1b7998a92638c..6671626713529 100644 --- a/src/librustc/middle/traits/util.rs +++ b/src/librustc/middle/traits/util.rs @@ -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> { diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 7f1aad8ca77c5..89e10270f0105 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -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>, + self_ty: Option>, + // 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>; } 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>, 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>, types: Vec>, - regions: Vec) + regions: Vec, + 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, Vec>) + -> (Vec, + Vec>, + 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>) + self_ty: Option>, + allow_eq: AllowEqConstraints) -> Rc> 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>, - 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( diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 6ff276edbce7e..3fa1234ee6e60 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -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>], + num_includes_types: bool, mk_cand: for<'a> |this: &mut ProbeContext<'a, 'tcx>, tr: Rc>, m: Rc>, @@ -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>)> { 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))) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 1a8b06ec12def..6a7f6bd0ea1fb 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -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>, _: ast::DefId, _: ast::DefId) - -> Ty<'tcx> { + -> Option> { 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>, region_defs: &VecPerParamSpace, segment: &ast::PathSegment, + trait_def_id: Option, + 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>, region_defs: &VecPerParamSpace, data: &ast::AngleBracketedParameterData, + trait_def_id: Option, + path_span: Span, substs: &mut Substs<'tcx>) { { @@ -5281,8 +5291,54 @@ 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); } { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 74ac9c480defe..32892aa94ee98 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -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>, _: ast::DefId, _: ast::DefId) - -> Ty<'tcx> { + -> Option> { 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>, + self_ty: Option>, trait_id: ast::DefId, associated_type_id: ast::DefId) - -> Ty<'tcx> { + -> Option> { 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> = 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 = @@ -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") } } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 11af1a43277de..ea8de458ce225 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -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> { + 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, /// The type parameters for this path segment, if present. pub types: OwnedSlice>, + /// Bindings (equality constraints) on associated types, if present. + /// E.g., `Foo`. + pub bindings: OwnedSlice>, } 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, } +#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] +pub struct WhereEqPredicate { + pub id: NodeId, + pub span: Span, + pub path: Path, + pub ty: P, +} + /// The set of MetaItems that define the compilation environment of the crate, /// used to drive conditional compilation pub type CrateConfig = Vec> ; @@ -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, + pub span: Span, +} + + // NB PartialEq method appears below. #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub struct Ty { diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 7dba6a57fc4c9..eec3f69ee64de 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -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 { + 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 { P(Pat { id: id, diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index b4bb1a1a52963..84040bcfa9f05 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -37,7 +37,8 @@ pub trait AstBuilder { global: bool, idents: Vec , lifetimes: Vec, - types: Vec> ) + types: Vec>, + bindings: Vec> ) -> ast::Path; // types @@ -293,20 +294,21 @@ pub trait AstBuilder { impl<'a> AstBuilder for ExtCtxt<'a> { fn path(&self, span: Span, strs: Vec ) -> 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::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 , lifetimes: Vec, - types: Vec> ) + types: Vec>, + bindings: Vec> ) -> ast::Path { let last_identifier = idents.pop().unwrap(); let mut segments: Vec = 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::TypeField { diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs index d5f472bd82710..cf3b3ad9051aa 100644 --- a/src/libsyntax/ext/deriving/generic/mod.rs +++ b/src/libsyntax/ext/deriving/generic/mod.rs @@ -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, diff --git a/src/libsyntax/ext/deriving/generic/ty.rs b/src/libsyntax/ext/deriving/generic/ty.rs index 0139827316193..56d11c2377fa4 100644 --- a/src/libsyntax/ext/deriving/generic/ty.rs +++ b/src/libsyntax/ext/deriving/generic/ty.rs @@ -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) diff --git a/src/libsyntax/ext/deriving/rand.rs b/src/libsyntax/ext/deriving/rand.rs index 8ad8436906b3c..c4e64d58c2932 100644 --- a/src/libsyntax/ext/deriving/rand.rs +++ b/src/libsyntax/ext/deriving/rand.rs @@ -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); diff --git a/src/libsyntax/ext/env.rs b/src/libsyntax/ext/env.rs index e6a44c57f1b65..8c17b31f458d0 100644 --- a/src/libsyntax/ext/env.rs +++ b/src/libsyntax/ext/env.rs @@ -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, diff --git a/src/libsyntax/ext/format.rs b/src/libsyntax/ext/format.rs index c8fed3dcd16f6..5d595474e9c70 100644 --- a/src/libsyntax/ext/format.rs +++ b/src/libsyntax/ext/format.rs @@ -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, diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 122f99cabb3f6..69e311c57f5ab 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -146,6 +146,10 @@ pub trait Folder { noop_fold_qpath(t, self) } + fn fold_ty_binding(&mut self, t: P) -> P { + 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(d: P, fld: &mut T) -> SmallVector }) } +pub fn noop_fold_ty_binding(b: P, fld: &mut T) -> P { + 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: P, fld: &mut T) -> P { t.map(|Ty {id, node, span}| Ty { id: fld.new_id(id), @@ -533,9 +546,10 @@ pub fn noop_fold_angle_bracketed_parameter_data(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(data: ParenthesizedParameterData, @@ -807,14 +821,32 @@ pub fn noop_fold_where_clause( } pub fn noop_fold_where_predicate( - 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) + }) + } } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 4929ee885acf9..92c7380a61ded 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -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( - &mut self, - sep: Option, - f: |&mut Parser| -> T) - -> OwnedSlice { + pub fn parse_seq_to_before_gt_or_return(&mut self, + sep: Option, + f: |&mut Parser| -> Option) + -> (OwnedSlice, 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); + } + + /// Parse a sequence bracketed by '<' and '>', stopping + /// before the '>'. + pub fn parse_seq_to_before_gt(&mut self, + sep: Option, + f: |&mut Parser| -> T) + -> OwnedSlice { + 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( - &mut self, - sep: Option, - f: |&mut Parser| -> T) - -> OwnedSlice { + pub fn parse_seq_to_gt(&mut self, + sep: Option, + f: |&mut Parser| -> T) + -> OwnedSlice { let v = self.parse_seq_to_before_gt(sep, f); self.expect_gt(); return v; } + pub fn parse_seq_to_gt_or_return(&mut self, + sep: Option, + f: |&mut Parser| -> Option) + -> (OwnedSlice, 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, Vec> ) { + fn parse_generic_values_after_lt(&mut self) + -> (Vec, Vec>, Vec>) { 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) { @@ -4070,29 +4134,58 @@ 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"); + } - 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 diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index eab03f7309174..26373d00aaf60 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -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(()) diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index f5e89dd61ff7e..a36f8b23ca322 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -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); + } + } } } diff --git a/src/test/compile-fail/assoc-eq-1.rs b/src/test/compile-fail/assoc-eq-1.rs new file mode 100644 index 0000000000000..4fd5315061874 --- /dev/null +++ b/src/test/compile-fail/assoc-eq-1.rs @@ -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 or the MIT license +// , 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) -> ::A; +} + +fn foo2(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() {} diff --git a/src/test/compile-fail/assoc-eq-2.rs b/src/test/compile-fail/assoc-eq-2.rs new file mode 100644 index 0000000000000..652bf4fb57753 --- /dev/null +++ b/src/test/compile-fail/assoc-eq-2.rs @@ -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 or the MIT license +// , 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) -> ::A; +} + +struct Bar; + +impl Foo for int { + type A = uint; + fn boo(&self) -> uint { 42 } +} + +fn baz(x: &>::A) {} //~ERROR equality constraints are not allowed in this + +pub fn main() {} diff --git a/src/test/compile-fail/assoc-eq-3.rs b/src/test/compile-fail/assoc-eq-3.rs new file mode 100644 index 0000000000000..880b2e9cc4a77 --- /dev/null +++ b/src/test/compile-fail/assoc-eq-3.rs @@ -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 or the MIT license +// , 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) -> ::A; +} + +struct Bar; + +impl Foo for int { + type A = uint; + fn boo(&self) -> uint { + 42 + } +} + +fn foo1>(x: I) { + let _: Bar = x.boo(); +} + +fn foo2(x: I) { + let _: Bar = x.boo(); //~ERROR mismatched types +} + + +pub fn baz(x: &Foo) { + 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` +} diff --git a/src/test/compile-fail/issue-3973.rs b/src/test/compile-fail/issue-3973.rs index 57bc11379125f..e4f7521c33303 100644 --- a/src/test/compile-fail/issue-3973.rs +++ b/src/test/compile-fail/issue-3973.rs @@ -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()); } diff --git a/src/test/compile-fail/macro-inner-attributes.rs b/src/test/compile-fail/macro-inner-attributes.rs index 3e731a2d2fed4..4c4fb5572d614 100644 --- a/src/test/compile-fail/macro-inner-attributes.rs +++ b/src/test/compile-fail/macro-inner-attributes.rs @@ -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(); } diff --git a/src/test/run-pass/assoc-eq.rs b/src/test/run-pass/assoc-eq.rs new file mode 100644 index 0000000000000..f1ba382b42dad --- /dev/null +++ b/src/test/run-pass/assoc-eq.rs @@ -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 or the MIT license +// , 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) -> ::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>(x: I) -> Bar { + x.boo() +} +fn foo2(x: I) -> ::A { + x.boo() +} +fn baz(x: &Foo) -> 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); +} From ae8ba88424652a0d263f193cd9c31e024a000546 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Sat, 29 Nov 2014 17:09:12 +1300 Subject: [PATCH 2/3] Mostly non-behaviour-changing changes (style, etc.) --- src/librustc/metadata/decoder.rs | 2 +- src/librustc/middle/resolve.rs | 74 ++++++++++++----------- src/librustc/middle/subst.rs | 2 +- src/librustc/middle/traits/util.rs | 2 +- src/librustc/middle/ty.rs | 2 +- src/librustc_typeck/astconv.rs | 19 +----- src/librustc_typeck/check/method/probe.rs | 4 +- src/librustc_typeck/check/mod.rs | 1 + src/librustc_typeck/collect.rs | 67 ++++++++++---------- 9 files changed, 82 insertions(+), 91 deletions(-) diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 0d51e044de9cc..4acda5bf659f3 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -435,7 +435,7 @@ pub fn get_symbol(data: &[u8], id: ast::NodeId) -> String { } // Something that a name can resolve to. -#[deriving(Clone)] +#[deriving(Clone,Show)] pub enum DefLike { DlDef(def::Def), DlImpl(ast::DefId), diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index e36fefe578def..59bda245f9233 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -108,7 +108,7 @@ pub type ExportMap2 = NodeMap>; pub struct Export2 { pub name: String, // The name of the target. - pub def_id: DefId, // The definition of the target. + pub def_id: DefId, // The definition of the target. } // This set contains all exported definitions from external crates. The set does @@ -314,7 +314,7 @@ impl<'a> Copy for TypeParameters<'a> {} // The rib kind controls the translation of local // definitions (`DefLocal`) to upvars (`DefUpvar`). - +#[deriving(Show)] enum RibKind { // No translation needs to be applied. NormalRibKind, @@ -340,6 +340,7 @@ enum RibKind { impl Copy for RibKind {} // Methods can be required or provided. RequiredMethod methods only occur in traits. +#[deriving(Show)] enum MethodSort { RequiredMethod, ProvidedMethod(NodeId) @@ -414,6 +415,7 @@ enum DuplicateCheckingMode { impl Copy for DuplicateCheckingMode {} /// One local scope. +#[deriving(Show)] struct Rib { bindings: HashMap, kind: RibKind, @@ -728,8 +730,11 @@ impl NameBindings { let type_def = self.type_def.borrow().clone(); match type_def { None => { - let module = Module::new(parent_link, def_id, kind, - external, is_public); + let module = Module::new(parent_link, + def_id, + kind, + external, + is_public); *self.type_def.borrow_mut() = Some(TypeNsDef { modifiers: modifiers, module_def: Some(Rc::new(module)), @@ -774,9 +779,9 @@ impl NameBindings { } Some(type_def) => { *self.type_def.borrow_mut() = Some(TypeNsDef { + module_def: type_def.module_def, type_def: Some(def), type_span: Some(sp), - module_def: type_def.module_def, modifiers: modifiers, }); } @@ -1286,7 +1291,7 @@ impl<'a> Resolver<'a> { } fn get_parent_link(&mut self, parent: ReducedGraphParent, name: Name) - -> ParentLink { + -> ParentLink { match parent { ModuleReducedGraphParent(module_) => { return ModuleParentLink(module_.downgrade(), name); @@ -1578,14 +1583,14 @@ impl<'a> Resolver<'a> { ItemImpl(_, Some(_), _, _) => parent, - ItemTrait(_, _, _, ref methods) => { + ItemTrait(_, _, _, ref items) => { let name_bindings = self.add_child(name, parent.clone(), ForbidDuplicateTypesAndModules, sp); - // Add all the methods within to a new module. + // Add all the items within to a new module. let parent_link = self.get_parent_link(parent.clone(), name); name_bindings.define_module(parent_link, Some(local_def(item.id)), @@ -1598,13 +1603,12 @@ impl<'a> Resolver<'a> { let def_id = local_def(item.id); - // Add the names of all the methods to the trait info. - for method in methods.iter() { - let (name, kind) = match *method { + // Add the names of all the items to the trait info. + for trait_item in items.iter() { + let (name, kind) = match *trait_item { ast::RequiredMethod(_) | ast::ProvidedMethod(_) => { - let ty_m = - ast_util::trait_item_to_ty_method(method); + let ty_m = ast_util::trait_item_to_ty_method(trait_item); let name = ty_m.ident.name; @@ -3353,7 +3357,7 @@ impl<'a> Resolver<'a> { use_lexical_scope: UseLexicalScopeFlag, span: Span, name_search_type: NameSearchType) - -> ResolveResult<(Rc, LastPrivate)> { + -> ResolveResult<(Rc, LastPrivate)> { let module_path_len = module_path.len(); assert!(module_path_len > 0); @@ -3382,7 +3386,9 @@ impl<'a> Resolver<'a> { mpath.slice_to(idx - 1)); return Failed(Some((span, msg))); }, - None => return Failed(None), + None => { + return Failed(None) + } } } Failed(err) => return Failed(err), @@ -3575,8 +3581,7 @@ impl<'a> Resolver<'a> { -> ResolveResult> { // If this module is an anonymous module, resolve the item in the // lexical scope. Otherwise, resolve the item from the crate root. - let resolve_result = self.resolve_item_in_lexical_scope( - module_, name, TypeNS); + let resolve_result = self.resolve_item_in_lexical_scope(module_, name, TypeNS); match resolve_result { Success((target, _)) => { let bindings = &*target.bindings; @@ -5327,15 +5332,15 @@ impl<'a> Resolver<'a> { // resolve a single identifier (used as a varref) fn resolve_identifier(&mut self, - identifier: Ident, - namespace: Namespace, - check_ribs: bool, - span: Span) - -> Option<(Def, LastPrivate)> { + identifier: Ident, + namespace: Namespace, + check_ribs: bool, + span: Span) + -> Option<(Def, LastPrivate)> { if check_ribs { match self.resolve_identifier_in_local_ribs(identifier, - namespace, - span) { + namespace, + span) { Some(def) => { return Some((def, LastMod(AllPublic))); } @@ -5353,7 +5358,7 @@ impl<'a> Resolver<'a> { containing_module: Rc, name: Name, namespace: Namespace) - -> NameDefinition { + -> NameDefinition { // First, search children. self.populate_module_if_necessary(&containing_module); @@ -5423,9 +5428,9 @@ impl<'a> Resolver<'a> { // resolve a "module-relative" path, e.g. a::b::c fn resolve_module_relative_path(&mut self, - path: &Path, - namespace: Namespace) - -> Option<(Def, LastPrivate)> { + path: &Path, + namespace: Namespace) + -> Option<(Def, LastPrivate)> { let module_path = path.segments.init().iter() .map(|ps| ps.identifier.name) .collect::>(); @@ -5442,9 +5447,8 @@ impl<'a> Resolver<'a> { let (span, msg) = match err { Some((span, msg)) => (span, msg), None => { - let msg = format!("Use of undeclared module `{}`", - self.names_to_string( - module_path.as_slice())); + let msg = format!("Use of undeclared type or module `{}`", + self.names_to_string(module_path.as_slice())); (path.span, msg) } }; @@ -5538,10 +5542,10 @@ impl<'a> Resolver<'a> { } fn resolve_identifier_in_local_ribs(&mut self, - ident: Ident, - namespace: Namespace, - span: Span) - -> Option { + ident: Ident, + namespace: Namespace, + span: Span) + -> Option { // Check the local set of ribs. let search_result = match namespace { ValueNS => { diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index fccb45f872413..d3b1c2d2afc4d 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -112,7 +112,7 @@ impl<'tcx> Substs<'tcx> { } } -pub fn self_ty(&self) -> Option> { + pub fn self_ty(&self) -> Option> { self.types.get_self().map(|&t| t) } diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs index 6671626713529..159b6961782c0 100644 --- a/src/librustc/middle/traits/util.rs +++ b/src/librustc/middle/traits/util.rs @@ -139,7 +139,7 @@ impl<'cx, 'tcx> Iterator>> for Supertraits<'cx, 'tcx> { } // determine the `self` type, using fresh variables for all variables -// declared on the impl declaration e.g., `impl for ~[(A,B)]` +// declared on the impl declaration e.g., `impl for Box<[(A,B)]>` // would return ($0, $1) where $0 and $1 are freshly instantiated type // variables. pub fn fresh_substs_for_impl<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 4c4b5d07f50ac..3f555ec5c4cbe 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1613,7 +1613,7 @@ pub struct RegionParameterDef { pub bounds: Vec, } -/// Information about the type/lifetime parameters associated with an +/// Information about the formal type/lifetime parameters associated with an /// item or method. Analogous to ast::Generics. #[deriving(Clone, Show)] pub struct Generics<'tcx> { diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 89e10270f0105..b65dbff2f6106 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -522,16 +522,6 @@ fn convert_parenthesized_parameters<'tcx,AC>(this: &AC, vec![input_ty, output] } -pub fn instantiate_poly_trait_ref<'tcx,AC,RS>( - this: &AC, - rscope: &RS, - ast_trait_ref: &ast::PolyTraitRef, - self_ty: Option>) - -> Rc> - where AC: AstConv<'tcx>, RS: RegionScope -{ - instantiate_trait_ref(this, rscope, &ast_trait_ref.trait_ref, self_ty) -} /// Instantiates the path for the given trait reference, assuming that it's bound to a valid trait /// type. Returns the def_id for the defining trait. Fails if the type is a type other than a trait @@ -637,7 +627,6 @@ pub fn ast_path_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( rscope, did, &generics, - None, path); let ty = decl_ty.subst(tcx, &substs); TypeAndSubsts { substs: substs, ty: ty } @@ -678,7 +667,7 @@ pub fn ast_path_to_ty_relaxed<'tcx,AC,RS>( Substs::new(VecPerParamSpace::params_from_type(type_params), VecPerParamSpace::params_from_type(region_params)) } else { - ast_path_substs_for_ty(this, rscope, did, &generics, None, path) + ast_path_substs_for_ty(this, rscope, did, &generics, path) }; let ty = decl_ty.subst(tcx, &substs); @@ -777,7 +766,7 @@ fn ast_ty_to_trait_ref<'tcx,AC,RS>(this: &AC, } } _ => { - span_err!(this.tcx().sess, ty.span, E0171, + span_err!(this.tcx().sess, ty.span, E0178, "expected a path on the left-hand side of `+`, not `{}`", pprust::ty_to_string(ty)); match ty.node { @@ -788,8 +777,7 @@ fn ast_ty_to_trait_ref<'tcx,AC,RS>(this: &AC, pprust::ty_to_string(&*mut_ty.ty), pprust::bounds_to_string(bounds)); } - - ast::TyRptr(Some(ref lt), ref mut_ty) => { + ast::TyRptr(Some(ref lt), ref mut_ty) => { span_note!(this.tcx().sess, ty.span, "perhaps you meant `&{} {}({} +{})`? (per RFC 248)", pprust::lifetime_to_string(lt), @@ -806,7 +794,6 @@ fn ast_ty_to_trait_ref<'tcx,AC,RS>(this: &AC, Err(ErrorReported) } } - } fn trait_ref_to_object_type<'tcx,AC,RS>(this: &AC, diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 3fa1234ee6e60..cc60b2962677a 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -1020,7 +1020,7 @@ fn get_method_index<'tcx>(tcx: &ty::ctxt<'tcx>, // iterating down the supertraits of the object's trait until // we find the trait the method came from, counting up the // methods from them. - let mut method_count = 0; + let mut method_count = n_method; ty::each_bound_trait_and_supertraits(tcx, &[subtrait], |bound_ref| { if bound_ref.def_id == trait_ref.def_id { false @@ -1035,7 +1035,7 @@ fn get_method_index<'tcx>(tcx: &ty::ctxt<'tcx>, true } }); - method_count + n_method + method_count } impl<'tcx> Candidate<'tcx> { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 6a7f6bd0ea1fb..80ea8d9026856 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -5355,6 +5355,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, region_count, data.lifetimes.len()); substs.mut_regions().truncate(space, 0); + break; } } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 32892aa94ee98..0830bd476a2e5 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -663,48 +663,43 @@ fn is_associated_type_valid_for_param(ty: Ty, fn find_associated_type_in_generics<'tcx>(tcx: &ty::ctxt<'tcx>, span: Span, - ty: Option>, + self_ty: Option>, associated_type_id: ast::DefId, generics: &ty::Generics<'tcx>) - -> Ty<'tcx> + -> Option> { debug!("find_associated_type_in_generics(ty={}, associated_type_id={}, generics={}", - ty.repr(tcx), associated_type_id.repr(tcx), generics.repr(tcx)); + self_ty.repr(tcx), associated_type_id.repr(tcx), generics.repr(tcx)); - let ty = match ty { + let self_ty = match self_ty { None => { - tcx.sess.span_bug(span, - "find_associated_type_in_generics(): no self \ - type") + return None; } Some(ty) => ty, }; - match ty.sty { + match self_ty.sty { ty::ty_param(ref param_ty) => { - /*let type_parameter = generics.types.get(param_ty.space, - param_ty.idx); - let param_id = type_parameter.def_id;*/ let param_id = param_ty.def_id; for type_parameter in generics.types.iter() { if type_parameter.def_id == associated_type_id && type_parameter.associated_with == Some(param_id) { - return ty::mk_param_from_def(tcx, type_parameter); + return Some(ty::mk_param_from_def(tcx, type_parameter)); } } tcx.sess.span_err( span, format!("no suitable bound on `{}`", - ty.user_string(tcx))[]); - ty::mk_err() + self_ty.user_string(tcx))[]); + Some(ty::mk_err()) } _ => { tcx.sess.span_err( span, "it is currently unsupported to access associated types except \ through a type parameter; this restriction will be lifted in time"); - ty::mk_err() + Some(ty::mk_err()) } } } @@ -762,16 +757,16 @@ impl<'a,'tcx> AstConv<'tcx> for ImplCtxt<'a,'tcx> { fn associated_type_binding(&self, span: Span, - ty: Option>, + self_ty: Option>, trait_id: ast::DefId, associated_type_id: ast::DefId) - -> Ty<'tcx> + -> Option> { - let trait_def = ty::lookup_trait_def(self.tcx(), trait_id); match self.opt_trait_ref_id { + // It's an associated type on the trait that we're + // implementing. Some(trait_ref_id) if trait_ref_id == trait_id => { - // It's an associated type on the trait that we're - // implementing. + let trait_def = ty::lookup_trait_def(self.tcx(), trait_id); assert!(trait_def.generics.types .get_slice(subst::AssocSpace) .iter() @@ -801,7 +796,7 @@ impl<'a,'tcx> AstConv<'tcx> for ImplCtxt<'a,'tcx> { // our bounds. find_associated_type_in_generics(self.ccx.tcx, span, - ty, + self_ty, associated_type_id, self.impl_generics) } @@ -840,17 +835,17 @@ impl<'a,'tcx> AstConv<'tcx> for FnCtxt<'a,'tcx> { fn associated_type_binding(&self, span: Span, - ty: Option>, + self_ty: Option>, _: ast::DefId, associated_type_id: ast::DefId) - -> Ty<'tcx> { + -> Option> { debug!("collect::FnCtxt::associated_type_binding()"); // The ID should map to an associated type on one of the traits in // our bounds. find_associated_type_in_generics(self.ccx.tcx, span, - ty, + self_ty, associated_type_id, self.generics) } @@ -887,17 +882,17 @@ impl<'a,'tcx> AstConv<'tcx> for ImplMethodCtxt<'a,'tcx> { fn associated_type_binding(&self, span: Span, - ty: Option>, + self_ty: Option>, _: ast::DefId, associated_type_id: ast::DefId) - -> Ty<'tcx> { + -> Option> { debug!("collect::ImplMethodCtxt::associated_type_binding()"); // The ID should map to an associated type on one of the traits in // our bounds. find_associated_type_in_generics(self.ccx.tcx, span, - ty, + self_ty, associated_type_id, self.method_generics) } @@ -979,7 +974,7 @@ impl<'a,'tcx> AstConv<'tcx> for TraitMethodCtxt<'a,'tcx> { // our bounds. find_associated_type_in_generics(self.ccx.tcx, span, - ty, + self_ty, associated_type_id, self.method_generics) } @@ -1020,17 +1015,17 @@ impl<'a,'tcx,AC:AstConv<'tcx>> AstConv<'tcx> for GenericsCtxt<'a,'tcx,AC> { fn associated_type_binding(&self, span: Span, - ty: Option>, + self_ty: Option>, _: ast::DefId, associated_type_id: ast::DefId) - -> Ty<'tcx> { + -> Option> { debug!("collect::GenericsCtxt::associated_type_binding()"); // The ID should map to an associated type on one of the traits in // our bounds. find_associated_type_in_generics(self.chain.tcx(), span, - ty, + self_ty, associated_type_id, self.associated_types_generics) } @@ -1364,8 +1359,12 @@ pub fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let self_param_ty = ty::ParamTy::for_self(def_id); - let bounds = compute_bounds(ccx, token::SELF_KEYWORD_NAME, self_param_ty, - bounds.as_slice(), unbound, it.span, + let bounds = compute_bounds(ccx, + token::SELF_KEYWORD_NAME, + self_param_ty, + bounds.as_slice(), + unbound, + it.span, &generics.where_clause); let substs = mk_item_substs(ccx, &ty_generics); @@ -1791,7 +1790,7 @@ fn ty_generics<'tcx,AC>(this: &AC, return result; - fn create_type_parameters_for_associated_types<'tcx,AC>( + fn create_type_parameters_for_associated_types<'tcx, AC>( this: &AC, space: subst::ParamSpace, types: &[ast::TyParam], From ce4318ad86f2ccd0710247020269ba0ba22c6d59 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 2 Dec 2014 15:03:02 -0800 Subject: [PATCH 3/3] Reviewer comments --- src/librustc/diagnostics.rs | 5 +- src/librustc/middle/privacy.rs | 4 +- src/librustc/middle/resolve.rs | 4 +- src/librustc/middle/resolve_lifetime.rs | 14 +++-- src/librustc_typeck/astconv.rs | 12 +--- src/librustc_typeck/check/mod.rs | 60 ++----------------- src/librustc_typeck/coherence/mod.rs | 2 +- src/librustc_typeck/collect.rs | 6 +- src/librustc_typeck/diagnostics.rs | 8 ++- src/librustdoc/clean/mod.rs | 13 +++- .../phase-syntax-doesnt-resolve.rs | 2 +- src/test/compile-fail/assoc-eq-expr-path.rs | 28 +++++++++ .../hrtb-precedence-of-plus-error-message.rs | 6 +- 13 files changed, 76 insertions(+), 88 deletions(-) create mode 100644 src/test/compile-fail/assoc-eq-expr-path.rs diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 641d1e1f2992b..0cdf6a68e44be 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -151,9 +151,6 @@ register_diagnostics!( E0172, E0173, E0174, - E0175, - E0176, E0177, - E0178, - E0179 + E0178 ) diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index 37b7053530604..79bb19a1e535f 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -1454,12 +1454,12 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> { } for predicate in generics.where_clause.predicates.iter() { match predicate { - &ast::BoundPredicate(ref bound_pred) => { + &ast::WherePredicate::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) => { + &ast::WherePredicate::EqPredicate(ref eq_pred) => { self.visit_ty(&*eq_pred.ty); } } diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 59bda245f9233..2899f60f736af 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -4595,7 +4595,7 @@ impl<'a> Resolver<'a> { fn resolve_where_clause(&mut self, where_clause: &ast::WhereClause) { for predicate in where_clause.predicates.iter() { match predicate { - &ast::BoundPredicate(ref bound_pred) => { + &ast::WherePredicate::BoundPredicate(ref bound_pred) => { match self.resolve_identifier(bound_pred.ident, TypeNS, true, @@ -4617,7 +4617,7 @@ impl<'a> Resolver<'a> { TraitBoundingTypeParameter); } } - &ast::EqPredicate(ref eq_pred) => { + &ast::WherePredicate::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)); diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index b822e658c0dff..3ab94d3ca6619 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -211,11 +211,17 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> { } for predicate in generics.where_clause.predicates.iter() { match predicate { - &ast::BoundPredicate(ast::WhereBoundPredicate{ident, ref bounds, span, ..}) => { + &ast::WherePredicate::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, ..}) => { + &ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{ id, + ref path, + ref ty, + .. }) => { self.visit_path(path, id); self.visit_ty(&**ty); } @@ -495,10 +501,10 @@ fn early_bound_lifetime_names(generics: &ast::Generics) -> Vec { } for predicate in generics.where_clause.predicates.iter() { match predicate { - &ast::BoundPredicate(ast::WhereBoundPredicate{ref bounds, ..}) => { + &ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{ref bounds, ..}) => { visit::walk_ty_param_bounds_helper(&mut collector, bounds); } - _ => {} + &ast::WherePredicate::EqPredicate(_) => unimplemented!() } } } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index b65dbff2f6106..c84446a2e4566 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -367,13 +367,11 @@ fn create_substs_for_ast_path<'tcx,AC,RS>( } } - 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; } @@ -385,10 +383,10 @@ fn create_substs_for_ast_path<'tcx,AC,RS>( formal_assoc.def_id) { Some(ty) => { substs.types.push(AssocSpace, ty); - matched_assoc += 1; } None => { - span_err!(this.tcx().sess, span, E0179, + substs.types.push(AssocSpace, ty::mk_err()); + span_err!(this.tcx().sess, span, E0171, "missing type for associated type `{}`", token::get_ident(formal_assoc.name.ident())); } @@ -396,12 +394,6 @@ fn create_substs_for_ast_path<'tcx,AC,RS>( } } - 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()); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 80ea8d9026856..7e29e7078d488 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -5152,18 +5152,12 @@ 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); } } @@ -5250,14 +5244,12 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, type_defs: &VecPerParamSpace>, region_defs: &VecPerParamSpace, segment: &ast::PathSegment, - trait_def_id: Option, - 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, trait_def_id, path_span, substs); + fcx, space, type_defs, region_defs, data, substs); } ast::ParenthesizedParameters(ref data) => { @@ -5273,8 +5265,6 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, type_defs: &VecPerParamSpace>, region_defs: &VecPerParamSpace, data: &ast::AngleBracketedParameterData, - trait_def_id: Option, - path_span: Span, substs: &mut Substs<'tcx>) { { @@ -5296,49 +5286,11 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } } - 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); + if data.bindings.len() > 0 { + span_err!(fcx.tcx().sess, data.bindings[0].span, E0182, + "unexpected binding of associated item in expression path \ + (only allowed in type paths)"); + substs.types.truncate(subst::ParamSpace::AssocSpace, 0); } { diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index c4e1f6fe8eb18..defad95f749bd 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -562,7 +562,7 @@ fn enforce_trait_manually_implementable(tcx: &ty::ctxt, sp: Span, trait_def_id: } else { return // everything OK }; - span_err!(tcx.sess, sp, E0173, "manual implementations of `{}` are experimental", trait_name); + span_err!(tcx.sess, sp, E0183, "manual implementations of `{}` are experimental", trait_name); span_help!(tcx.sess, sp, "add `#![feature(unboxed_closures)]` to the crate attributes to enable"); } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 0830bd476a2e5..2e1ba846584d2 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1840,7 +1840,7 @@ 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. + // Find any associated type bindings in the bound. let ref segments = ast_trait_ref.trait_ref.path.segments; let bindings = segments[segments.len() -1].parameters.bindings(); @@ -2042,7 +2042,7 @@ fn merge_param_bounds<'a>(tcx: &ty::ctxt, for predicate in where_clause.predicates.iter() { match predicate { - &ast::BoundPredicate(ref bound_pred) => { + &ast::WherePredicate::BoundPredicate(ref bound_pred) => { let predicate_param_id = tcx.def_map .borrow() @@ -2057,7 +2057,7 @@ fn merge_param_bounds<'a>(tcx: &ty::ctxt, result.push(bound); } } - &ast::EqPredicate(_) => panic!("not implemented") + &ast::WherePredicate::EqPredicate(_) => panic!("not implemented") } } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index e026fbd05c7f0..ecd3cafd91f16 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -149,5 +149,11 @@ register_diagnostics!( E0171, E0172, E0173, // manual implementations of unboxed closure traits are experimental - E0174 // explicit use of unboxed closure methods are experimental + E0174, // explicit use of unboxed closure methods are experimental + E0177, + E0178, + E0180, + E0181, + E0182, + E0183 ) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index df7b922bd1abc..630d41fa7e209 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -693,9 +693,16 @@ pub struct WherePredicate { impl Clean for ast::WherePredicate { fn clean(&self, cx: &DocContext) -> WherePredicate { - WherePredicate { - name: self.ident.clean(cx), - bounds: self.bounds.clean(cx) + match *self { + ast::WherePredicate::BoundPredicate(ref wbp) => { + WherePredicate { + name: wbp.ident.clean(cx), + bounds: wbp.bounds.clean(cx) + } + } + ast::WherePredicate::EqPredicate(_) => { + unimplemented!(); + } } } } diff --git a/src/test/compile-fail-fulldeps/phase-syntax-doesnt-resolve.rs b/src/test/compile-fail-fulldeps/phase-syntax-doesnt-resolve.rs index 3972d01850e63..00aeb1c1bae8f 100644 --- a/src/test/compile-fail-fulldeps/phase-syntax-doesnt-resolve.rs +++ b/src/test/compile-fail-fulldeps/phase-syntax-doesnt-resolve.rs @@ -19,6 +19,6 @@ extern crate macro_crate_test; fn main() { macro_crate_test::foo(); - //~^ ERROR failed to resolve. Use of undeclared module `macro_crate_test` + //~^ ERROR failed to resolve. Use of undeclared type or module `macro_crate_test` //~^^ ERROR unresolved name `macro_crate_test::foo` } diff --git a/src/test/compile-fail/assoc-eq-expr-path.rs b/src/test/compile-fail/assoc-eq-expr-path.rs new file mode 100644 index 0000000000000..1a96b0ca6812e --- /dev/null +++ b/src/test/compile-fail/assoc-eq-expr-path.rs @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Check that an associated type cannot be bound in an expression path. + +#![feature(associated_types)] + +trait Foo { + type A; + fn bar() -> int; +} + +impl Foo for int { + type A = uint; + fn bar() -> int { 42 } +} + +pub fn main() { + let x: int = Foo::::bar(); + //~^ERROR unexpected binding of associated item in expression path +} diff --git a/src/test/compile-fail/hrtb-precedence-of-plus-error-message.rs b/src/test/compile-fail/hrtb-precedence-of-plus-error-message.rs index ff3512ad8e72a..41a0be37add41 100644 --- a/src/test/compile-fail/hrtb-precedence-of-plus-error-message.rs +++ b/src/test/compile-fail/hrtb-precedence-of-plus-error-message.rs @@ -18,17 +18,17 @@ trait Bar { struct Foo<'a> { a: &'a Bar+'a, - //~^ ERROR E0171 + //~^ ERROR E0178 //~^^ NOTE perhaps you meant `&'a (Bar + 'a)`? b: &'a mut Bar+'a, - //~^ ERROR E0171 + //~^ ERROR E0178 //~^^ NOTE perhaps you meant `&'a mut (Bar + 'a)`? c: Box, // OK, no paren needed in this context d: fn() -> Bar+'a, - //~^ ERROR E0171 + //~^ ERROR E0178 //~^^ NOTE perhaps you forgot parentheses //~^^^ WARN deprecated syntax }