use middle::def;
use middle::ty::{self, Ty};
use syntax::ast;
-use syntax::codemap::Span;
use util::ppaux::Repr;
pub const NO_REGIONS: uint = 1;
pub const NO_TPS: uint = 2;
-pub fn check_path_args(tcx: &ty::ctxt,
- span: Span,
- segments: &[ast::PathSegment],
- flags: uint) {
- if (flags & NO_TPS) != 0 {
- if segments.iter().any(|s| s.parameters.has_types()) {
- span_err!(tcx.sess, span, E0109,
- "type parameters are not allowed on this type");
+pub fn check_path_args(tcx: &ty::ctxt, segments: &[ast::PathSegment], flags: uint) {
+ for segment in segments {
+ if (flags & NO_TPS) != 0 {
+ for typ in segment.parameters.types() {
+ span_err!(tcx.sess, typ.span, E0109,
+ "type parameters are not allowed on this type");
+ break;
+ }
}
- }
- if (flags & NO_REGIONS) != 0 {
- if segments.iter().any(|s| s.parameters.has_lifetimes()) {
- span_err!(tcx.sess, span, E0110,
- "lifetime parameters are not allowed on this type");
+ if (flags & NO_REGIONS) != 0 {
+ for lifetime in segment.parameters.lifetimes() {
+ span_err!(tcx.sess, lifetime.span, E0110,
+ "lifetime parameters are not allowed on this type");
+ break;
+ }
}
}
}
pub fn prim_ty_to_ty<'tcx>(tcx: &ty::ctxt<'tcx>,
- span: Span,
segments: &[ast::PathSegment],
nty: ast::PrimTy)
-> Ty<'tcx> {
- check_path_args(tcx, span, segments, NO_TPS | NO_REGIONS);
+ check_path_args(tcx, segments, NO_TPS | NO_REGIONS);
match nty {
ast::TyBool => tcx.types.bool,
ast::TyChar => tcx.types.char,
Some(&d) => d
};
if let def::DefPrimTy(nty) = def {
- Some(prim_ty_to_ty(tcx, path.span, &path.segments[], nty))
+ Some(prim_ty_to_ty(tcx, &path.segments[], nty))
} else {
None
}
}
fn resolve_generics(&mut self, generics: &Generics) {
- for type_parameter in &generics.ty_params {
+ for type_parameter in &*generics.ty_params {
self.check_if_primitive_type_name(type_parameter.ident.name, type_parameter.span);
}
for predicate in &generics.where_clause.predicates {
// multiple elements in it or not.
ExprPath(ref path) | ExprQPath(ast::QPath { ref path, .. }) => {
- if let ExprQPath(_) = expr.node {
+ let max_assoc_types = if let ExprQPath(_) = expr.node {
// Make sure the trait is valid.
let _ = self.resolve_trait_reference(expr.id, path, 1);
+ 1
+ } else {
+ path.segments.len()
+ };
+
+ let mut result = self.with_no_errors(|this| {
+ this.resolve_path(expr.id, path, 0, ValueNS, true)
+ });
+ for depth in 1..max_assoc_types {
+ if result.is_some() {
+ break;
+ }
+ self.with_no_errors(|this| {
+ result = this.resolve_path(expr.id, path, depth, TypeNS, true);
+ });
+ }
+ if let Some((DefMod(_), _, _)) = result {
+ // A module is not a valid type or value.
+ result = None;
}
// This is a local path in the value namespace. Walk through
// scopes looking for it.
- match self.resolve_path(expr.id, path, 0, ValueNS, true) {
+ match result {
// Check if struct variant
- Some((DefVariant(_, _, true), _, _)) => {
+ Some((DefVariant(_, _, true), _, 0)) => {
let path_name = self.path_names_to_string(path, 0);
self.resolve_error(expr.span,
&format!("`{}` is a struct variant name, but \
debug!("(resolving expr) resolved `{}`",
self.path_names_to_string(path, 0));
+ // Partial resolutions will need the set of traits in scope,
+ // so they can be completed during typeck.
+ if def.2 != 0 {
+ let method_name = path.segments.last().unwrap().identifier.name;
+ let traits = self.search_for_traits_containing_method(method_name);
+ self.trait_map.insert(expr.id, traits);
+ }
+
self.record_def(expr.id, def);
}
None => {
}
_ => {
+ // Keep reporting some errors even if they're ignored above.
+ self.resolve_path(expr.id, path, 0, ValueNS, true);
+
let mut method_scope = false;
self.value_ribs.iter().rev().all(|rib| {
method_scope = match rib.kind {
this: &AstConv<'tcx>,
rscope: &RegionScope,
span: Span,
+ param_mode: PathParamMode,
decl_generics: &ty::Generics<'tcx>,
item_segment: &ast::PathSegment)
-> Substs<'tcx>
let (regions, types, assoc_bindings) = match item_segment.parameters {
ast::AngleBracketedParameters(ref data) => {
- convert_angle_bracketed_parameters(this, rscope, path.span, decl_generics, data)
+ convert_angle_bracketed_parameters(this, rscope, span, decl_generics, data)
}
ast::ParenthesizedParameters(ref data) => {
span_err!(tcx.sess, span, E0214,
"parenthesized parameters may only be used with a trait");
- convert_parenthesized_parameters(this, rscope, path.span, decl_generics, data)
+ convert_parenthesized_parameters(this, rscope, span, decl_generics, data)
}
};
create_substs_for_ast_path(this,
span,
+ param_mode,
decl_generics,
None,
types,
regions)
}
+#[derive(PartialEq, Eq)]
+pub enum PathParamMode {
+ // Any path in a type context.
+ Explicit,
+ // The `module::Type` in `module::Type::method` in an expression.
+ Optional
+}
+
fn create_region_substs<'tcx>(
this: &AstConv<'tcx>,
rscope: &RegionScope,
fn create_substs_for_ast_path<'tcx>(
this: &AstConv<'tcx>,
span: Span,
+ param_mode: PathParamMode,
decl_generics: &ty::Generics<'tcx>,
self_ty: Option<Ty<'tcx>>,
types_provided: Vec<Ty<'tcx>>,
// Convert the type parameters supplied by the user.
let ty_param_defs = decl_generics.types.get_slice(TypeSpace);
- let supplied_ty_param_count = types_provided.len();
let formal_ty_param_count = ty_param_defs.len();
let required_ty_param_count = ty_param_defs.iter()
.take_while(|x| x.default.is_none())
.count();
- let mut type_substs = types_provided;
+ // Fill with `ty_infer` if no params were specified, as long as
+ // they were optional (e.g. paths inside expressions).
+ let mut type_substs = if param_mode == PathParamMode::Optional &&
+ types_provided.is_empty() {
+ (0..formal_ty_param_count).map(|_| this.ty_infer(span)).collect()
+ } else {
+ types_provided
+ };
+
+ let supplied_ty_param_count = type_substs.len();
check_type_argument_count(this.tcx(), span, supplied_ty_param_count,
required_ty_param_count, formal_ty_param_count);
}
}
- return substs;
+ substs
}
struct ConvertedBinding<'tcx> {
let trait_ref = ast_path_to_trait_ref(this,
rscope,
path.span,
+ PathParamMode::Explicit,
trait_def_id,
self_ty,
path.segments.last().unwrap(),
this: &AstConv<'tcx>,
rscope: &RegionScope,
span: Span,
+ param_mode: PathParamMode,
trait_def_id: ast::DefId,
trait_segment: &ast::PathSegment,
mut projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
let trait_ref = ty::Binder(ast_path_to_trait_ref(this,
&shifted_rscope,
span,
+ param_mode,
trait_def_id,
None,
trait_segment,
this: &AstConv<'tcx>,
rscope: &RegionScope,
span: Span,
+ param_mode: PathParamMode,
trait_def_id: ast::DefId,
self_ty: Option<Ty<'tcx>>,
trait_segment: &ast::PathSegment,
the crate attributes to enable");
}
- convert_angle_bracketed_parameters(this, rscope, path.span, &trait_def.generics, data)
+ convert_angle_bracketed_parameters(this, rscope, span, &trait_def.generics, data)
}
ast::ParenthesizedParameters(ref data) => {
// For now, require that parenthetical notation be used
the crate attributes to enable");
}
- convert_parenthesized_parameters(this, rscope, path.span, &trait_def.generics, data)
+ convert_parenthesized_parameters(this, rscope, span, &trait_def.generics, data)
}
};
let substs = create_substs_for_ast_path(this,
span,
+ param_mode,
&trait_def.generics,
self_ty,
types,
this: &AstConv<'tcx>,
rscope: &RegionScope,
span: Span,
+ param_mode: PathParamMode,
did: ast::DefId,
item_segment: &ast::PathSegment)
-> Ty<'tcx>
ty: decl_ty
} = this.get_item_type_scheme(did);
- let substs = ast_path_substs_for_ty(this, rscope, span, &generics, item_segment);
+ let substs = ast_path_substs_for_ty(this, rscope,
+ span, param_mode,
+ &generics, item_segment);
// FIXME(#12938): This is a hack until we have full support for DST.
if Some(did) == this.tcx().lang_items.owned_box() {
let trait_ref = object_path_to_poly_trait_ref(this,
rscope,
path.span,
+ PathParamMode::Explicit,
trait_def_id,
path.segments.last().unwrap(),
&mut projection_bounds);
-> (Ty<'tcx>, def::Def)
{
let tcx = this.tcx();
- check_path_args(tcx, span, slice::ref_slice(item_segment),
- NO_TPS | NO_REGIONS);
+ check_path_args(tcx, slice::ref_slice(item_segment), NO_TPS | NO_REGIONS);
let assoc_name = item_segment.identifier.name;
let ty_param_node_id = if let ty::ty_param(_) = ty.sty {
fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>,
rscope: &RegionScope,
span: Span,
- opt_self_ty: Option<&ast::Ty>,
+ param_mode: PathParamMode,
+ opt_self_ty: Option<Ty<'tcx>>,
trait_def_id: ast::DefId,
trait_segment: &ast::PathSegment,
item_segment: &ast::PathSegment)
{
let tcx = this.tcx();
- check_path_args(tcx, span, slice::ref_slice(item_segment),
- NO_TPS | NO_REGIONS);
+ check_path_args(tcx, slice::ref_slice(item_segment), NO_TPS | NO_REGIONS);
let self_ty = if let Some(ty) = opt_self_ty {
- ast_ty_to_ty(this, rscope, ty)
+ ty
} else {
let path_str = ty::item_path_str(tcx, trait_def_id);
span_err!(tcx.sess, span, E0223,
let trait_ref = ast_path_to_trait_ref(this,
rscope,
span,
+ param_mode,
trait_def_id,
Some(self_ty),
trait_segment,
}
}
+pub fn finish_resolving_def_to_ty<'tcx>(this: &AstConv<'tcx>,
+ rscope: &RegionScope,
+ span: Span,
+ param_mode: PathParamMode,
+ def: &mut def::Def,
+ opt_self_ty: Option<Ty<'tcx>>,
+ segments: &[ast::PathSegment],
+ assoc_segments: &[ast::PathSegment])
+ -> Ty<'tcx> {
+ let tcx = this.tcx();
+
+ let base_ty = match *def {
+ def::DefTrait(trait_def_id) => {
+ // N.B. this case overlaps somewhat with
+ // TyObjectSum, see that fn for details
+ let mut projection_bounds = Vec::new();
+
+ let trait_ref = object_path_to_poly_trait_ref(this,
+ rscope,
+ span,
+ param_mode,
+ trait_def_id,
+ segments.last().unwrap(),
+ &mut projection_bounds);
+
+ check_path_args(tcx, segments.init(), NO_TPS | NO_REGIONS);
+ trait_ref_to_object_type(this, rscope, span, trait_ref,
+ projection_bounds, &[])
+ }
+ def::DefTy(did, _) | def::DefStruct(did) => {
+ check_path_args(tcx, segments.init(), NO_TPS | NO_REGIONS);
+ ast_path_to_ty(this, rscope, span,
+ param_mode, did,
+ segments.last().unwrap())
+ }
+ def::DefTyParam(space, index, _, name) => {
+ check_path_args(tcx, segments, NO_TPS | NO_REGIONS);
+ ty::mk_param(tcx, space, index, name)
+ }
+ def::DefSelfTy(_) => {
+ // n.b.: resolve guarantees that the this type only appears in a
+ // trait, which we rely upon in various places when creating
+ // substs
+ check_path_args(tcx, segments, NO_TPS | NO_REGIONS);
+ ty::mk_self_type(tcx)
+ }
+ def::DefAssociatedTy(trait_did, _) => {
+ check_path_args(tcx, &segments[..segments.len()-2], NO_TPS | NO_REGIONS);
+ qpath_to_ty(this, rscope, span, param_mode,
+ opt_self_ty, trait_did,
+ &segments[segments.len()-2],
+ segments.last().unwrap())
+ }
+ def::DefMod(id) => {
+ tcx.sess.span_bug(span,
+ &format!("found module name used as a type: {}",
+ tcx.map.node_to_string(id.node)));
+ }
+ def::DefPrimTy(prim_ty) => {
+ prim_ty_to_ty(tcx, segments, prim_ty)
+ }
+ _ => {
+ span_fatal!(tcx.sess, span, E0248,
+ "found value name used as a type: {:?}", *def);
+ }
+ };
+
+ // If any associated type segments remain, attempt to resolve them.
+ let mut ty = base_ty;
+ for segment in assoc_segments {
+ if ty.sty == ty::ty_err {
+ break;
+ }
+ // This is pretty bad (it will fail except for T::A and Self::A).
+ let (a_ty, a_def) = associated_path_def_to_ty(this, span,
+ ty, *def, segment);
+ ty = a_ty;
+ *def = a_def;
+ }
+ ty
+}
+
/// Parses the programmer's textual representation of a type into our
/// internal notion of a type.
pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>,
tcx.sess.span_bug(ast_ty.span,
&format!("unbound path {}", ast_ty.repr(tcx)))
};
- let (base_def, max_depth) = result;
- let span = ast_ty.span; // Could be more granular.
- let segments = &path.segments[..path.segments.len()-max_depth];
- let base_ty = match base_def {
- def::DefTrait(trait_def_id) => {
- // N.B. this case overlaps somewhat with
- // TyObjectSum, see that fn for details
- let mut projection_bounds = Vec::new();
-
- let trait_ref = object_path_to_poly_trait_ref(this,
- rscope,
- span,
- trait_def_id,
- segments.last().unwrap(),
- &mut projection_bounds);
-
- check_path_args(tcx, span, segments.init(), NO_TPS | NO_REGIONS);
- trait_ref_to_object_type(this, rscope, span, trait_ref,
- projection_bounds, &[])
- }
- def::DefTy(did, _) | def::DefStruct(did) => {
- check_path_args(tcx, span, segments.init(), NO_TPS | NO_REGIONS);
- ast_path_to_ty(this, rscope, span, did, segments.last().unwrap())
- }
- def::DefTyParam(space, index, _, name) => {
- check_path_args(tcx, span, segments, NO_TPS | NO_REGIONS);
- ty::mk_param(tcx, space, index, name)
- }
- def::DefSelfTy(_) => {
- // n.b.: resolve guarantees that the this type only appears in a
- // trait, which we rely upon in various places when creating
- // substs
- check_path_args(tcx, span, segments, NO_TPS | NO_REGIONS);
- ty::mk_self_type(tcx)
- }
- def::DefAssociatedTy(trait_did, _) => {
- let opt_self_ty = if let ast::TyQPath(ref qpath) = ast_ty.node {
- Some(&*qpath.self_type)
- } else {
- None
- };
- check_path_args(tcx, span, &segments[..segments.len()-2],
- NO_TPS | NO_REGIONS);
- qpath_to_ty(this, rscope, span, opt_self_ty, trait_did,
- &segments[segments.len()-2],
- segments.last().unwrap())
- }
- def::DefMod(id) => {
- tcx.sess.span_bug(span,
- &format!("found module name used as a type: {}",
- tcx.map.node_to_string(id.node)));
- }
- def::DefPrimTy(prim_ty) => {
- prim_ty_to_ty(tcx, span, segments, prim_ty)
- }
- _ => {
- span_fatal!(tcx.sess, span, E0248,
- "found value name used as a type: {:?}", base_def);
- }
+ let (mut def, max_depth) = result;
+ let base_ty_end = path.segments.len() - max_depth;
+ let opt_self_ty = if let ast::TyQPath(ref qpath) = ast_ty.node {
+ Some(ast_ty_to_ty(this, rscope, &*qpath.self_type))
+ } else {
+ None
};
-
- // If any associated type segments remain, attempt to resolve them.
- let mut ty = base_ty;
- let mut def = base_def;
- for depth in (0..max_depth).rev() {
- if ty.sty == ty::ty_err {
- break;
- }
- // This is pretty bad (it will fail except for T::A and Self::A).
- let segment = &path.segments[path.segments.len()-depth-1];
- let (a_ty, a_def) = associated_path_def_to_ty(this, span,
- ty, def, segment);
- ty = a_ty;
- def = a_def;
- }
+ let ty = finish_resolving_def_to_ty(this, rscope, ast_ty.span,
+ PathParamMode::Explicit, &mut def,
+ opt_self_ty,
+ &path.segments[..base_ty_end],
+ &path.segments[base_ty_end..]);
if max_depth != 0 && ty.sty != ty::ty_err {
// Write back the new resolution.
};
instantiate_path(pcx.fcx,
- path,
+ &path.segments,
ty::lookup_item_type(tcx, enum_def_id),
&ty::lookup_predicates(tcx, enum_def_id),
None,
} else {
ctor_scheme
};
- instantiate_path(pcx.fcx, path, path_scheme, &ctor_predicates, None, def, pat.span, pat.id);
+ instantiate_path(pcx.fcx, &path.segments,
+ path_scheme, &ctor_predicates,
+ None, def, pat.span, pat.id);
let pat_ty = fcx.node_ty(pat.id);
demand::eqtype(fcx, pat.span, expected, pat_ty);
use check::{FnCtxt};
use check::vtable;
use check::vtable::select_new_fcx_obligations;
+use middle::def;
use middle::subst;
use middle::traits;
use middle::ty::*;
call_expr_id: ast::NodeId)
-> bool
{
- match probe::probe(fcx, span, method_name, self_ty, call_expr_id) {
+ let mode = probe::Mode::MethodCall;
+ match probe::probe(fcx, span, mode, method_name, self_ty, call_expr_id) {
Ok(..) => true,
Err(NoMatch(..)) => false,
Err(Ambiguity(..)) => true,
call_expr.repr(fcx.tcx()),
self_expr.repr(fcx.tcx()));
+ let mode = probe::Mode::MethodCall;
let self_ty = fcx.infcx().resolve_type_vars_if_possible(&self_ty);
- let pick = try!(probe::probe(fcx, span, method_name, self_ty, call_expr.id));
+ let pick = try!(probe::probe(fcx, span, mode, method_name, self_ty, call_expr.id));
Ok(confirm::confirm(fcx, span, self_expr, call_expr, self_ty, pick, supplied_method_types))
}
Some(callee)
}
+pub fn resolve_ufcs<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
+ span: Span,
+ method_name: ast::Name,
+ self_ty: Ty<'tcx>,
+ expr_id: ast::NodeId)
+ -> Result<def::Def, MethodError>
+{
+ let mode = probe::Mode::Path;
+ let pick = try!(probe::probe(fcx, span, mode, method_name, self_ty, expr_id));
+ let def_id = pick.method_ty.def_id;
+ let provenance = match pick.kind {
+ probe::InherentImplPick(impl_def_id) => def::FromImpl(impl_def_id),
+ _ => def::FromTrait(pick.method_ty.container.id())
+ };
+ Ok(def::DefMethod(def_id, provenance))
+}
+
/// Find method with name `method_name` defined in `trait_def_id` and return it, along with its
/// index (or `None`, if no such method).
struct ProbeContext<'a, 'tcx:'a> {
fcx: &'a FnCtxt<'a, 'tcx>,
span: Span,
+ mode: Mode,
method_name: ast::Name,
steps: Rc<Vec<CandidateStep<'tcx>>>,
opt_simplified_steps: Option<Vec<fast_reject::SimplifiedType>>,
AutoRef(ast::Mutability, Box<PickAdjustment>),
}
+#[derive(PartialEq, Eq, Copy)]
+pub enum Mode {
+ // An expression of the form `receiver.method_name(...)`.
+ // Autoderefs are performed on `receiver`, lookup is done based on the
+ // `self` argument of the method, and static methods aren't considered.
+ MethodCall,
+ // An expression of the form `Type::method` or `<T>::method`.
+ // No autoderefs are performed, lookup is done based on the type each
+ // implementation is for, and static methods are included.
+ Path
+}
+
pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
span: Span,
+ mode: Mode,
method_name: ast::Name,
self_ty: Ty<'tcx>,
- call_expr_id: ast::NodeId)
+ scope_expr_id: ast::NodeId)
-> PickResult<'tcx>
{
- debug!("probe(self_ty={}, method_name={}, call_expr_id={})",
+ debug!("probe(self_ty={}, method_name={}, scope_expr_id={})",
self_ty.repr(fcx.tcx()),
method_name,
- call_expr_id);
+ scope_expr_id);
// FIXME(#18741) -- right now, creating the steps involves evaluating the
// `*` operator, which registers obligations that then escape into
// it ride, although it's really not great, and in fact could I
// think cause spurious errors. Really though this part should
// take place in the `fcx.infcx().probe` below.
- let steps = match create_steps(fcx, span, self_ty) {
- Some(steps) => steps,
- None => return Err(MethodError::NoMatch(Vec::new(), Vec::new())),
+ let steps = if mode == Mode::MethodCall {
+ match create_steps(fcx, span, self_ty) {
+ Some(steps) => steps,
+ None => return Err(MethodError::NoMatch(Vec::new(), Vec::new())),
+ }
+ } else {
+ vec![CandidateStep {
+ self_ty: self_ty,
+ adjustment: AutoDeref(0)
+ }]
};
// Create a list of simplified self types, if we can.
// this creates one big transaction so that all type variables etc
// that we create during the probe process are removed later
- let mut dummy = Some((steps, opt_simplified_steps)); // FIXME(#18101) need once closures
fcx.infcx().probe(|_| {
- let (steps, opt_simplified_steps) = dummy.take().unwrap();
- let mut probe_cx = ProbeContext::new(fcx, span, method_name, steps, opt_simplified_steps);
+ let mut probe_cx = ProbeContext::new(fcx,
+ span,
+ mode,
+ method_name,
+ steps,
+ opt_simplified_steps);
probe_cx.assemble_inherent_candidates();
- try!(probe_cx.assemble_extension_candidates_for_traits_in_scope(call_expr_id));
+ try!(probe_cx.assemble_extension_candidates_for_traits_in_scope(scope_expr_id));
probe_cx.pick()
})
}
impl<'a,'tcx> ProbeContext<'a,'tcx> {
fn new(fcx: &'a FnCtxt<'a,'tcx>,
span: Span,
+ mode: Mode,
method_name: ast::Name,
steps: Vec<CandidateStep<'tcx>>,
opt_simplified_steps: Option<Vec<fast_reject::SimplifiedType>>)
ProbeContext {
fcx: fcx,
span: span,
+ mode: mode,
method_name: method_name,
inherent_candidates: Vec::new(),
extension_candidates: Vec::new(),
return self.record_static_candidate(ImplSource(impl_def_id));
}
- let impl_substs = self.impl_substs(impl_def_id);
+ let (impl_ty, impl_substs) = self.impl_ty_and_substs(impl_def_id);
+ let impl_ty = self.fcx.instantiate_type_scheme(self.span, &impl_substs, &impl_ty);
// Determine the receiver type that the method itself expects.
let xform_self_ty =
- self.xform_self_ty(&method, &impl_substs);
+ self.xform_self_ty(&method, impl_ty, &impl_substs);
self.inherent_candidates.push(Candidate {
xform_self_ty: xform_self_ty,
new_trait_ref.def_id,
method_num);
- let xform_self_ty = this.xform_self_ty(&m, new_trait_ref.substs);
+ let xform_self_ty = this.xform_self_ty(&m,
+ new_trait_ref.self_ty(),
+ new_trait_ref.substs);
this.inherent_candidates.push(Candidate {
xform_self_ty: xform_self_ty,
this.erase_late_bound_regions(&poly_trait_ref);
let xform_self_ty =
- this.xform_self_ty(&m, trait_ref.substs);
+ this.xform_self_ty(&m,
+ trait_ref.self_ty(),
+ trait_ref.substs);
debug!("found match: trait_ref={} substs={} m={}",
trait_ref.repr(this.tcx()),
continue;
}
- let impl_substs = self.impl_substs(impl_def_id);
+ let (_, impl_substs) = self.impl_ty_and_substs(impl_def_id);
debug!("impl_substs={}", impl_substs.repr(self.tcx()));
// Determine the receiver type that the method itself expects.
let xform_self_ty =
- self.xform_self_ty(&method, impl_trait_ref.substs);
+ self.xform_self_ty(&method,
+ impl_trait_ref.self_ty(),
+ impl_trait_ref.substs);
debug!("xform_self_ty={}", xform_self_ty.repr(self.tcx()));
&trait_def.generics,
step.self_ty);
- let xform_self_ty = self.xform_self_ty(&method_ty, &substs);
+ let xform_self_ty = self.xform_self_ty(&method_ty,
+ step.self_ty,
+ &substs);
self.inherent_candidates.push(Candidate {
xform_self_ty: xform_self_ty,
method_ty: method_ty.clone(),
bound.repr(self.tcx()));
if self.infcx().can_equate(&step.self_ty, &bound.self_ty()).is_ok() {
- let xform_self_ty = self.xform_self_ty(&method, bound.substs);
+ let xform_self_ty = self.xform_self_ty(&method,
+ bound.self_ty(),
+ bound.substs);
debug!("assemble_projection_candidates: bound={} xform_self_ty={}",
bound.repr(self.tcx()),
.filter(|b| b.def_id() == trait_def_id)
{
let bound = self.erase_late_bound_regions(&poly_bound);
- let xform_self_ty = self.xform_self_ty(&method_ty, bound.substs);
+ let xform_self_ty = self.xform_self_ty(&method_ty,
+ bound.self_ty(),
+ bound.substs);
debug!("assemble_where_clause_candidates: bound={} xform_self_ty={}",
bound.repr(self.tcx()),
// "fast track" -- check for usage of sugar
match method.explicit_self {
ty::StaticExplicitSelfCategory => {
- // fallthrough
+ if self.mode == Mode::Path {
+ return true;
+ }
}
ty::ByValueExplicitSelfCategory |
ty::ByReferenceExplicitSelfCategory(..) |
fn xform_self_ty(&self,
method: &Rc<ty::Method<'tcx>>,
+ impl_ty: Ty<'tcx>,
substs: &subst::Substs<'tcx>)
-> Ty<'tcx>
{
- debug!("xform_self_ty(self_ty={}, substs={})",
- method.fty.sig.0.inputs[0].repr(self.tcx()),
+ debug!("xform_self_ty(impl_ty={}, self_ty={}, substs={})",
+ impl_ty.repr(self.tcx()),
+ method.fty.sig.0.inputs.get(0).repr(self.tcx()),
substs.repr(self.tcx()));
assert!(!substs.has_escaping_regions());
// if there are any.
assert_eq!(substs.types.len(subst::FnSpace), 0);
assert_eq!(substs.regions().len(subst::FnSpace), 0);
+
+ if self.mode == Mode::Path {
+ return impl_ty;
+ }
+
let placeholder;
let mut substs = substs;
if
xform_self_ty
}
- fn impl_substs(&self,
- impl_def_id: ast::DefId)
- -> subst::Substs<'tcx>
+ /// Get the type of an impl and generate substitutions with placeholders.
+ fn impl_ty_and_substs(&self,
+ impl_def_id: ast::DefId)
+ -> (Ty<'tcx>, subst::Substs<'tcx>)
{
let impl_pty = ty::lookup_item_type(self.tcx(), impl_def_id);
impl_pty.generics.regions.map(
|_| ty::ReStatic); // see erase_late_bound_regions() for an expl of why 'static
- subst::Substs::new(type_vars, region_placeholders)
+ let substs = subst::Substs::new(type_vars, region_placeholders);
+ (impl_pty.ty, substs)
}
/// Replace late-bound-regions bound by `value` with `'static` using
use self::IsBinopAssignment::*;
use self::TupleArgumentsFlag::*;
-use astconv::{self, ast_region_to_region, ast_ty_to_ty, AstConv};
+use astconv::{self, ast_region_to_region, ast_ty_to_ty, AstConv, PathParamMode};
use check::_match::pat_ctxt;
use fmt_macros::{Parser, Piece, Position};
+use middle::astconv_util::{check_path_args, NO_TPS, NO_REGIONS};
use middle::{const_eval, def};
use middle::infer;
use middle::mem_categorization as mc;
let ty::TypeScheme { generics, ty: decl_ty } =
ty::lookup_item_type(tcx, did);
- let wants_params =
- generics.has_type_params(TypeSpace) || generics.has_region_params(TypeSpace);
-
- let needs_defaults =
- wants_params &&
- path.segments.iter().all(|s| s.parameters.is_empty());
-
- let substs = if needs_defaults {
- let tps =
- self.infcx().next_ty_vars(generics.types.len(TypeSpace));
- let rps =
- self.infcx().region_vars_for_defs(path.span,
- generics.regions.get_slice(TypeSpace));
- Substs::new_type(tps, rps)
- } else {
- astconv::ast_path_substs_for_ty(self, self,
- path.span,
- &generics,
- path.segments.last().unwrap())
- };
+ let substs = astconv::ast_path_substs_for_ty(self, self,
+ path.span,
+ PathParamMode::Optional,
+ &generics,
+ path.segments.last().unwrap());
let ty = self.instantiate_type_scheme(path.span, &substs, &decl_ty);
};
fcx.write_ty(id, oprnd_t);
}
- ast::ExprPath(ref path) => {
- let defn = lookup_def(fcx, path.span, id);
- let (scheme, predicates) = type_scheme_and_predicates_for_def(fcx, expr.span, defn);
- instantiate_path(fcx, path, scheme, &predicates, None, defn, expr.span, expr.id);
+ ast::ExprPath(ref path) | ast::ExprQPath(ast::QPath { ref path, .. }) => {
+ let opt_self_ty = if let ast::ExprQPath(ref qpath) = expr.node {
+ Some(fcx.to_ty(&*qpath.self_type))
+ } else {
+ None
+ };
- // We always require that the type provided as the value for
- // a type parameter outlives the moment of instantiation.
- constrain_path_type_parameters(fcx, expr);
- }
- ast::ExprQPath(ref qpath) => {
- let self_ty = fcx.to_ty(&*qpath.self_type);
- let defn = lookup_def(fcx, expr.span, id);
- let (scheme, predicates) = type_scheme_and_predicates_for_def(fcx, expr.span, defn);
- instantiate_path(fcx, &qpath.path, scheme, &predicates, Some(self_ty),
- defn, expr.span, expr.id);
+ // Helpers to avoid keeping the RefCell borrow for too long.
+ let get_def = |&:| tcx.def_map.borrow().get(&id).cloned();
+ let get_partial_def = |&:| tcx.partial_def_map.borrow().get(&id).cloned();
+
+ if let Some(def) = get_def() {
+ let (scheme, predicates) =
+ type_scheme_and_predicates_for_def(fcx, expr.span, def);
+ instantiate_path(fcx, &path.segments,
+ scheme, &predicates,
+ None, def, expr.span, id);
+ } else if let Some(partial) = get_partial_def() {
+ let mut def = partial.base_type;
+ let ty_segments = path.segments.init();
+ let ty_assoc_num = partial.extra_associated_types as usize;
+ let base_ty_end = ty_segments.len() - ty_assoc_num;
+ let ty = astconv::finish_resolving_def_to_ty(fcx, fcx, expr.span,
+ PathParamMode::Optional,
+ &mut def,
+ opt_self_ty,
+ &ty_segments[..base_ty_end],
+ &ty_segments[base_ty_end..]);
+ let method_segment = path.segments.last().unwrap();
+ let method_name = method_segment.identifier.name;
+ match method::resolve_ufcs(fcx, expr.span, method_name, ty, id) {
+ Ok(def) => {
+ // Write back the new resolution.
+ tcx.def_map.borrow_mut().insert(id, def);
+
+ let (scheme, predicates) =
+ type_scheme_and_predicates_for_def(fcx, expr.span, def);
+ instantiate_path(fcx, slice::ref_slice(method_segment),
+ scheme, &predicates,
+ Some(ty), def, expr.span, id);
+ }
+ Err(error) => {
+ method::report_error(fcx, expr.span, ty,
+ method_name, expr, error);
+ fcx.write_error(id);
+ }
+ }
+ } else {
+ tcx.sess.span_bug(expr.span,
+ &format!("unbound path {}", expr.repr(tcx))[])
+ }
// We always require that the type provided as the value for
// a type parameter outlives the moment of instantiation.
def::DefForeignMod(..) |
def::DefUse(..) |
def::DefRegion(..) |
- def::DefTyParamBinder(..) |
def::DefLabel(..) |
def::DefSelfTy(..) => {
fcx.ccx.tcx.sess.span_bug(sp, &format!("expected value, found {:?}", defn));
// Instantiates the given path, which must refer to an item with the given
// number of type parameters and type.
pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
- path: &ast::Path,
+ segments: &[ast::PathSegment],
type_scheme: TypeScheme<'tcx>,
type_predicates: &ty::GenericPredicates<'tcx>,
opt_self_ty: Option<Ty<'tcx>>,
def: def::Def,
span: Span,
node_id: ast::NodeId) {
- debug!("instantiate_path(path={}, def={}, node_id={}, type_scheme={})",
- path.repr(fcx.tcx()),
+ debug!("instantiate_path(path={:?}, def={}, node_id={}, type_scheme={})",
+ segments,
def.repr(fcx.tcx()),
node_id,
type_scheme.repr(fcx.tcx()));
//
// The first step then is to categorize the segments appropriately.
- assert!(path.segments.len() >= 1);
+ assert!(segments.len() >= 1);
+
+ // In `<T as Trait<A, B>>::method`, `A` and `B` are mandatory.
+ let mut require_type_space = opt_self_ty.is_some();
+
let mut segment_spaces: Vec<_>;
match def {
// Case 1 and 1b. Reference to a *type* or *enum variant*.
def::DefTyParam(..) => {
// Everything but the final segment should have no
// parameters at all.
- segment_spaces = repeat(None).take(path.segments.len() - 1).collect();
+ segment_spaces = repeat(None).take(segments.len() - 1).collect();
segment_spaces.push(Some(subst::TypeSpace));
}
def::DefFn(..) |
def::DefConst(..) |
def::DefStatic(..) => {
- segment_spaces = repeat(None).take(path.segments.len() - 1).collect();
+ segment_spaces = repeat(None).take(segments.len() - 1).collect();
segment_spaces.push(Some(subst::FnSpace));
}
// Case 3. Reference to a method.
def::DefMethod(_, providence) => {
- assert!(path.segments.len() >= 2);
-
match providence {
def::FromTrait(trait_did) => {
callee::check_legal_trait_for_method_call(fcx.ccx, span, trait_did)
def::FromImpl(_) => {}
}
- segment_spaces = repeat(None).take(path.segments.len() - 2).collect();
- segment_spaces.push(Some(subst::TypeSpace));
- segment_spaces.push(Some(subst::FnSpace));
+ if segments.len() >= 2 {
+ segment_spaces = repeat(None).take(segments.len() - 2).collect();
+ segment_spaces.push(Some(subst::TypeSpace));
+ segment_spaces.push(Some(subst::FnSpace));
+ } else {
+ // `<T>::method` will end up here, and so can `T::method`.
+ assert!(opt_self_ty.is_some());
+ require_type_space = false;
+ segment_spaces = vec![Some(subst::FnSpace)];
+ }
}
// Other cases. Various nonsense that really shouldn't show up
def::DefRegion(..) |
def::DefLabel(..) |
def::DefUpvar(..) => {
- segment_spaces = repeat(None).take(path.segments.len()).collect();
+ segment_spaces = repeat(None).take(segments.len()).collect();
}
}
- assert_eq!(segment_spaces.len(), path.segments.len());
+ assert_eq!(segment_spaces.len(), segments.len());
debug!("segment_spaces={:?}", segment_spaces);
// provided (if any) into their appropriate spaces. We'll also report
// errors if type parameters are provided in an inappropriate place.
let mut substs = Substs::empty();
- for (opt_space, segment) in segment_spaces.iter().zip(path.segments.iter()) {
+ for (opt_space, segment) in segment_spaces.iter().zip(segments.iter()) {
match *opt_space {
None => {
- report_error_if_segment_contains_type_parameters(fcx, segment);
+ check_path_args(fcx.tcx(), slice::ref_slice(segment),
+ NO_TPS | NO_REGIONS);
}
Some(space) => {
push_explicit_parameters_from_segment_to_substs(fcx,
space,
- path.span,
+ span,
type_defs,
region_defs,
segment,
// a problem.
for &space in &ParamSpace::all() {
adjust_type_parameters(fcx, span, space, type_defs,
- opt_self_ty.is_some(), &mut substs);
+ require_type_space, &mut substs);
assert_eq!(substs.types.len(space), type_defs.len(space));
adjust_region_parameters(fcx, span, space, region_defs, &mut substs);
fcx.write_substs(node_id, ty::ItemSubsts { substs: substs });
return;
- fn report_error_if_segment_contains_type_parameters(
- fcx: &FnCtxt,
- segment: &ast::PathSegment)
- {
- for typ in &segment.parameters.types() {
- span_err!(fcx.tcx().sess, typ.span, E0085,
- "type parameters may not appear here");
- break;
- }
-
- for lifetime in &segment.parameters.lifetimes() {
- span_err!(fcx.tcx().sess, lifetime.span, E0086,
- "lifetime parameters may not appear here");
- break;
- }
- }
-
/// Finds the parameters that the user provided and adds them to `substs`. If too many
/// parameters are provided, then reports an error and clears the output vector.
///
-> bool
{
match ast_ty.node {
- ast::TyPath(_, id) => {
- match ccx.tcx.def_map.borrow()[id] {
+ ast::TyPath(_) => {
+ match ccx.tcx.def_map.borrow()[ast_ty.id] {
def::DefTyParam(s, i, _, _) => {
space == s && index == i
}
fn main() {
let p = Point::new(0.0, 0.0);
- //~^ ERROR unresolved name `Point::new`
- //~^^ ERROR failed to resolve. Use of undeclared type or module `Point`
println!("{}", p.to_string());
}
// , (vec![b'f', b'o', b'o'], u8_as_i8);
// Trait static methods.
+ bool::size, fn() -> uint, ();
<bool as Size>::size, fn() -> uint, ();
+
Default::default, fn() -> int, ();
+ int::default, fn() -> int, ();
<int as Default>::default, fn() -> int, ();
+
Rand::rand, fn(&mut DummyRng) -> int, (&mut dummy_rng());
+ int::rand, fn(&mut DummyRng) -> int, (&mut dummy_rng());
<int as Rand>::rand, fn(&mut DummyRng) -> int, (&mut dummy_rng());
Rand::rand::<DummyRng>, fn(&mut DummyRng) -> int, (&mut dummy_rng());
+ int::rand::<DummyRng>, fn(&mut DummyRng) -> int, (&mut dummy_rng());
<int as Rand>::rand::<DummyRng>, fn(&mut DummyRng) -> int, (&mut dummy_rng());
// Trait non-static methods.
Clone::clone, fn(&int) -> int, (&5);
+ int::clone, fn(&int) -> int, (&5);
<int as Clone>::clone, fn(&int) -> int, (&5);
+
FromIterator::from_iter, fn(OptionIter<int>) -> Vec<int>, (Some(5).into_iter());
+ Vec::from_iter, fn(OptionIter<int>) -> Vec<int>, (Some(5).into_iter());
<Vec<_> as FromIterator<_>>::from_iter, fn(OptionIter<int>) -> Vec<int>,
(Some(5).into_iter());
<Vec<int> as FromIterator<_>>::from_iter, fn(OptionIter<int>) -> Vec<int>,
(Some(5).into_iter());
<Vec<int> as FromIterator<_>>::from_iter::<OptionIter<int>>, fn(OptionIter<int>) -> Vec<int>,
(Some(5).into_iter());
+
Add::add, fn(i32, i32) -> i32, (5, 6);
+ i32::add, fn(i32, i32) -> i32, (5, 6);
<i32 as Add<_>>::add, fn(i32, i32) -> i32, (5, 6);
<i32 as Add<i32>>::add, fn(i32, i32) -> i32, (5, 6);
+
+ String::into_cow, fn(String) -> Cow<'static, str>,
+ ("foo".to_string());
<String as IntoCow<_>>::into_cow, fn(String) -> Cow<'static, str>,
("foo".to_string());
<String as IntoCow<'static, _>>::into_cow, fn(String) -> Cow<'static, str>,