Skip to content

Commit 000f87a

Browse files
committed
Desugar parenthesized generic arguments in HIR
1 parent 230a379 commit 000f87a

18 files changed

+264
-438
lines changed

src/librustc/diagnostics.rs

+15
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,21 @@ attributes:
687687
See also https://doc.rust-lang.org/book/first-edition/no-stdlib.html
688688
"##,
689689

690+
E0214: r##"
691+
A generic type was described using parentheses rather than angle brackets. For
692+
example:
693+
694+
```compile_fail,E0214
695+
fn main() {
696+
let v: Vec(&str) = vec!["foo"];
697+
}
698+
```
699+
700+
This is not currently supported: `v` should be defined as `Vec<&str>`.
701+
Parentheses are currently only used with generic types when defining parameters
702+
for `Fn`-family traits.
703+
"##,
704+
690705
E0261: r##"
691706
When using a lifetime like `'a` in a type, it must be declared before being
692707
used.

src/librustc/hir/intravisit.rs

+3-11
Original file line numberDiff line numberDiff line change
@@ -617,17 +617,9 @@ pub fn walk_path_segment<'v, V: Visitor<'v>>(visitor: &mut V,
617617
pub fn walk_path_parameters<'v, V: Visitor<'v>>(visitor: &mut V,
618618
_path_span: Span,
619619
path_parameters: &'v PathParameters) {
620-
match *path_parameters {
621-
AngleBracketedParameters(ref data) => {
622-
walk_list!(visitor, visit_ty, &data.types);
623-
walk_list!(visitor, visit_lifetime, &data.lifetimes);
624-
walk_list!(visitor, visit_assoc_type_binding, &data.bindings);
625-
}
626-
ParenthesizedParameters(ref data) => {
627-
walk_list!(visitor, visit_ty, &data.inputs);
628-
walk_list!(visitor, visit_ty, &data.output);
629-
}
630-
}
620+
walk_list!(visitor, visit_lifetime, &path_parameters.lifetimes);
621+
walk_list!(visitor, visit_ty, &path_parameters.types);
622+
walk_list!(visitor, visit_assoc_type_binding, &path_parameters.bindings);
631623
}
632624

633625
pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(visitor: &mut V,

src/librustc/hir/lowering.rs

+73-25
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,16 @@ use hir::map::{Definitions, DefKey, REGULAR_SPACE};
4545
use hir::map::definitions::DefPathData;
4646
use hir::def_id::{DefIndex, DefId, CRATE_DEF_INDEX};
4747
use hir::def::{Def, PathResolution};
48+
use lint::builtin::PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES;
4849
use rustc_data_structures::indexed_vec::IndexVec;
4950
use session::Session;
51+
use util::common::FN_OUTPUT_NAME;
5052
use util::nodemap::{DefIdMap, FxHashMap, NodeMap};
5153

5254
use std::collections::BTreeMap;
5355
use std::fmt::Debug;
5456
use std::iter;
5557
use std::mem;
56-
5758
use syntax::attr;
5859
use syntax::ast::*;
5960
use syntax::errors;
@@ -160,6 +161,12 @@ struct LoweredNodeId {
160161
hir_id: hir::HirId,
161162
}
162163

164+
enum ParenthesizedGenericArgs {
165+
Ok,
166+
Warn,
167+
Err,
168+
}
169+
163170
impl<'a> LoweringContext<'a> {
164171
fn lower_crate(mut self, c: &Crate) -> hir::Crate {
165172
/// Full-crate AST visitor that inserts into a fresh
@@ -749,6 +756,21 @@ impl<'a> LoweringContext<'a> {
749756
Def::Trait(def_id) if i + 1 == proj_start => Some(def_id),
750757
_ => None
751758
};
759+
let parenthesized_generic_args = match resolution.base_def() {
760+
// `a::b::Trait(Args)`
761+
Def::Trait(..) if i + 1 == proj_start => ParenthesizedGenericArgs::Ok,
762+
// `a::b::Trait(Args)::TraitItem`
763+
Def::Method(..) |
764+
Def::AssociatedConst(..) |
765+
Def::AssociatedTy(..) if i + 2 == proj_start => ParenthesizedGenericArgs::Ok,
766+
// Avoid duplicated errors
767+
Def::Err => ParenthesizedGenericArgs::Ok,
768+
// An error
769+
Def::Struct(..) | Def::Enum(..) | Def::Union(..) | Def::TyAlias(..) |
770+
Def::Variant(..) if i + 1 == proj_start => ParenthesizedGenericArgs::Err,
771+
// A warning for now, for compatibility reasons
772+
_ => ParenthesizedGenericArgs::Warn,
773+
};
752774

753775
let num_lifetimes = type_def_id.map_or(0, |def_id| {
754776
if let Some(&n) = self.type_def_lifetime_params.get(&def_id) {
@@ -759,7 +781,8 @@ impl<'a> LoweringContext<'a> {
759781
self.type_def_lifetime_params.insert(def_id, n);
760782
n
761783
});
762-
self.lower_path_segment(p.span, segment, param_mode, num_lifetimes)
784+
self.lower_path_segment(p.span, segment, param_mode, num_lifetimes,
785+
parenthesized_generic_args)
763786
}).collect(),
764787
span: p.span,
765788
});
@@ -794,7 +817,8 @@ impl<'a> LoweringContext<'a> {
794817
// 3. `<<std::vec::Vec<T>>::IntoIter>::Item`
795818
// * final path is `<<<std::vec::Vec<T>>::IntoIter>::Item>::clone`
796819
for (i, segment) in p.segments.iter().enumerate().skip(proj_start) {
797-
let segment = P(self.lower_path_segment(p.span, segment, param_mode, 0));
820+
let segment = P(self.lower_path_segment(p.span, segment, param_mode, 0,
821+
ParenthesizedGenericArgs::Warn));
798822
let qpath = hir::QPath::TypeRelative(ty, segment);
799823

800824
// It's finished, return the extension of the right node type.
@@ -827,7 +851,8 @@ impl<'a> LoweringContext<'a> {
827851
hir::Path {
828852
def: self.expect_full_def(id),
829853
segments: segments.map(|segment| {
830-
self.lower_path_segment(p.span, segment, param_mode, 0)
854+
self.lower_path_segment(p.span, segment, param_mode, 0,
855+
ParenthesizedGenericArgs::Err)
831856
}).chain(name.map(|name| {
832857
hir::PathSegment {
833858
name,
@@ -851,29 +876,37 @@ impl<'a> LoweringContext<'a> {
851876
path_span: Span,
852877
segment: &PathSegment,
853878
param_mode: ParamMode,
854-
expected_lifetimes: usize)
879+
expected_lifetimes: usize,
880+
parenthesized_generic_args: ParenthesizedGenericArgs)
855881
-> hir::PathSegment {
856882
let mut parameters = if let Some(ref parameters) = segment.parameters {
883+
let msg = "parenthesized parameters may only be used with a trait";
857884
match **parameters {
858885
PathParameters::AngleBracketed(ref data) => {
859-
let data = self.lower_angle_bracketed_parameter_data(data, param_mode);
860-
hir::AngleBracketedParameters(data)
886+
self.lower_angle_bracketed_parameter_data(data, param_mode)
861887
}
862-
PathParameters::Parenthesized(ref data) => {
863-
hir::ParenthesizedParameters(self.lower_parenthesized_parameter_data(data))
888+
PathParameters::Parenthesized(ref data) => match parenthesized_generic_args {
889+
ParenthesizedGenericArgs::Ok => self.lower_parenthesized_parameter_data(data),
890+
ParenthesizedGenericArgs::Warn => {
891+
self.sess.buffer_lint(PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES,
892+
CRATE_NODE_ID, data.span, msg.into());
893+
hir::PathParameters::none()
894+
}
895+
ParenthesizedGenericArgs::Err => {
896+
struct_span_err!(self.sess, data.span, E0214, "{}", msg)
897+
.span_label(data.span, "only traits may use parentheses").emit();
898+
hir::PathParameters::none()
899+
}
864900
}
865901
}
866902
} else {
867-
let data = self.lower_angle_bracketed_parameter_data(&Default::default(), param_mode);
868-
hir::AngleBracketedParameters(data)
903+
self.lower_angle_bracketed_parameter_data(&Default::default(), param_mode)
869904
};
870905

871-
if let hir::AngleBracketedParameters(ref mut data) = parameters {
872-
if data.lifetimes.is_empty() {
873-
data.lifetimes = (0..expected_lifetimes).map(|_| {
874-
self.elided_lifetime(path_span)
875-
}).collect();
876-
}
906+
if !parameters.parenthesized && parameters.lifetimes.is_empty() {
907+
parameters.lifetimes = (0..expected_lifetimes).map(|_| {
908+
self.elided_lifetime(path_span)
909+
}).collect();
877910
}
878911

879912
hir::PathSegment {
@@ -885,24 +918,38 @@ impl<'a> LoweringContext<'a> {
885918
fn lower_angle_bracketed_parameter_data(&mut self,
886919
data: &AngleBracketedParameterData,
887920
param_mode: ParamMode)
888-
-> hir::AngleBracketedParameterData {
921+
-> hir::PathParameters {
889922
let &AngleBracketedParameterData { ref lifetimes, ref types, ref bindings, .. } = data;
890-
hir::AngleBracketedParameterData {
923+
hir::PathParameters {
891924
lifetimes: self.lower_lifetimes(lifetimes),
892925
types: types.iter().map(|ty| self.lower_ty(ty)).collect(),
893926
infer_types: types.is_empty() && param_mode == ParamMode::Optional,
894927
bindings: bindings.iter().map(|b| self.lower_ty_binding(b)).collect(),
928+
parenthesized: false,
895929
}
896930
}
897931

898932
fn lower_parenthesized_parameter_data(&mut self,
899933
data: &ParenthesizedParameterData)
900-
-> hir::ParenthesizedParameterData {
934+
-> hir::PathParameters {
901935
let &ParenthesizedParameterData { ref inputs, ref output, span } = data;
902-
hir::ParenthesizedParameterData {
903-
inputs: inputs.iter().map(|ty| self.lower_ty(ty)).collect(),
904-
output: output.as_ref().map(|ty| self.lower_ty(ty)),
905-
span,
936+
let inputs = inputs.iter().map(|ty| self.lower_ty(ty)).collect();
937+
let mk_tup = |this: &mut Self, tys, span| {
938+
P(hir::Ty { node: hir::TyTup(tys), id: this.next_id().node_id, span })
939+
};
940+
941+
hir::PathParameters {
942+
lifetimes: hir::HirVec::new(),
943+
types: hir_vec![mk_tup(self, inputs, span)],
944+
infer_types: false,
945+
bindings: hir_vec![hir::TypeBinding {
946+
id: self.next_id().node_id,
947+
name: Symbol::intern(FN_OUTPUT_NAME),
948+
ty: output.as_ref().map(|ty| self.lower_ty(&ty))
949+
.unwrap_or_else(|| mk_tup(self, hir::HirVec::new(), span)),
950+
span: output.as_ref().map_or(span, |ty| ty.span),
951+
}],
952+
parenthesized: true,
906953
}
907954
}
908955

@@ -1877,7 +1924,8 @@ impl<'a> LoweringContext<'a> {
18771924
hir::ExprCall(f, args.iter().map(|x| self.lower_expr(x)).collect())
18781925
}
18791926
ExprKind::MethodCall(ref seg, ref args) => {
1880-
let hir_seg = self.lower_path_segment(e.span, seg, ParamMode::Optional, 0);
1927+
let hir_seg = self.lower_path_segment(e.span, seg, ParamMode::Optional, 0,
1928+
ParenthesizedGenericArgs::Err);
18811929
let args = args.iter().map(|x| self.lower_expr(x)).collect();
18821930
hir::ExprMethodCall(hir_seg, seg.span, args)
18831931
}

src/librustc/hir/mod.rs

+25-70
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ pub use self::TyParamBound::*;
2626
pub use self::UnOp::*;
2727
pub use self::UnsafeSource::*;
2828
pub use self::Visibility::{Public, Inherited};
29-
pub use self::PathParameters::*;
3029

3130
use hir::def::Def;
3231
use hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX};
@@ -227,65 +226,7 @@ impl PathSegment {
227226
}
228227

229228
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
230-
pub enum PathParameters {
231-
/// The `<'a, A,B,C>` in `foo::bar::baz::<'a, A,B,C>`
232-
AngleBracketedParameters(AngleBracketedParameterData),
233-
/// The `(A,B)` and `C` in `Foo(A,B) -> C`
234-
ParenthesizedParameters(ParenthesizedParameterData),
235-
}
236-
237-
impl PathParameters {
238-
pub fn none() -> PathParameters {
239-
AngleBracketedParameters(AngleBracketedParameterData {
240-
lifetimes: HirVec::new(),
241-
types: HirVec::new(),
242-
infer_types: true,
243-
bindings: HirVec::new(),
244-
})
245-
}
246-
247-
/// Returns the types that the user wrote. Note that these do not necessarily map to the type
248-
/// parameters in the parenthesized case.
249-
pub fn types(&self) -> HirVec<&P<Ty>> {
250-
match *self {
251-
AngleBracketedParameters(ref data) => {
252-
data.types.iter().collect()
253-
}
254-
ParenthesizedParameters(ref data) => {
255-
data.inputs
256-
.iter()
257-
.chain(data.output.iter())
258-
.collect()
259-
}
260-
}
261-
}
262-
263-
pub fn lifetimes(&self) -> HirVec<&Lifetime> {
264-
match *self {
265-
AngleBracketedParameters(ref data) => {
266-
data.lifetimes.iter().collect()
267-
}
268-
ParenthesizedParameters(_) => {
269-
HirVec::new()
270-
}
271-
}
272-
}
273-
274-
pub fn bindings(&self) -> HirVec<&TypeBinding> {
275-
match *self {
276-
AngleBracketedParameters(ref data) => {
277-
data.bindings.iter().collect()
278-
}
279-
ParenthesizedParameters(_) => {
280-
HirVec::new()
281-
}
282-
}
283-
}
284-
}
285-
286-
/// A path like `Foo<'a, T>`
287-
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
288-
pub struct AngleBracketedParameterData {
229+
pub struct PathParameters {
289230
/// The lifetime parameters for this path segment.
290231
pub lifetimes: HirVec<Lifetime>,
291232
/// The type parameters for this path segment, if present.
@@ -298,19 +239,33 @@ pub struct AngleBracketedParameterData {
298239
/// Bindings (equality constraints) on associated types, if present.
299240
/// E.g., `Foo<A=Bar>`.
300241
pub bindings: HirVec<TypeBinding>,
242+
/// Were parameters written in parenthesized form `Fn(T) -> U`?
243+
/// This is required mostly for pretty-printing and diagnostics,
244+
/// but also for changing lifetime elision rules to be "function-like".
245+
pub parenthesized: bool,
301246
}
302247

303-
/// A path like `Foo(A,B) -> C`
304-
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
305-
pub struct ParenthesizedParameterData {
306-
/// Overall span
307-
pub span: Span,
308-
309-
/// `(A,B)`
310-
pub inputs: HirVec<P<Ty>>,
248+
impl PathParameters {
249+
pub fn none() -> Self {
250+
Self {
251+
lifetimes: HirVec::new(),
252+
types: HirVec::new(),
253+
infer_types: true,
254+
bindings: HirVec::new(),
255+
parenthesized: false,
256+
}
257+
}
311258

312-
/// `C`
313-
pub output: Option<P<Ty>>,
259+
pub fn inputs(&self) -> &[P<Ty>] {
260+
if self.parenthesized {
261+
if let Some(ref ty) = self.types.get(0) {
262+
if let TyTup(ref tys) = ty.node {
263+
return tys;
264+
}
265+
}
266+
}
267+
bug!("PathParameters::inputs: not a `Fn(T) -> U`");
268+
}
314269
}
315270

316271
/// The AST represents all type param bounds as types.

0 commit comments

Comments
 (0)