diff --git a/src/librustc/middle/astconv_util.rs b/src/librustc/middle/astconv_util.rs index 621a231ed7d18..1cd5a19d6788a 100644 --- a/src/librustc/middle/astconv_util.rs +++ b/src/librustc/middle/astconv_util.rs @@ -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 } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index b85ac04cc9e23..0c5236101cfb8 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -3018,7 +3018,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } 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 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // 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 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { 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 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } _ => { + // 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 { diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index bc0986eff1f28..adbc4d546f190 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -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>, types_provided: Vec>, @@ -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>) @@ -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>, 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>, 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>, + 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. diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 34c52981b794d..edbda795bde3c 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -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); diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 256cd415a33af..488d9d53dbe39 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -14,6 +14,7 @@ use astconv::AstConv; 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 +{ + 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). diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 1cc4fe37fbddd..938b7edeef2ff 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -37,6 +37,7 @@ pub use self::PickKind::*; struct ProbeContext<'a, 'tcx:'a> { fcx: &'a FnCtxt<'a, 'tcx>, span: Span, + mode: Mode, method_name: ast::Name, steps: Rc>>, opt_simplified_steps: Option>, @@ -108,17 +109,30 @@ pub enum PickAdjustment { AutoRef(ast::Mutability, Box), } +#[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 `::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>, opt_simplified_steps: Option>) @@ -206,6 +231,7 @@ impl<'a,'tcx> ProbeContext<'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 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { 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 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { 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 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { 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 @@ impl<'a,'tcx> ProbeContext<'a,'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())); @@ -553,7 +584,9 @@ impl<'a,'tcx> ProbeContext<'a,'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())); @@ -630,7 +663,9 @@ impl<'a,'tcx> ProbeContext<'a,'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(), @@ -684,7 +719,9 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { 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 @@ impl<'a,'tcx> ProbeContext<'a,'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()), @@ -1023,7 +1062,9 @@ impl<'a,'tcx> ProbeContext<'a,'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(..) | @@ -1047,11 +1088,13 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { fn xform_self_ty(&self, method: &Rc>, + 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 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { // 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 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { 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 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { 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 diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 4daa9a5d80ab0..7a4fab5e56cf0 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -82,9 +82,10 @@ pub use self::compare_method::compare_impl_method; 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 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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_expr_with_unifier<'a, 'tcx, F>(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>, 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 `>::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 { + // `::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. /// diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 46e1f6f076a7b..976c794735fbb 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1684,8 +1684,8 @@ fn compute_object_lifetime_default<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>, -> 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 } diff --git a/src/test/compile-fail/issue-3973.rs b/src/test/compile-fail/issue-3973.rs index e4f7521c33303..2652fb5dfc2fd 100644 --- a/src/test/compile-fail/issue-3973.rs +++ b/src/test/compile-fail/issue-3973.rs @@ -30,7 +30,5 @@ 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 type or module `Point` println!("{}", p.to_string()); } diff --git a/src/test/run-pass/const-polymorphic-paths.rs b/src/test/run-pass/const-polymorphic-paths.rs index dce12030f7942..23d90c5ee292b 100644 --- a/src/test/run-pass/const-polymorphic-paths.rs +++ b/src/test/run-pass/const-polymorphic-paths.rs @@ -77,18 +77,27 @@ tests! { // , (vec![b'f', b'o', b'o'], u8_as_i8); // Trait static methods. + bool::size, fn() -> uint, (); ::size, fn() -> uint, (); + Default::default, fn() -> int, (); + int::default, fn() -> int, (); ::default, fn() -> int, (); + Rand::rand, fn(&mut DummyRng) -> int, (&mut dummy_rng()); + int::rand, fn(&mut DummyRng) -> int, (&mut dummy_rng()); ::rand, fn(&mut DummyRng) -> int, (&mut dummy_rng()); Rand::rand::, fn(&mut DummyRng) -> int, (&mut dummy_rng()); + int::rand::, fn(&mut DummyRng) -> int, (&mut dummy_rng()); ::rand::, fn(&mut DummyRng) -> int, (&mut dummy_rng()); // Trait non-static methods. Clone::clone, fn(&int) -> int, (&5); + int::clone, fn(&int) -> int, (&5); ::clone, fn(&int) -> int, (&5); + FromIterator::from_iter, fn(OptionIter) -> Vec, (Some(5).into_iter()); + Vec::from_iter, fn(OptionIter) -> Vec, (Some(5).into_iter()); as FromIterator<_>>::from_iter, fn(OptionIter) -> Vec, (Some(5).into_iter()); as FromIterator<_>>::from_iter, fn(OptionIter) -> Vec, @@ -97,9 +106,14 @@ tests! { (Some(5).into_iter()); as FromIterator<_>>::from_iter::>, fn(OptionIter) -> Vec, (Some(5).into_iter()); + Add::add, fn(i32, i32) -> i32, (5, 6); + i32::add, fn(i32, i32) -> i32, (5, 6); >::add, fn(i32, i32) -> i32, (5, 6); >::add, fn(i32, i32) -> i32, (5, 6); + + String::into_cow, fn(String) -> Cow<'static, str>, + ("foo".to_string()); >::into_cow, fn(String) -> Cow<'static, str>, ("foo".to_string()); >::into_cow, fn(String) -> Cow<'static, str>,