TraitDerivation, // trait T : SomeTrait { ... }
TraitBoundingTypeParameter, // fn f<T:SomeTrait>() { ... }
TraitObject, // Box<for<'a> SomeTrait>
+ TraitQPath, // <T as SomeTrait>::
}
impl NameBindings {
TraitImplementation => "implement",
TraitDerivation => "derive",
TraitObject => "reference",
+ TraitQPath => "extract an associated type from",
};
let msg = format!("attempt to {} a nonexistent trait `{}`", usage_str, path_str);
}
TyQPath(ref qpath) => {
- self.resolve_type(&*qpath.for_type);
-
- let current_module = self.current_module.clone();
- let module_path: Vec<_> =
- qpath.trait_name
- .segments
- .iter()
- .map(|ps| ps.identifier.name)
- .collect();
- match self.resolve_module_path(
- current_module,
- module_path.as_slice(),
- UseLexicalScope,
- qpath.trait_name.span,
- PathSearch) {
- Success((ref module, _)) if module.kind.get() ==
- TraitModuleKind => {
- match self.resolve_definition_of_name_in_module(
- (*module).clone(),
- qpath.item_name.name,
- TypeNS) {
- ChildNameDefinition(def, lp) |
- ImportNameDefinition(def, lp) => {
- match def {
- DefAssociatedTy(trait_type_id) => {
- let def = DefAssociatedTy(
- trait_type_id);
- self.record_def(ty.id, (def, lp));
- }
- _ => {
- self.resolve_error(
- ty.span,
- "not an associated type");
- }
- }
- }
- NoNameDefinition => {
- self.resolve_error(ty.span,
- "unresolved associated \
- type");
- }
- }
- }
- Success(..) => self.resolve_error(ty.span, "not a trait"),
- Indeterminate => {
- self.session.span_bug(ty.span,
- "indeterminate result when \
- resolving associated type")
- }
- Failed(error) => {
- let (span, help) = match error {
- Some((span, msg)) => (span, format!("; {}", msg)),
- None => (ty.span, String::new()),
- };
- self.resolve_error(span,
- format!("unresolved trait: {}",
- help).as_slice())
- }
- }
+ self.resolve_type(&*qpath.self_type);
+ self.resolve_trait_reference(ty.id, &*qpath.trait_ref, TraitQPath);
}
TyClosure(ref c) | TyProc(ref c) => {
regions_is_noop && self.types.is_empty()
}
+ pub fn type_for_def(&self, ty_param_def: &ty::TypeParameterDef) -> Ty<'tcx> {
+ *self.types.get(ty_param_def.space, ty_param_def.index)
+ }
+
pub fn has_regions_escaping_depth(&self, depth: uint) -> bool {
self.types.iter().any(|&t| ty::type_escapes_depth(t, depth)) || {
match self.regions {
use std::slice::Items;
use syntax::ast;
use syntax::codemap::{Span, DUMMY_SP};
+use util::common::ErrorReported;
pub use self::fulfill::FulfillmentContext;
pub use self::select::SelectionContext;
FieldSized,
}
-// An error has already been reported to the user, so no need to continue checking.
-#[deriving(Clone,Show)]
-pub struct ErrorReported;
-
pub type Obligations<'tcx> = subst::VecPerParamSpace<Obligation<'tcx>>;
pub type Selection<'tcx> = Vtable<'tcx, Obligation<'tcx>>;
use self::BuiltinBoundConditions::*;
use self::EvaluationResult::*;
-use super::{ErrorReported};
use super::{Obligation, ObligationCause};
use super::{SelectionError, Unimplemented, Overflow,
OutputTypeParameterMismatch};
use std::collections::hash_map::HashMap;
use std::rc::Rc;
use syntax::ast;
+use util::common::ErrorReported;
use util::ppaux::Repr;
pub struct SelectionContext<'cx, 'tcx:'cx> {
use std::rc::Rc;
use syntax::ast;
use syntax::codemap::Span;
+use util::common::ErrorReported;
use util::ppaux::Repr;
-use super::{ErrorReported, Obligation, ObligationCause, VtableImpl,
+use super::{Obligation, ObligationCause, VtableImpl,
VtableParam, VtableParamData, VtableImplData};
///////////////////////////////////////////////////////////////////////////
decl_def_id: ast::DefId,
decl_generics: &ty::Generics<'tcx>,
self_ty: Option<Ty<'tcx>>,
- associated_ty: Option<Ty<'tcx>>,
path: &ast::Path)
-> Substs<'tcx>
where AC: AstConv<'tcx>, RS: RegionScope
};
create_substs_for_ast_path(this, rscope, path.span, decl_def_id,
- decl_generics, self_ty, types, regions, associated_ty)
+ decl_generics, self_ty, types, regions)
}
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>,
- associated_ty: Option<Ty<'tcx>>)
+ regions: Vec<ty::Region>)
-> Substs<'tcx>
where AC: AstConv<'tcx>, RS: RegionScope
{
substs.types.push(
AssocSpace,
this.associated_type_binding(span,
- associated_ty,
+ self_ty,
decl_def_id,
- param.def_id))
+ param.def_id));
}
return substs;
this: &AC,
rscope: &RS,
ast_trait_ref: &ast::PolyTraitRef,
- self_ty: Option<Ty<'tcx>>,
- associated_type: Option<Ty<'tcx>>)
+ self_ty: Option<Ty<'tcx>>)
-> Rc<ty::TraitRef<'tcx>>
where AC: AstConv<'tcx>, RS: RegionScope
{
- instantiate_trait_ref(this, rscope, &ast_trait_ref.trait_ref, self_ty, associated_type)
+ instantiate_trait_ref(this, rscope, &ast_trait_ref.trait_ref, self_ty)
}
pub fn instantiate_trait_ref<'tcx,AC,RS>(this: &AC,
rscope: &RS,
ast_trait_ref: &ast::TraitRef,
- self_ty: Option<Ty<'tcx>>,
- associated_type: Option<Ty<'tcx>>)
+ self_ty: Option<Ty<'tcx>>)
-> 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,
- associated_type, &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));
this.tcx().trait_refs.borrow_mut().insert(ast_trait_ref.ref_id,
trait_ref.clone());
trait_ref
rscope: &RS,
trait_def_id: ast::DefId,
self_ty: Option<Ty<'tcx>>,
- associated_type: Option<Ty<'tcx>>,
path: &ast::Path)
-> ty::TraitRef<'tcx>
where AC: AstConv<'tcx>, RS: RegionScope
&trait_def.generics,
self_ty,
types,
- regions,
- associated_type);
+ regions);
ty::TraitRef::new(trait_def_id, substs)
}
did,
&generics,
None,
- None,
path);
let ty = decl_ty.subst(tcx, &substs);
TypeAndSubsts { substs: substs, ty: ty }
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, None, path)
+ ast_path_substs_for_ty(this, rscope, did, &generics, None, path)
};
let ty = decl_ty.subst(tcx, &substs);
rscope,
trait_def_id,
None,
- None,
path);
let empty_vec = [];
let bounds = match *opt_bounds { None => empty_vec.as_slice(),
constr(ast_ty_to_ty(this, rscope, a_seq_ty))
}
-fn associated_ty_to_ty<'tcx,AC,RS>(this: &AC,
- rscope: &RS,
- trait_path: &ast::Path,
- for_ast_type: &ast::Ty,
- trait_type_id: ast::DefId,
- span: Span)
- -> Ty<'tcx>
- where AC: AstConv<'tcx>, RS: RegionScope
+fn qpath_to_ty<'tcx,AC,RS>(this: &AC,
+ rscope: &RS,
+ ast_ty: &ast::Ty, // the TyQPath
+ qpath: &ast::QPath)
+ -> Ty<'tcx>
+ where AC: AstConv<'tcx>, RS: RegionScope
{
- debug!("associated_ty_to_ty(trait_path={}, for_ast_type={}, trait_type_id={})",
- trait_path.repr(this.tcx()),
- for_ast_type.repr(this.tcx()),
- trait_type_id.repr(this.tcx()));
-
- // Find the trait that this associated type belongs to.
- let trait_did = match ty::impl_or_trait_item(this.tcx(),
- trait_type_id).container() {
- ty::ImplContainer(_) => {
- this.tcx().sess.span_bug(span,
- "associated_ty_to_ty(): impl associated \
- types shouldn't go through this \
- function")
- }
- ty::TraitContainer(trait_id) => trait_id,
- };
+ debug!("qpath_to_ty(ast_ty={})",
+ ast_ty.repr(this.tcx()));
- let for_type = ast_ty_to_ty(this, rscope, for_ast_type);
- if !this.associated_types_of_trait_are_valid(for_type, trait_did) {
- this.tcx().sess.span_err(span,
- "this associated type is not \
- allowed in this context");
- return ty::mk_err()
- }
+ let self_type = ast_ty_to_ty(this, rscope, &*qpath.self_type);
+
+ debug!("qpath_to_ty: self_type={}", self_type.repr(this.tcx()));
- let trait_ref = ast_path_to_trait_ref(this,
+ let trait_ref = instantiate_trait_ref(this,
rscope,
- trait_did,
- None,
- Some(for_type),
- trait_path);
-
- debug!("associated_ty_to_ty(trait_ref={})",
- trait_ref.repr(this.tcx()));
-
- let trait_def = this.get_trait_def(trait_did);
- for type_parameter in trait_def.generics.types.iter() {
- if type_parameter.def_id == trait_type_id {
- debug!("associated_ty_to_ty(type_parameter={} substs={})",
- type_parameter.repr(this.tcx()),
- trait_ref.substs.repr(this.tcx()));
- return *trait_ref.substs.types.get(type_parameter.space,
- type_parameter.index)
+ &*qpath.trait_ref,
+ Some(self_type));
+
+ debug!("qpath_to_ty: trait_ref={}", trait_ref.repr(this.tcx()));
+
+ let trait_def = this.get_trait_def(trait_ref.def_id);
+
+ for ty_param_def in trait_def.generics.types.get_slice(AssocSpace).iter() {
+ if ty_param_def.name == qpath.item_name.name {
+ debug!("qpath_to_ty: corresponding ty_param_def={}", ty_param_def);
+ return trait_ref.substs.type_for_def(ty_param_def);
}
}
- this.tcx().sess.span_bug(span,
+
+ this.tcx().sess.span_bug(ast_ty.span,
"this associated type didn't get added \
as a parameter for some reason")
}
rscope,
trait_def_id,
None,
- None,
path);
let empty_bounds: &[ast::TyParamBound] = &[];
let ast_bounds = match *bounds {
}
}
ast::TyQPath(ref qpath) => {
- match tcx.def_map.borrow().get(&ast_ty.id) {
- None => {
- tcx.sess.span_bug(ast_ty.span,
- "unbound qualified path")
- }
- Some(&def::DefAssociatedTy(trait_type_id)) => {
- associated_ty_to_ty(this,
- rscope,
- &qpath.trait_name,
- &*qpath.for_type,
- trait_type_id,
- ast_ty.span)
- }
- Some(_) => {
- tcx.sess.span_err(ast_ty.span,
- "this qualified path does not name \
- an associated type");
- ty::mk_err()
- }
- }
+ qpath_to_ty(this, rscope, ast_ty, &**qpath)
}
ast::TyFixedLengthVec(ref ty, ref e) => {
match const_eval::eval_const_expr_partial(tcx, &**e) {
let main_trait_bound = match partitioned_bounds.trait_bounds.remove(0) {
Some(trait_bound) => {
- Some(instantiate_poly_trait_ref(this, rscope, trait_bound, None, None))
+ Some(instantiate_poly_trait_ref(this, rscope, trait_bound, None))
}
None => {
this.tcx().sess.span_err(
ty: Option<Ty<'tcx>>,
associated_type_id: ast::DefId,
generics: &ty::Generics<'tcx>)
- -> Ty<'tcx> {
+ -> Ty<'tcx>
+{
+ debug!("find_associated_type_in_generics(ty={}, associated_type_id={}, generics={}",
+ ty.repr(tcx), associated_type_id.repr(tcx), generics.repr(tcx));
+
let ty = match ty {
None => {
tcx.sess.span_bug(span,
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 ty::mk_param_from_def(tcx, type_parameter);
}
}
- tcx.sess.span_bug(span,
- "find_associated_type_in_generics(): didn't \
- find associated type anywhere in the generics \
- list")
+ tcx.sess.span_err(
+ span,
+ format!("no suitable bound on `{}`",
+ ty.user_string(tcx))[]);
+ ty::mk_err()
}
_ => {
- tcx.sess.span_bug(span,
- "find_associated_type_in_generics(): self type \
- is not a parameter")
-
+ 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()
}
}
}
for trait_ref in opt_trait_ref.iter() {
astconv::instantiate_trait_ref(&icx, &ExplicitRscope, trait_ref,
- Some(selfty), None);
+ Some(selfty));
}
},
ast::ItemTrait(_, _, _, ref trait_methods) => {
ccx,
subst::AssocSpace,
&associated_type.ty_param,
- generics.types.len(subst::TypeSpace),
+ generics.types.len(subst::AssocSpace),
&ast_generics.where_clause,
Some(local_def(trait_id)));
ccx.tcx.ty_param_defs.borrow_mut().insert(associated_type.ty_param.id,
astconv::instantiate_poly_trait_ref(this,
&ExplicitRscope,
bound,
- Some(param_ty.to_ty(this.tcx())),
Some(param_ty.to_ty(this.tcx())))
})
.collect();
use syntax::visit;
use syntax::visit::Visitor;
+// An error has already been reported to the user, so no need to continue checking.
+#[deriving(Clone,Show)]
+pub struct ErrorReported;
+
pub fn time<T, U>(do_it: bool, what: &str, u: U, f: |U| -> T) -> T {
local_data_key!(depth: uint);
if !do_it { return f(u); }
///
/// <Vec<T> as SomeTrait>::SomeAssociatedItem
/// ^~~~~ ^~~~~~~~~ ^~~~~~~~~~~~~~~~~~
-/// for_type trait_name item_name
+/// self_type trait_name item_name
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
pub struct QPath {
- pub for_type: P<Ty>,
- pub trait_name: Path,
+ pub self_type: P<Ty>,
+ pub trait_ref: P<TraitRef>,
pub item_name: Ident,
}
noop_fold_ty(t, self)
}
+ fn fold_qpath(&mut self, t: P<QPath>) -> P<QPath> {
+ noop_fold_qpath(t, self)
+ }
+
fn fold_mod(&mut self, m: Mod) -> Mod {
noop_fold_mod(m, self)
}
fld.fold_opt_bounds(bounds),
id)
}
- TyQPath(ref qpath) => {
- TyQPath(P(QPath {
- for_type: fld.fold_ty(qpath.for_type.clone()),
- trait_name: fld.fold_path(qpath.trait_name.clone()),
- item_name: fld.fold_ident(qpath.item_name.clone()),
- }))
+ TyQPath(qpath) => {
+ TyQPath(fld.fold_qpath(qpath))
}
TyFixedLengthVec(ty, e) => {
TyFixedLengthVec(fld.fold_ty(ty), fld.fold_expr(e))
})
}
+pub fn noop_fold_qpath<T: Folder>(qpath: P<QPath>, fld: &mut T) -> P<QPath> {
+ qpath.map(|qpath| {
+ QPath {
+ self_type: fld.fold_ty(qpath.self_type),
+ trait_ref: qpath.trait_ref.map(|tr| fld.fold_trait_ref(tr)),
+ item_name: fld.fold_ident(qpath.item_name),
+ }
+ })
+}
+
pub fn noop_fold_foreign_mod<T: Folder>(ForeignMod {abi, view_items, items}: ForeignMod,
fld: &mut T) -> ForeignMod {
ForeignMod {
} else if self.eat_keyword(keywords::Proc) {
self.parse_proc_type(Vec::new())
} else if self.token == token::Lt {
- // QUALIFIED PATH
+ // QUALIFIED PATH `<TYPE as TRAIT_REF>::item`
self.bump();
- let for_type = self.parse_ty(true);
+ let self_type = self.parse_ty(true);
self.expect_keyword(keywords::As);
- let trait_name = self.parse_path(LifetimeAndTypesWithoutColons);
+ let trait_ref = self.parse_trait_ref();
self.expect(&token::Gt);
self.expect(&token::ModSep);
let item_name = self.parse_ident();
TyQPath(P(QPath {
- for_type: for_type,
- trait_name: trait_name.path,
+ self_type: self_type,
+ trait_ref: P(trait_ref),
item_name: item_name,
}))
} else if self.token == token::ModSep ||
}
ast::TyQPath(ref qpath) => {
try!(word(&mut self.s, "<"));
- try!(self.print_type(&*qpath.for_type));
+ try!(self.print_type(&*qpath.self_type));
try!(space(&mut self.s));
try!(self.word_space("as"));
- try!(self.print_path(&qpath.trait_name, false));
+ try!(self.print_trait_ref(&*qpath.trait_ref));
try!(word(&mut self.s, ">"));
try!(word(&mut self.s, "::"));
try!(self.print_ident(qpath.item_name));
}
}
TyQPath(ref qpath) => {
- visitor.visit_ty(&*qpath.for_type);
- visitor.visit_path(&qpath.trait_name, typ.id);
+ visitor.visit_ty(&*qpath.self_type);
+ visitor.visit_trait_ref(&*qpath.trait_ref);
visitor.visit_ident(typ.span, qpath.item_name);
}
TyFixedLengthVec(ref ty, ref expression) => {
trait Other {
fn uhoh<U:Get>(&self, foo: U, bar: <Self as Get>::Value) {}
- //~^ ERROR this associated type is not allowed in this context
+ //~^ ERROR no suitable bound on `Self`
}
impl<T:Get> Other for T {
fn uhoh<U:Get>(&self, foo: U, bar: <(T, U) as Get>::Value) {}
- //~^ ERROR this associated type is not allowed in this context
+ //~^ ERROR currently unsupported
}
trait Grab {
}
fn get(x: int) -> <int as Get>::Value {}
-//~^ ERROR this associated type is not allowed in this context
+//~^ ERROR unsupported
struct Struct {
x: int,
impl Struct {
fn uhoh<T>(foo: <T as Get>::Value) {}
- //~^ ERROR this associated type is not allowed in this context
+ //~^ ERROR no suitable bound on `T`
}
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.
+
+#![feature(associated_types)]
+
+trait Foo<T> {
+ type Bar;
+ fn get_bar() -> <Self as Foo<T>>::Bar;
+}
+
+fn main() { }