提交 fe4f9b8e 编写于 作者: E Eduard Burtescu

Use partial path resolutions in expressions for UFCS desugaring.

上级 7a3054f5
......@@ -17,37 +17,36 @@
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,
......@@ -69,7 +68,7 @@ pub fn ast_ty_to_prim_ty<'tcx>(tcx: &ty::ctxt<'tcx>, ast_ty: &ast::Ty)
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
}
......
......@@ -3018,7 +3018,7 @@ fn resolve_trait_reference(&mut self,
}
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 {
......@@ -4083,16 +4083,35 @@ fn resolve_expr(&mut self, expr: &Expr) {
// 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 \
......@@ -4110,6 +4129,14 @@ fn resolve_expr(&mut self, expr: &Expr) {
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 => {
......@@ -4135,6 +4162,9 @@ fn resolve_expr(&mut self, expr: &Expr) {
}
_ => {
// 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 {
......
......@@ -246,6 +246,7 @@ pub fn ast_path_substs_for_ty<'tcx>(
this: &AstConv<'tcx>,
rscope: &RegionScope,
span: Span,
param_mode: PathParamMode,
decl_generics: &ty::Generics<'tcx>,
item_segment: &ast::PathSegment)
-> Substs<'tcx>
......@@ -265,12 +266,12 @@ pub fn ast_path_substs_for_ty<'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)
}
};
......@@ -278,12 +279,21 @@ pub fn ast_path_substs_for_ty<'tcx>(
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,
......@@ -331,6 +341,7 @@ fn create_region_substs<'tcx>(
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>>,
......@@ -349,13 +360,21 @@ fn create_substs_for_ast_path<'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);
......@@ -415,7 +434,7 @@ fn create_substs_for_ast_path<'tcx>(
}
}
return substs;
substs
}
struct ConvertedBinding<'tcx> {
......@@ -607,6 +626,7 @@ pub fn instantiate_trait_ref<'tcx>(
let trait_ref = ast_path_to_trait_ref(this,
rscope,
path.span,
PathParamMode::Explicit,
trait_def_id,
self_ty,
path.segments.last().unwrap(),
......@@ -627,6 +647,7 @@ fn object_path_to_poly_trait_ref<'a,'tcx>(
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>>)
......@@ -640,6 +661,7 @@ fn object_path_to_poly_trait_ref<'a,'tcx>(
let trait_ref = ty::Binder(ast_path_to_trait_ref(this,
&shifted_rscope,
span,
param_mode,
trait_def_id,
None,
trait_segment,
......@@ -652,6 +674,7 @@ fn ast_path_to_trait_ref<'a,'tcx>(
this: &AstConv<'tcx>,
rscope: &RegionScope,
span: Span,
param_mode: PathParamMode,
trait_def_id: ast::DefId,
self_ty: Option<Ty<'tcx>>,
trait_segment: &ast::PathSegment,
......@@ -674,7 +697,7 @@ fn ast_path_to_trait_ref<'a,'tcx>(
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
......@@ -688,12 +711,13 @@ fn ast_path_to_trait_ref<'a,'tcx>(
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,
......@@ -830,6 +854,7 @@ fn ast_path_to_ty<'tcx>(
this: &AstConv<'tcx>,
rscope: &RegionScope,
span: Span,
param_mode: PathParamMode,
did: ast::DefId,
item_segment: &ast::PathSegment)
-> Ty<'tcx>
......@@ -839,7 +864,9 @@ fn ast_path_to_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() {
......@@ -878,6 +905,7 @@ fn ast_ty_to_trait_ref<'tcx>(this: &AstConv<'tcx>,
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);
......@@ -950,8 +978,7 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>,
-> (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 {
......@@ -1043,7 +1070,8 @@ fn trait_defines_associated_type_named(this: &AstConv,
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)
......@@ -1051,11 +1079,10 @@ fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>,
{
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,
......@@ -1070,6 +1097,7 @@ fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>,
let trait_ref = ast_path_to_trait_ref(this,
rscope,
span,
param_mode,
trait_def_id,
Some(self_ty),
trait_segment,
......@@ -1113,6 +1141,88 @@ pub fn ast_ty_arg_to_ty<'tcx>(this: &AstConv<'tcx>,
}
}
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>,
......@@ -1201,81 +1311,18 @@ 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.
......
......@@ -470,7 +470,7 @@ pub fn check_pat_struct<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &'tcx ast::Pat,
};
instantiate_path(pcx.fcx,
path,
&path.segments,
ty::lookup_item_type(tcx, enum_def_id),
&ty::lookup_predicates(tcx, enum_def_id),
None,
......@@ -517,7 +517,9 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
} 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);
......
......@@ -14,6 +14,7 @@
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::*;
......@@ -66,7 +67,8 @@ pub fn exists<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
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,
......@@ -103,8 +105,9 @@ pub fn lookup<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
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))
}
......@@ -301,6 +304,23 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
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).
......
......@@ -37,6 +37,7 @@
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>>,
......@@ -108,17 +109,30 @@ pub enum PickAdjustment {
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
......@@ -127,9 +141,16 @@ pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
// 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.
......@@ -153,12 +174,15 @@ pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
// 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()
})
}
......@@ -198,6 +222,7 @@ fn create_steps<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
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>>)
......@@ -206,6 +231,7 @@ fn new(fcx: &'a FnCtxt<'a,'tcx>,
ProbeContext {
fcx: fcx,
span: span,
mode: mode,
method_name: method_name,
inherent_candidates: Vec::new(),
extension_candidates: Vec::new(),
......@@ -292,11 +318,12 @@ fn assemble_inherent_impl_probe(&mut self, impl_def_id: ast::DefId) {
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,
......@@ -330,7 +357,9 @@ fn assemble_inherent_candidates_from_object(&mut self,
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,
......@@ -373,7 +402,9 @@ fn assemble_inherent_candidates_from_param(&mut self,
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()),
......@@ -540,7 +571,7 @@ fn assemble_extension_candidates_for_trait_impls(&mut self,
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()));
......@@ -553,7 +584,9 @@ fn assemble_extension_candidates_for_trait_impls(&mut self,
// 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()));
......@@ -630,7 +663,9 @@ fn assemble_closure_candidates(&mut self,
&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(),
......@@ -684,7 +719,9 @@ fn assemble_projection_candidates(&mut self,
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()),
......@@ -714,7 +751,9 @@ fn assemble_where_clause_candidates(&mut self,
.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()),
......@@ -1023,7 +1062,9 @@ fn has_applicable_self(&self, method: &ty::Method) -> bool {
// "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(..) |
......@@ -1047,11 +1088,13 @@ fn record_static_candidate(&mut self, source: CandidateSource) {
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());
......@@ -1063,6 +1106,11 @@ fn xform_self_ty(&self,
// 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
......@@ -1094,9 +1142,10 @@ fn xform_self_ty(&self,
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);
......@@ -1108,7 +1157,8 @@ fn impl_substs(&self,
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
......
......@@ -82,9 +82,10 @@
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;
......@@ -1598,26 +1599,11 @@ fn instantiate_struct_literal_ty(&self,
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);
......@@ -3604,21 +3590,57 @@ fn check_struct_fields_on_error<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
};
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.
......@@ -4641,7 +4663,6 @@ fn type_scheme_and_predicates_for_def<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
def::DefForeignMod(..) |
def::DefUse(..) |
def::DefRegion(..) |
def::DefTyParamBinder(..) |
def::DefLabel(..) |
def::DefSelfTy(..) => {
fcx.ccx.tcx.sess.span_bug(sp, &format!("expected value, found {:?}", defn));
......@@ -4652,15 +4673,15 @@ fn type_scheme_and_predicates_for_def<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
// 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()));
......@@ -4724,7 +4745,11 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, '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*.
......@@ -4738,7 +4763,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
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));
}
......@@ -4746,14 +4771,12 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
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)
......@@ -4761,9 +4784,16 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
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
......@@ -4776,10 +4806,10 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
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);
......@@ -4793,16 +4823,17 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
// 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,
......@@ -4824,7 +4855,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
// 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);
......@@ -4851,23 +4882,6 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
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.
///
......
......@@ -1684,8 +1684,8 @@ fn is_param(ccx: &CollectCtxt,
-> 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
}
......
......@@ -30,7 +30,5 @@ fn to_string(&self) -> String {
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());
}
......@@ -77,18 +77,27 @@ impl<T> Size for T {}
// , (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>,
......@@ -97,9 +106,14 @@ impl<T> Size for T {}
(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>,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册