diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 088fd8d90901c..1755b3bca0572 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -627,7 +627,9 @@ pub fn walk_path_segment<'v, V: Visitor<'v>>(visitor: &mut V, path_span: Span, segment: &'v PathSegment) { visitor.visit_name(path_span, segment.name); - visitor.visit_path_parameters(path_span, &segment.parameters); + if let Some(ref parameters) = segment.parameters { + visitor.visit_path_parameters(path_span, parameters); + } } pub fn walk_path_parameters<'v, V: Visitor<'v>>(visitor: &mut V, diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 8208eb896d669..95b8e49d60c6a 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -690,10 +690,9 @@ impl<'a> LoweringContext<'a> { TyKind::ImplicitSelf => { hir::TyPath(hir::QPath::Resolved(None, P(hir::Path { def: self.expect_full_def(t.id), - segments: hir_vec![hir::PathSegment { - name: keywords::SelfType.name(), - parameters: hir::PathParameters::none() - }], + segments: hir_vec![ + hir::PathSegment::from_name(keywords::SelfType.name()) + ], span: t.span, }))) } @@ -914,12 +913,8 @@ impl<'a> LoweringContext<'a> { segments: segments.map(|segment| { self.lower_path_segment(p.span, segment, param_mode, 0, ParenthesizedGenericArgs::Err) - }).chain(name.map(|name| { - hir::PathSegment { - name, - parameters: hir::PathParameters::none() - } - })).collect(), + }).chain(name.map(|name| hir::PathSegment::from_name(name))) + .collect(), span: p.span, } } @@ -940,7 +935,7 @@ impl<'a> LoweringContext<'a> { expected_lifetimes: usize, parenthesized_generic_args: ParenthesizedGenericArgs) -> hir::PathSegment { - let mut parameters = if let Some(ref parameters) = segment.parameters { + let (mut parameters, infer_types) = if let Some(ref parameters) = segment.parameters { let msg = "parenthesized parameters may only be used with a trait"; match **parameters { PathParameters::AngleBracketed(ref data) => { @@ -951,12 +946,12 @@ impl<'a> LoweringContext<'a> { ParenthesizedGenericArgs::Warn => { self.sess.buffer_lint(PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES, CRATE_NODE_ID, data.span, msg.into()); - hir::PathParameters::none() + (hir::PathParameters::none(), true) } ParenthesizedGenericArgs::Err => { struct_span_err!(self.sess, data.span, E0214, "{}", msg) .span_label(data.span, "only traits may use parentheses").emit(); - hir::PathParameters::none() + (hir::PathParameters::none(), true) } } } @@ -970,29 +965,29 @@ impl<'a> LoweringContext<'a> { }).collect(); } - hir::PathSegment { - name: self.lower_ident(segment.identifier), + hir::PathSegment::new( + self.lower_ident(segment.identifier), parameters, - } + infer_types + ) } fn lower_angle_bracketed_parameter_data(&mut self, data: &AngleBracketedParameterData, param_mode: ParamMode) - -> hir::PathParameters { + -> (hir::PathParameters, bool) { let &AngleBracketedParameterData { ref lifetimes, ref types, ref bindings, .. } = data; - hir::PathParameters { + (hir::PathParameters { lifetimes: self.lower_lifetimes(lifetimes), types: types.iter().map(|ty| self.lower_ty(ty)).collect(), - infer_types: types.is_empty() && param_mode == ParamMode::Optional, bindings: bindings.iter().map(|b| self.lower_ty_binding(b)).collect(), parenthesized: false, - } + }, types.is_empty() && param_mode == ParamMode::Optional) } fn lower_parenthesized_parameter_data(&mut self, data: &ParenthesizedParameterData) - -> hir::PathParameters { + -> (hir::PathParameters, bool) { let &ParenthesizedParameterData { ref inputs, ref output, span } = data; let inputs = inputs.iter().map(|ty| self.lower_ty(ty)).collect(); let mk_tup = |this: &mut Self, tys, span| { @@ -1000,10 +995,9 @@ impl<'a> LoweringContext<'a> { P(hir::Ty { node: hir::TyTup(tys), id: node_id, hir_id, span }) }; - hir::PathParameters { + (hir::PathParameters { lifetimes: hir::HirVec::new(), types: hir_vec![mk_tup(self, inputs, span)], - infer_types: false, bindings: hir_vec![hir::TypeBinding { id: self.next_id().node_id, name: Symbol::intern(FN_OUTPUT_NAME), @@ -1012,7 +1006,7 @@ impl<'a> LoweringContext<'a> { span: output.as_ref().map_or(span, |ty| ty.span), }], parenthesized: true, - } + }, false) } fn lower_local(&mut self, l: &Local) -> P { diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index e96edaa86d2a2..bff71155440a3 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -236,7 +236,13 @@ pub struct PathSegment { /// this is more than just simple syntactic sugar; the use of /// parens affects the region binding rules, so we preserve the /// distinction. - pub parameters: PathParameters, + pub parameters: Option>, + + /// Whether to infer remaining type parameters, if any. + /// This only applies to expression and pattern paths, and + /// out of those only the segments with no type parameters + /// to begin with, e.g. `Vec::new` is `>::new::<..>`. + pub infer_types: bool, } impl PathSegment { @@ -244,9 +250,35 @@ impl PathSegment { pub fn from_name(name: Name) -> PathSegment { PathSegment { name, - parameters: PathParameters::none() + infer_types: true, + parameters: None + } + } + + pub fn new(name: Name, parameters: PathParameters, infer_types: bool) -> Self { + PathSegment { + name, + infer_types, + parameters: if parameters.is_empty() { + None + } else { + Some(P(parameters)) + } } } + + // FIXME: hack required because you can't create a static + // PathParameters, so you can't just return a &PathParameters. + pub fn with_parameters(&self, f: F) -> R + where F: FnOnce(&PathParameters) -> R + { + let dummy = PathParameters::none(); + f(if let Some(ref params) = self.parameters { + ¶ms + } else { + &dummy + }) + } } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] @@ -255,11 +287,6 @@ pub struct PathParameters { pub lifetimes: HirVec, /// The type parameters for this path segment, if present. pub types: HirVec>, - /// Whether to infer remaining type parameters, if any. - /// This only applies to expression and pattern paths, and - /// out of those only the segments with no type parameters - /// to begin with, e.g. `Vec::new` is `>::new::<..>`. - pub infer_types: bool, /// Bindings (equality constraints) on associated types, if present. /// E.g., `Foo`. pub bindings: HirVec, @@ -274,12 +301,16 @@ impl PathParameters { Self { lifetimes: HirVec::new(), types: HirVec::new(), - infer_types: true, bindings: HirVec::new(), parenthesized: false, } } + pub fn is_empty(&self) -> bool { + self.lifetimes.is_empty() && self.types.is_empty() && + self.bindings.is_empty() && !self.parenthesized + } + pub fn inputs(&self) -> &[P] { if self.parenthesized { if let Some(ref ty) = self.types.get(0) { diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index ad31b2009a01d..5daffe667fde5 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -1213,11 +1213,17 @@ impl<'a> State<'a> { self.print_expr_maybe_paren(&args[0], parser::PREC_POSTFIX)?; self.s.word(".")?; self.print_name(segment.name)?; - if !segment.parameters.lifetimes.is_empty() || - !segment.parameters.types.is_empty() || - !segment.parameters.bindings.is_empty() { - self.print_path_parameters(&segment.parameters, true)?; - } + + segment.with_parameters(|parameters| { + if !parameters.lifetimes.is_empty() || + !parameters.types.is_empty() || + !parameters.bindings.is_empty() + { + self.print_path_parameters(¶meters, segment.infer_types, true) + } else { + Ok(()) + } + })?; self.print_call_post(base_args) } @@ -1564,8 +1570,12 @@ impl<'a> State<'a> { } if segment.name != keywords::CrateRoot.name() && segment.name != keywords::DollarCrate.name() { - self.print_name(segment.name)?; - self.print_path_parameters(&segment.parameters, colons_before_params)?; + self.print_name(segment.name)?; + segment.with_parameters(|parameters| { + self.print_path_parameters(parameters, + segment.infer_types, + colons_before_params) + })?; } } @@ -1593,7 +1603,11 @@ impl<'a> State<'a> { if segment.name != keywords::CrateRoot.name() && segment.name != keywords::DollarCrate.name() { self.print_name(segment.name)?; - self.print_path_parameters(&segment.parameters, colons_before_params)?; + segment.with_parameters(|parameters| { + self.print_path_parameters(parameters, + segment.infer_types, + colons_before_params) + })?; } } @@ -1601,7 +1615,11 @@ impl<'a> State<'a> { self.s.word("::")?; let item_segment = path.segments.last().unwrap(); self.print_name(item_segment.name)?; - self.print_path_parameters(&item_segment.parameters, colons_before_params) + item_segment.with_parameters(|parameters| { + self.print_path_parameters(parameters, + item_segment.infer_types, + colons_before_params) + }) } hir::QPath::TypeRelative(ref qself, ref item_segment) => { self.s.word("<")?; @@ -1609,13 +1627,18 @@ impl<'a> State<'a> { self.s.word(">")?; self.s.word("::")?; self.print_name(item_segment.name)?; - self.print_path_parameters(&item_segment.parameters, colons_before_params) + item_segment.with_parameters(|parameters| { + self.print_path_parameters(parameters, + item_segment.infer_types, + colons_before_params) + }) } } } fn print_path_parameters(&mut self, parameters: &hir::PathParameters, + infer_types: bool, colons_before_params: bool) -> io::Result<()> { if parameters.parenthesized { @@ -1652,7 +1675,7 @@ impl<'a> State<'a> { // FIXME(eddyb) This would leak into error messages, e.g.: // "non-exhaustive patterns: `Some::<..>(_)` not covered". - if parameters.infer_types && false { + if infer_types && false { start_or_comma(self)?; self.s.word("..")?; } diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index bc0c52575ae15..96d5940caf6a4 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -150,13 +150,13 @@ impl_stable_hash_for!(struct hir::Path { impl_stable_hash_for!(struct hir::PathSegment { name, + infer_types, parameters }); impl_stable_hash_for!(struct hir::PathParameters { lifetimes, types, - infer_types, bindings, parenthesized }); diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 60f03eb5d89ec..d0c5460fa9714 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -445,7 +445,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { fn visit_path(&mut self, path: &'tcx hir::Path, _: ast::NodeId) { for (i, segment) in path.segments.iter().enumerate() { let depth = path.segments.len() - i - 1; - self.visit_segment_parameters(path.def, depth, &segment.parameters); + if let Some(ref parameters) = segment.parameters { + self.visit_segment_parameters(path.def, depth, parameters); + } } } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 3171bd41f92dc..54fd070e93cbc 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -157,11 +157,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { item_segment: &hir::PathSegment) -> &'tcx Substs<'tcx> { + let (substs, assoc_bindings) = - self.create_substs_for_ast_path(span, - def_id, - &item_segment.parameters, - None); + item_segment.with_parameters(|parameters| { + self.create_substs_for_ast_path( + span, + def_id, + parameters, + item_segment.infer_types, + None) + }); assoc_bindings.first().map(|b| self.prohibit_projection(b.span)); @@ -177,6 +182,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { span: Span, def_id: DefId, parameters: &hir::PathParameters, + infer_types: bool, self_ty: Option>) -> (&'tcx Substs<'tcx>, Vec>) { @@ -204,7 +210,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // Check the number of type parameters supplied by the user. let ty_param_defs = &decl_generics.types[self_ty.is_some() as usize..]; - if !parameters.infer_types || num_types_provided > ty_param_defs.len() { + if !infer_types || num_types_provided > ty_param_defs.len() { check_type_argument_count(tcx, span, num_types_provided, ty_param_defs); } @@ -240,7 +246,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { if i < num_types_provided { // A provided type parameter. self.ast_ty_to_ty(¶meters.types[i]) - } else if parameters.infer_types { + } else if infer_types { // No type parameters were provided, we can infer all. let ty_var = if !default_needs_object_self(def) { self.ty_infer_for_def(def, substs, span) @@ -390,7 +396,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let trait_def = self.tcx().trait_def(trait_def_id); if !self.tcx().sess.features.borrow().unboxed_closures && - trait_segment.parameters.parenthesized != trait_def.paren_sugar { + trait_segment.with_parameters(|p| p.parenthesized) != trait_def.paren_sugar { // For now, require that parenthetical notation be used only with `Fn()` etc. let msg = if trait_def.paren_sugar { "the precise format of `Fn`-family traits' type parameters is subject to change. \ @@ -402,10 +408,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { span, GateIssue::Language, msg); } - self.create_substs_for_ast_path(span, - trait_def_id, - &trait_segment.parameters, - Some(self_ty)) + trait_segment.with_parameters(|parameters| { + self.create_substs_for_ast_path(span, + trait_def_id, + parameters, + trait_segment.infer_types, + Some(self_ty)) + }) } fn trait_defines_associated_type_named(&self, @@ -876,25 +885,27 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { pub fn prohibit_type_params(&self, segments: &[hir::PathSegment]) { for segment in segments { - for typ in &segment.parameters.types { - struct_span_err!(self.tcx().sess, typ.span, E0109, - "type parameters are not allowed on this type") - .span_label(typ.span, "type parameter not allowed") - .emit(); - break; - } - for lifetime in &segment.parameters.lifetimes { - struct_span_err!(self.tcx().sess, lifetime.span, E0110, - "lifetime parameters are not allowed on this type") - .span_label(lifetime.span, - "lifetime parameter not allowed on this type") - .emit(); - break; - } - for binding in &segment.parameters.bindings { - self.prohibit_projection(binding.span); - break; - } + segment.with_parameters(|parameters| { + for typ in ¶meters.types { + struct_span_err!(self.tcx().sess, typ.span, E0109, + "type parameters are not allowed on this type") + .span_label(typ.span, "type parameter not allowed") + .emit(); + break; + } + for lifetime in ¶meters.lifetimes { + struct_span_err!(self.tcx().sess, lifetime.span, E0110, + "lifetime parameters are not allowed on this type") + .span_label(lifetime.span, + "lifetime parameter not allowed on this type") + .emit(); + break; + } + for binding in ¶meters.bindings { + self.prohibit_projection(binding.span); + break; + } + }) } } @@ -978,12 +989,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } Def::Err => { for segment in &path.segments { - for ty in &segment.parameters.types { - self.ast_ty_to_ty(ty); - } - for binding in &segment.parameters.bindings { - self.ast_ty_to_ty(&binding.ty); - } + segment.with_parameters(|parameters| { + for ty in ¶meters.types { + self.ast_ty_to_ty(ty); + } + for binding in ¶meters.bindings { + self.ast_ty_to_ty(&binding.ty); + } + }); } self.set_tainted_by_errors(); return self.tcx().types.err; @@ -1314,15 +1327,16 @@ fn split_auto_traits<'a, 'b, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, if Some(trait_did) == tcx.lang_items().send_trait() || Some(trait_did) == tcx.lang_items().sync_trait() { let segments = &bound.trait_ref.path.segments; - let parameters = &segments[segments.len() - 1].parameters; - if !parameters.types.is_empty() { - check_type_argument_count(tcx, bound.trait_ref.path.span, - parameters.types.len(), &[]); - } - if !parameters.lifetimes.is_empty() { - report_lifetime_number_error(tcx, bound.trait_ref.path.span, - parameters.lifetimes.len(), 0); - } + segments[segments.len() - 1].with_parameters(|parameters| { + if !parameters.types.is_empty() { + check_type_argument_count(tcx, bound.trait_ref.path.span, + parameters.types.len(), &[]); + } + if !parameters.lifetimes.is_empty() { + report_lifetime_number_error(tcx, bound.trait_ref.path.span, + parameters.lifetimes.len(), 0); + } + }); true } else { false diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 852134bbee315..a9830dd5ddece 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -300,7 +300,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { if i < parent_substs.len() { parent_substs.region_at(i) } else if let Some(lifetime) - = provided.lifetimes.get(i - parent_substs.len()) { + = provided.as_ref().and_then(|p| p.lifetimes.get(i - parent_substs.len())) { AstConv::ast_region_to_region(self.fcx, lifetime, Some(def)) } else { self.region_var_for_def(self.span, def) @@ -310,7 +310,10 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { if i < parent_substs.len() { parent_substs.type_at(i) } else if let Some(ast_ty) - = provided.types.get(i - parent_substs.len() - method_generics.regions.len()) { + = provided.as_ref().and_then(|p| { + p.types.get(i - parent_substs.len() - method_generics.regions.len()) + }) + { self.to_ty(ast_ty) } else { self.type_var_for_def(self.span, def, cur_substs) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index edbdfc1a7d4bc..38558f50f6e16 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4668,7 +4668,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { i -= fn_start; fn_segment }; - let lifetimes = segment.map_or(&[][..], |(s, _)| &s.parameters.lifetimes[..]); + let lifetimes = segment.map_or(&[][..], |(s, _)| { + s.parameters.as_ref().map_or(&[][..], |p| &p.lifetimes[..]) + }); if let Some(lifetime) = lifetimes.get(i) { AstConv::ast_region_to_region(self, lifetime, Some(def)) @@ -4692,7 +4694,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn_segment }; let (types, infer_types) = segment.map_or((&[][..], true), |(s, _)| { - (&s.parameters.types[..], s.parameters.infer_types) + (s.parameters.as_ref().map_or(&[][..], |p| &p.types[..]), s.infer_types) }); // Skip over the lifetimes in the same segment. @@ -4769,8 +4771,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { is_method_call: bool) { let (lifetimes, types, infer_types, bindings) = segment.map_or( (&[][..], &[][..], true, &[][..]), - |(s, _)| (&s.parameters.lifetimes[..], &s.parameters.types[..], - s.parameters.infer_types, &s.parameters.bindings[..])); + |(s, _)| s.parameters.as_ref().map_or( + (&[][..], &[][..], s.infer_types, &[][..]), + |p| (&p.lifetimes[..], &p.types[..], + s.infer_types, &p.bindings[..]))); let infer_lifetimes = lifetimes.len() == 0; let count_lifetime_params = |n| { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 1e25a57b1d2b1..c9afa3646b2da 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1852,25 +1852,27 @@ impl Clean for hir::Ty { }; if let Some(&hir::ItemTy(ref ty, ref generics)) = alias { - let provided_params = &path.segments.last().unwrap().parameters; + let provided_params = &path.segments.last().unwrap(); let mut ty_substs = FxHashMap(); let mut lt_substs = FxHashMap(); - for (i, ty_param) in generics.ty_params.iter().enumerate() { - let ty_param_def = Def::TyParam(cx.tcx.hir.local_def_id(ty_param.id)); - if let Some(ty) = provided_params.types.get(i).cloned() { - ty_substs.insert(ty_param_def, ty.unwrap().clean(cx)); - } else if let Some(default) = ty_param.default.clone() { - ty_substs.insert(ty_param_def, default.unwrap().clean(cx)); + provided_params.with_parameters(|provided_params| { + for (i, ty_param) in generics.ty_params.iter().enumerate() { + let ty_param_def = Def::TyParam(cx.tcx.hir.local_def_id(ty_param.id)); + if let Some(ty) = provided_params.types.get(i).cloned() { + ty_substs.insert(ty_param_def, ty.unwrap().clean(cx)); + } else if let Some(default) = ty_param.default.clone() { + ty_substs.insert(ty_param_def, default.unwrap().clean(cx)); + } } - } - for (i, lt_param) in generics.lifetimes.iter().enumerate() { - if let Some(lt) = provided_params.lifetimes.get(i).cloned() { - if !lt.is_elided() { - let lt_def_id = cx.tcx.hir.local_def_id(lt_param.lifetime.id); - lt_substs.insert(lt_def_id, lt.clean(cx)); + for (i, lt_param) in generics.lifetimes.iter().enumerate() { + if let Some(lt) = provided_params.lifetimes.get(i).cloned() { + if !lt.is_elided() { + let lt_def_id = cx.tcx.hir.local_def_id(lt_param.lifetime.id); + lt_substs.insert(lt_def_id, lt.clean(cx)); + } } } - } + }); return cx.enter_alias(ty_substs, lt_substs, || ty.clean(cx)); } resolve_type(cx, path.clean(cx), self.id) @@ -2419,7 +2421,7 @@ impl Clean for hir::PathSegment { fn clean(&self, cx: &DocContext) -> PathSegment { PathSegment { name: self.name.clean(cx), - params: self.parameters.clean(cx) + params: self.with_parameters(|parameters| parameters.clean(cx)) } } }