From 000f87ab1eb13b1e743bcb614b8d59463f2efd04 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 29 Jul 2017 01:13:40 +0300 Subject: [PATCH] Desugar parenthesized generic arguments in HIR --- src/librustc/diagnostics.rs | 15 ++ src/librustc/hir/intravisit.rs | 14 +- src/librustc/hir/lowering.rs | 98 ++++++++--- src/librustc/hir/mod.rs | 95 +++------- src/librustc/hir/print.rs | 94 +++++----- src/librustc/ich/impls_hir.rs | 16 +- src/librustc/middle/resolve_lifetime.rs | 23 ++- src/librustc_driver/driver.rs | 8 +- src/librustc_passes/ast_validation.rs | 8 - src/librustc_typeck/astconv.rs | 164 ++++-------------- src/librustc_typeck/check/method/confirm.rs | 13 +- src/librustc_typeck/check/mod.rs | 37 +--- src/librustc_typeck/diagnostics.rs | 55 +----- src/librustdoc/clean/mod.rs | 37 ++-- .../associated-types-eq-expr-path.rs | 2 +- src/test/compile-fail/issue-43431.rs | 24 +++ .../compile-fail/method-call-type-binding.rs | 2 +- .../unboxed-closure-sugar-used-on-struct.rs | 1 + 18 files changed, 266 insertions(+), 440 deletions(-) create mode 100644 src/test/compile-fail/issue-43431.rs diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 34d31028385..412759e1142 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -687,6 +687,21 @@ attributes: See also https://doc.rust-lang.org/book/first-edition/no-stdlib.html "##, +E0214: r##" +A generic type was described using parentheses rather than angle brackets. For +example: + +```compile_fail,E0214 +fn main() { + let v: Vec(&str) = vec!["foo"]; +} +``` + +This is not currently supported: `v` should be defined as `Vec<&str>`. +Parentheses are currently only used with generic types when defining parameters +for `Fn`-family traits. +"##, + E0261: r##" When using a lifetime like `'a` in a type, it must be declared before being used. diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 2a0c76d99bf..483885b3d23 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -617,17 +617,9 @@ pub fn walk_path_segment<'v, V: Visitor<'v>>(visitor: &mut V, pub fn walk_path_parameters<'v, V: Visitor<'v>>(visitor: &mut V, _path_span: Span, path_parameters: &'v PathParameters) { - match *path_parameters { - AngleBracketedParameters(ref data) => { - walk_list!(visitor, visit_ty, &data.types); - walk_list!(visitor, visit_lifetime, &data.lifetimes); - walk_list!(visitor, visit_assoc_type_binding, &data.bindings); - } - ParenthesizedParameters(ref data) => { - walk_list!(visitor, visit_ty, &data.inputs); - walk_list!(visitor, visit_ty, &data.output); - } - } + walk_list!(visitor, visit_lifetime, &path_parameters.lifetimes); + walk_list!(visitor, visit_ty, &path_parameters.types); + walk_list!(visitor, visit_assoc_type_binding, &path_parameters.bindings); } pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(visitor: &mut V, diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 58bb5b9580f..89ce52af77c 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -45,15 +45,16 @@ use hir::map::{Definitions, DefKey, REGULAR_SPACE}; use hir::map::definitions::DefPathData; use hir::def_id::{DefIndex, DefId, CRATE_DEF_INDEX}; use hir::def::{Def, PathResolution}; +use lint::builtin::PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES; use rustc_data_structures::indexed_vec::IndexVec; use session::Session; +use util::common::FN_OUTPUT_NAME; use util::nodemap::{DefIdMap, FxHashMap, NodeMap}; use std::collections::BTreeMap; use std::fmt::Debug; use std::iter; use std::mem; - use syntax::attr; use syntax::ast::*; use syntax::errors; @@ -160,6 +161,12 @@ struct LoweredNodeId { hir_id: hir::HirId, } +enum ParenthesizedGenericArgs { + Ok, + Warn, + Err, +} + impl<'a> LoweringContext<'a> { fn lower_crate(mut self, c: &Crate) -> hir::Crate { /// Full-crate AST visitor that inserts into a fresh @@ -749,6 +756,21 @@ impl<'a> LoweringContext<'a> { Def::Trait(def_id) if i + 1 == proj_start => Some(def_id), _ => None }; + let parenthesized_generic_args = match resolution.base_def() { + // `a::b::Trait(Args)` + Def::Trait(..) if i + 1 == proj_start => ParenthesizedGenericArgs::Ok, + // `a::b::Trait(Args)::TraitItem` + Def::Method(..) | + Def::AssociatedConst(..) | + Def::AssociatedTy(..) if i + 2 == proj_start => ParenthesizedGenericArgs::Ok, + // Avoid duplicated errors + Def::Err => ParenthesizedGenericArgs::Ok, + // An error + Def::Struct(..) | Def::Enum(..) | Def::Union(..) | Def::TyAlias(..) | + Def::Variant(..) if i + 1 == proj_start => ParenthesizedGenericArgs::Err, + // A warning for now, for compatibility reasons + _ => ParenthesizedGenericArgs::Warn, + }; let num_lifetimes = type_def_id.map_or(0, |def_id| { if let Some(&n) = self.type_def_lifetime_params.get(&def_id) { @@ -759,7 +781,8 @@ impl<'a> LoweringContext<'a> { self.type_def_lifetime_params.insert(def_id, n); n }); - self.lower_path_segment(p.span, segment, param_mode, num_lifetimes) + self.lower_path_segment(p.span, segment, param_mode, num_lifetimes, + parenthesized_generic_args) }).collect(), span: p.span, }); @@ -794,7 +817,8 @@ impl<'a> LoweringContext<'a> { // 3. `<>::IntoIter>::Item` // * final path is `<<>::IntoIter>::Item>::clone` for (i, segment) in p.segments.iter().enumerate().skip(proj_start) { - let segment = P(self.lower_path_segment(p.span, segment, param_mode, 0)); + let segment = P(self.lower_path_segment(p.span, segment, param_mode, 0, + ParenthesizedGenericArgs::Warn)); let qpath = hir::QPath::TypeRelative(ty, segment); // It's finished, return the extension of the right node type. @@ -827,7 +851,8 @@ impl<'a> LoweringContext<'a> { hir::Path { def: self.expect_full_def(id), segments: segments.map(|segment| { - self.lower_path_segment(p.span, segment, param_mode, 0) + self.lower_path_segment(p.span, segment, param_mode, 0, + ParenthesizedGenericArgs::Err) }).chain(name.map(|name| { hir::PathSegment { name, @@ -851,29 +876,37 @@ impl<'a> LoweringContext<'a> { path_span: Span, segment: &PathSegment, param_mode: ParamMode, - expected_lifetimes: usize) + expected_lifetimes: usize, + parenthesized_generic_args: ParenthesizedGenericArgs) -> hir::PathSegment { let mut parameters = if let Some(ref parameters) = segment.parameters { + let msg = "parenthesized parameters may only be used with a trait"; match **parameters { PathParameters::AngleBracketed(ref data) => { - let data = self.lower_angle_bracketed_parameter_data(data, param_mode); - hir::AngleBracketedParameters(data) + self.lower_angle_bracketed_parameter_data(data, param_mode) } - PathParameters::Parenthesized(ref data) => { - hir::ParenthesizedParameters(self.lower_parenthesized_parameter_data(data)) + PathParameters::Parenthesized(ref data) => match parenthesized_generic_args { + ParenthesizedGenericArgs::Ok => self.lower_parenthesized_parameter_data(data), + ParenthesizedGenericArgs::Warn => { + self.sess.buffer_lint(PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES, + CRATE_NODE_ID, data.span, msg.into()); + hir::PathParameters::none() + } + ParenthesizedGenericArgs::Err => { + struct_span_err!(self.sess, data.span, E0214, "{}", msg) + .span_label(data.span, "only traits may use parentheses").emit(); + hir::PathParameters::none() + } } } } else { - let data = self.lower_angle_bracketed_parameter_data(&Default::default(), param_mode); - hir::AngleBracketedParameters(data) + self.lower_angle_bracketed_parameter_data(&Default::default(), param_mode) }; - if let hir::AngleBracketedParameters(ref mut data) = parameters { - if data.lifetimes.is_empty() { - data.lifetimes = (0..expected_lifetimes).map(|_| { - self.elided_lifetime(path_span) - }).collect(); - } + if !parameters.parenthesized && parameters.lifetimes.is_empty() { + parameters.lifetimes = (0..expected_lifetimes).map(|_| { + self.elided_lifetime(path_span) + }).collect(); } hir::PathSegment { @@ -885,24 +918,38 @@ impl<'a> LoweringContext<'a> { fn lower_angle_bracketed_parameter_data(&mut self, data: &AngleBracketedParameterData, param_mode: ParamMode) - -> hir::AngleBracketedParameterData { + -> hir::PathParameters { let &AngleBracketedParameterData { ref lifetimes, ref types, ref bindings, .. } = data; - hir::AngleBracketedParameterData { + 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, } } fn lower_parenthesized_parameter_data(&mut self, data: &ParenthesizedParameterData) - -> hir::ParenthesizedParameterData { + -> hir::PathParameters { let &ParenthesizedParameterData { ref inputs, ref output, span } = data; - hir::ParenthesizedParameterData { - inputs: inputs.iter().map(|ty| self.lower_ty(ty)).collect(), - output: output.as_ref().map(|ty| self.lower_ty(ty)), - span, + let inputs = inputs.iter().map(|ty| self.lower_ty(ty)).collect(); + let mk_tup = |this: &mut Self, tys, span| { + P(hir::Ty { node: hir::TyTup(tys), id: this.next_id().node_id, span }) + }; + + 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), + ty: output.as_ref().map(|ty| self.lower_ty(&ty)) + .unwrap_or_else(|| mk_tup(self, hir::HirVec::new(), span)), + span: output.as_ref().map_or(span, |ty| ty.span), + }], + parenthesized: true, } } @@ -1877,7 +1924,8 @@ impl<'a> LoweringContext<'a> { hir::ExprCall(f, args.iter().map(|x| self.lower_expr(x)).collect()) } ExprKind::MethodCall(ref seg, ref args) => { - let hir_seg = self.lower_path_segment(e.span, seg, ParamMode::Optional, 0); + let hir_seg = self.lower_path_segment(e.span, seg, ParamMode::Optional, 0, + ParenthesizedGenericArgs::Err); let args = args.iter().map(|x| self.lower_expr(x)).collect(); hir::ExprMethodCall(hir_seg, seg.span, args) } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 400f46d66f8..01f5d268815 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -26,7 +26,6 @@ pub use self::TyParamBound::*; pub use self::UnOp::*; pub use self::UnsafeSource::*; pub use self::Visibility::{Public, Inherited}; -pub use self::PathParameters::*; use hir::def::Def; use hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX}; @@ -227,65 +226,7 @@ impl PathSegment { } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] -pub enum PathParameters { - /// The `<'a, A,B,C>` in `foo::bar::baz::<'a, A,B,C>` - AngleBracketedParameters(AngleBracketedParameterData), - /// The `(A,B)` and `C` in `Foo(A,B) -> C` - ParenthesizedParameters(ParenthesizedParameterData), -} - -impl PathParameters { - pub fn none() -> PathParameters { - AngleBracketedParameters(AngleBracketedParameterData { - lifetimes: HirVec::new(), - types: HirVec::new(), - infer_types: true, - bindings: HirVec::new(), - }) - } - - /// Returns the types that the user wrote. Note that these do not necessarily map to the type - /// parameters in the parenthesized case. - pub fn types(&self) -> HirVec<&P> { - match *self { - AngleBracketedParameters(ref data) => { - data.types.iter().collect() - } - ParenthesizedParameters(ref data) => { - data.inputs - .iter() - .chain(data.output.iter()) - .collect() - } - } - } - - pub fn lifetimes(&self) -> HirVec<&Lifetime> { - match *self { - AngleBracketedParameters(ref data) => { - data.lifetimes.iter().collect() - } - ParenthesizedParameters(_) => { - HirVec::new() - } - } - } - - pub fn bindings(&self) -> HirVec<&TypeBinding> { - match *self { - AngleBracketedParameters(ref data) => { - data.bindings.iter().collect() - } - ParenthesizedParameters(_) => { - HirVec::new() - } - } - } -} - -/// A path like `Foo<'a, T>` -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] -pub struct AngleBracketedParameterData { +pub struct PathParameters { /// The lifetime parameters for this path segment. pub lifetimes: HirVec, /// The type parameters for this path segment, if present. @@ -298,19 +239,33 @@ pub struct AngleBracketedParameterData { /// Bindings (equality constraints) on associated types, if present. /// E.g., `Foo`. pub bindings: HirVec, + /// Were parameters written in parenthesized form `Fn(T) -> U`? + /// This is required mostly for pretty-printing and diagnostics, + /// but also for changing lifetime elision rules to be "function-like". + pub parenthesized: bool, } -/// A path like `Foo(A,B) -> C` -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] -pub struct ParenthesizedParameterData { - /// Overall span - pub span: Span, +impl PathParameters { + pub fn none() -> Self { + Self { + lifetimes: HirVec::new(), + types: HirVec::new(), + infer_types: true, + bindings: HirVec::new(), + parenthesized: false, + } + } - /// `(A,B)` - pub inputs: HirVec>, - - /// `C` - pub output: Option>, + pub fn inputs(&self) -> &[P] { + if self.parenthesized { + if let Some(ref ty) = self.types.get(0) { + if let TyTup(ref tys) = ty.node { + return tys; + } + } + } + bug!("PathParameters::inputs: not a `Fn(T) -> U`"); + } } /// The AST represents all type param bounds as types. diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index abfb00a24a1..876875bce4a 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -1194,9 +1194,9 @@ impl<'a> State<'a> { self.print_expr(&args[0])?; self.s.word(".")?; self.print_name(segment.name)?; - if !segment.parameters.lifetimes().is_empty() || - !segment.parameters.types().is_empty() || - !segment.parameters.bindings().is_empty() { + if !segment.parameters.lifetimes.is_empty() || + !segment.parameters.types.is_empty() || + !segment.parameters.bindings.is_empty() { self.print_path_parameters(&segment.parameters, true)?; } self.print_call_post(base_args) @@ -1581,61 +1581,55 @@ impl<'a> State<'a> { parameters: &hir::PathParameters, colons_before_params: bool) -> io::Result<()> { - match *parameters { - hir::AngleBracketedParameters(ref data) => { - let start = if colons_before_params { "::<" } else { "<" }; - let empty = Cell::new(true); - let start_or_comma = |this: &mut Self| { - if empty.get() { - empty.set(false); - this.s.word(start) - } else { - this.word_space(",") - } - }; + if parameters.parenthesized { + self.s.word("(")?; + self.commasep(Inconsistent, parameters.inputs(), |s, ty| s.print_type(&ty))?; + self.s.word(")")?; - if !data.lifetimes.iter().all(|lt| lt.is_elided()) { - for lifetime in &data.lifetimes { - start_or_comma(self)?; - self.print_lifetime(lifetime)?; - } + self.space_if_not_bol()?; + self.word_space("->")?; + self.print_type(¶meters.bindings[0].ty)?; + } else { + let start = if colons_before_params { "::<" } else { "<" }; + let empty = Cell::new(true); + let start_or_comma = |this: &mut Self| { + if empty.get() { + empty.set(false); + this.s.word(start) + } else { + this.word_space(",") } + }; - if !data.types.is_empty() { + if !parameters.lifetimes.iter().all(|lt| lt.is_elided()) { + for lifetime in ¶meters.lifetimes { start_or_comma(self)?; - self.commasep(Inconsistent, &data.types, |s, ty| s.print_type(&ty))?; - } - - // FIXME(eddyb) This would leak into error messages, e.g.: - // "non-exhaustive patterns: `Some::<..>(_)` not covered". - if data.infer_types && false { - start_or_comma(self)?; - self.s.word("..")?; - } - - for binding in data.bindings.iter() { - start_or_comma(self)?; - self.print_name(binding.name)?; - self.s.space()?; - self.word_space("=")?; - self.print_type(&binding.ty)?; - } - - if !empty.get() { - self.s.word(">")? + self.print_lifetime(lifetime)?; } } - hir::ParenthesizedParameters(ref data) => { - self.s.word("(")?; - self.commasep(Inconsistent, &data.inputs, |s, ty| s.print_type(&ty))?; - self.s.word(")")?; + if !parameters.types.is_empty() { + start_or_comma(self)?; + self.commasep(Inconsistent, ¶meters.types, |s, ty| s.print_type(&ty))?; + } - if let Some(ref ty) = data.output { - self.space_if_not_bol()?; - self.word_space("->")?; - self.print_type(&ty)?; - } + // FIXME(eddyb) This would leak into error messages, e.g.: + // "non-exhaustive patterns: `Some::<..>(_)` not covered". + if parameters.infer_types && false { + start_or_comma(self)?; + self.s.word("..")?; + } + + for binding in parameters.bindings.iter() { + start_or_comma(self)?; + self.print_name(binding.name)?; + self.s.space()?; + self.word_space("=")?; + self.print_type(&binding.ty)?; + } + + if !empty.get() { + self.s.word(">")? } } diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 4c70816c0b8..c5222c2d6cb 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -133,22 +133,12 @@ impl_stable_hash_for!(struct hir::PathSegment { parameters }); -impl_stable_hash_for!(enum hir::PathParameters { - AngleBracketedParameters(data), - ParenthesizedParameters(data) -}); - -impl_stable_hash_for!(struct hir::AngleBracketedParameterData { +impl_stable_hash_for!(struct hir::PathParameters { lifetimes, types, infer_types, - bindings -}); - -impl_stable_hash_for!(struct hir::ParenthesizedParameterData { - span, - inputs, - output + bindings, + parenthesized }); impl_stable_hash_for!(enum hir::TyParamBound { diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 12362c8d3bf..a8e98e53db3 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -915,18 +915,15 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { def: Def, depth: usize, params: &'tcx hir::PathParameters) { - let data = match *params { - hir::ParenthesizedParameters(ref data) => { - self.visit_fn_like_elision(&data.inputs, data.output.as_ref()); - return; - } - hir::AngleBracketedParameters(ref data) => data - }; + if params.parenthesized { + self.visit_fn_like_elision(params.inputs(), Some(¶ms.bindings[0].ty)); + return; + } - if data.lifetimes.iter().all(|l| l.is_elided()) { - self.resolve_elided_lifetimes(&data.lifetimes); + if params.lifetimes.iter().all(|l| l.is_elided()) { + self.resolve_elided_lifetimes(¶ms.lifetimes); } else { - for l in &data.lifetimes { self.visit_lifetime(l); } + for l in ¶ms.lifetimes { self.visit_lifetime(l); } } // Figure out if this is a type/trait segment, @@ -995,13 +992,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { Some(Region::Static) } } - Set1::One(r) => r.subst(&data.lifetimes, map), + Set1::One(r) => r.subst(¶ms.lifetimes, map), Set1::Many => None } }).collect() }); - for (i, ty) in data.types.iter().enumerate() { + for (i, ty) in params.types.iter().enumerate() { if let Some(<) = object_lifetime_defaults.get(i) { let scope = Scope::ObjectLifetimeDefault { lifetime: lt, @@ -1013,7 +1010,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } } - for b in &data.bindings { self.visit_assoc_type_binding(b); } + for b in ¶ms.bindings { self.visit_assoc_type_binding(b); } } fn visit_fn_like_elision(&mut self, inputs: &'tcx [P], diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index c98f9c3d466..0be29ee5728 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -833,10 +833,6 @@ pub fn phase_2_configure_and_expand(sess: &Session, }) })?; - time(time_passes, - "early lint checks", - || lint::check_ast_crate(sess, &krate)); - // Lower ast -> hir. let hir_forest = time(time_passes, "lowering ast -> hir", || { let hir_crate = lower_crate(sess, &krate, &mut resolver); @@ -848,6 +844,10 @@ pub fn phase_2_configure_and_expand(sess: &Session, hir_map::Forest::new(hir_crate, &sess.dep_graph) }); + time(time_passes, + "early lint checks", + || lint::check_ast_crate(sess, &krate)); + // Discard hygiene data, which isn't required after lowering to HIR. if !keep_hygiene_data(sess) { syntax::ext::hygiene::clear_markings(); diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index b22f8112d7a..ffe444933a3 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -140,14 +140,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> { ExprKind::Continue(Some(ident)) => { self.check_label(ident.node, ident.span); } - ExprKind::MethodCall(ref segment, ..) => { - if let Some(ref params) = segment.parameters { - if let PathParameters::Parenthesized(..) = **params { - self.err_handler().span_err(expr.span, - "parenthesized parameters cannot be used on method calls"); - } - } - } _ => {} } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 32fa0534db6..ee1e6bd950f 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -22,16 +22,14 @@ use rustc::ty::subst::{Kind, Subst, Substs}; use rustc::traits; use rustc::ty::{self, Ty, TyCtxt, ToPredicate, TypeFoldable}; use rustc::ty::wf::object_region_bounds; -use rustc::lint::builtin::PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES; use rustc_back::slice; use require_c_abi_if_variadic; -use util::common::{ErrorReported, FN_OUTPUT_NAME}; +use util::common::ErrorReported; use util::nodemap::FxHashSet; use std::iter; use syntax::{abi, ast}; use syntax::feature_gate::{GateIssue, emit_feature_err}; -use syntax::symbol::Symbol; use syntax_pos::Span; pub trait AstConv<'gcx, 'tcx> { @@ -152,21 +150,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { item_segment: &hir::PathSegment) -> &'tcx Substs<'tcx> { - let tcx = self.tcx(); - - match item_segment.parameters { - hir::AngleBracketedParameters(_) => {} - hir::ParenthesizedParameters(..) => { - self.prohibit_parenthesized_params(item_segment, true); - - return Substs::for_item(tcx, def_id, |_, _| { - tcx.types.re_static - }, |_, _| { - tcx.types.err - }); - } - } - let (substs, assoc_bindings) = self.create_substs_for_ast_path(span, def_id, @@ -196,19 +179,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { parameters={:?})", def_id, self_ty, parameters); - let (lifetimes, num_types_provided, infer_types) = match *parameters { - hir::AngleBracketedParameters(ref data) => { - (&data.lifetimes[..], data.types.len(), data.infer_types) - } - hir::ParenthesizedParameters(_) => (&[][..], 1, false) - }; - // If the type is parameterized by this region, then replace this // region with the current anon region binding (in other words, // whatever & would get replaced with). let decl_generics = tcx.generics_of(def_id); + let num_types_provided = parameters.types.len(); let expected_num_region_params = decl_generics.regions.len(); - let supplied_num_region_params = lifetimes.len(); + let supplied_num_region_params = parameters.lifetimes.len(); if expected_num_region_params != supplied_num_region_params { report_lifetime_number_error(tcx, span, supplied_num_region_params, @@ -220,7 +197,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 !infer_types || num_types_provided > ty_param_defs.len() { + if !parameters.infer_types || num_types_provided > ty_param_defs.len() { check_type_argument_count(tcx, span, num_types_provided, ty_param_defs); } @@ -237,10 +214,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { false }; - let mut output_assoc_binding = None; let substs = Substs::for_item(tcx, def_id, |def, _| { let i = def.index as usize - self_ty.is_some() as usize; - if let Some(lifetime) = lifetimes.get(i) { + if let Some(lifetime) = parameters.lifetimes.get(i) { self.ast_region_to_region(lifetime, Some(def)) } else { tcx.types.re_static @@ -256,18 +232,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let i = i - self_ty.is_some() as usize - decl_generics.regions.len(); if i < num_types_provided { // A provided type parameter. - match *parameters { - hir::AngleBracketedParameters(ref data) => { - self.ast_ty_to_ty(&data.types[i]) - } - hir::ParenthesizedParameters(ref data) => { - assert_eq!(i, 0); - let (ty, assoc) = self.convert_parenthesized_parameters(data); - output_assoc_binding = Some(assoc); - ty - } - } - } else if infer_types { + self.ast_ty_to_ty(¶meters.types[i]) + } else if parameters.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) @@ -306,24 +272,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } }); - let assoc_bindings = match *parameters { - hir::AngleBracketedParameters(ref data) => { - data.bindings.iter().map(|b| { - ConvertedBinding { - item_name: b.name, - ty: self.ast_ty_to_ty(&b.ty), - span: b.span - } - }).collect() + let assoc_bindings = parameters.bindings.iter().map(|binding| { + ConvertedBinding { + item_name: binding.name, + ty: self.ast_ty_to_ty(&binding.ty), + span: binding.span, } - hir::ParenthesizedParameters(ref data) => { - vec![output_assoc_binding.unwrap_or_else(|| { - // This is an error condition, but we should - // get the associated type binding anyway. - self.convert_parenthesized_parameters(data).1 - })] - } - }; + }).collect(); debug!("create_substs_for_ast_path(decl_generics={:?}, self_ty={:?}) -> {:?}", decl_generics, self_ty, substs); @@ -331,32 +286,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { (substs, assoc_bindings) } - fn convert_parenthesized_parameters(&self, - data: &hir::ParenthesizedParameterData) - -> (Ty<'tcx>, ConvertedBinding<'tcx>) - { - let inputs = self.tcx().mk_type_list(data.inputs.iter().map(|a_t| { - self.ast_ty_to_ty(a_t) - })); - - let (output, output_span) = match data.output { - Some(ref output_ty) => { - (self.ast_ty_to_ty(output_ty), output_ty.span) - } - None => { - (self.tcx().mk_nil(), data.span) - } - }; - - let output_binding = ConvertedBinding { - item_name: Symbol::intern(FN_OUTPUT_NAME), - ty: output, - span: output_span - }; - - (self.tcx().mk_ty(ty::TyTuple(inputs, false)), output_binding) - } - /// Instantiates the path for the given trait reference, assuming that it's /// bound to a valid trait type. Returns the def_id for the defining trait. /// Fails if the type is a type other than a trait type. @@ -453,29 +382,17 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let trait_def = self.tcx().trait_def(trait_def_id); - match trait_segment.parameters { - hir::AngleBracketedParameters(_) => { - // For now, require that parenthetical notation be used - // only with `Fn()` etc. - if !self.tcx().sess.features.borrow().unboxed_closures && trait_def.paren_sugar { - emit_feature_err(&self.tcx().sess.parse_sess, - "unboxed_closures", span, GateIssue::Language, - "\ - the precise format of `Fn`-family traits' \ - type parameters is subject to change. \ - Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead"); - } - } - hir::ParenthesizedParameters(_) => { - // For now, require that parenthetical notation be used - // only with `Fn()` etc. - if !self.tcx().sess.features.borrow().unboxed_closures && !trait_def.paren_sugar { - emit_feature_err(&self.tcx().sess.parse_sess, - "unboxed_closures", span, GateIssue::Language, - "\ - parenthetical notation is only stable when used with `Fn`-family traits"); - } - } + if !self.tcx().sess.features.borrow().unboxed_closures && + trait_segment.parameters.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. \ + Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead" + } else { + "parenthetical notation is only stable when used with `Fn`-family traits" + }; + emit_feature_err(&self.tcx().sess.parse_sess, "unboxed_closures", + span, GateIssue::Language, msg); } self.create_substs_for_ast_path(span, @@ -951,18 +868,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { pub fn prohibit_type_params(&self, segments: &[hir::PathSegment]) { for segment in segments { - if let hir::ParenthesizedParameters(_) = segment.parameters { - self.prohibit_parenthesized_params(segment, false); - break; - } - for typ in segment.parameters.types() { + 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() { + 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, @@ -970,28 +883,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { .emit(); break; } - for binding in segment.parameters.bindings() { + for binding in &segment.parameters.bindings { self.prohibit_projection(binding.span); break; } } } - pub fn prohibit_parenthesized_params(&self, segment: &hir::PathSegment, emit_error: bool) { - if let hir::ParenthesizedParameters(ref data) = segment.parameters { - if emit_error { - struct_span_err!(self.tcx().sess, data.span, E0214, - "parenthesized parameters may only be used with a trait") - .span_label(data.span, "only traits may use parentheses") - .emit(); - } else { - let msg = "parenthesized parameters may only be used with a trait"; - self.tcx().lint_node(PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES, - ast::CRATE_NODE_ID, data.span, msg); - } - } - } - pub fn prohibit_projection(&self, span: Span) { let mut err = struct_span_err!(self.tcx().sess, span, E0229, "associated type bindings are not allowed here"); @@ -1392,13 +1290,13 @@ fn split_auto_traits<'a, 'b, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, 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() { + if !parameters.types.is_empty() { check_type_argument_count(tcx, bound.trait_ref.path.span, - parameters.types().len(), &[]); + parameters.types.len(), &[]); } - if !parameters.lifetimes().is_empty() { + if !parameters.lifetimes.is_empty() { report_lifetime_number_error(tcx, bound.trait_ref.path.span, - parameters.lifetimes().len(), 0); + parameters.lifetimes.len(), 0); } true } else { diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index cd2adfb7ab0..db383b6305b 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -311,17 +311,14 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // Create subst for early-bound lifetime parameters, combining // parameters from the type and those from the method. - let (supplied_types, supplied_lifetimes) = match segment.parameters { - hir::AngleBracketedParameters(ref data) => (&data.types, &data.lifetimes), - _ => bug!("unexpected generic arguments: {:?}", segment.parameters), - }; assert_eq!(method_generics.parent_count(), parent_substs.len()); + let provided = &segment.parameters; Substs::for_item(self.tcx, pick.item.def_id, |def, _| { let i = def.index as usize; if i < parent_substs.len() { parent_substs.region_at(i) - } else if let Some(lifetime) = - supplied_lifetimes.get(i - parent_substs.len()) { + } else if let Some(lifetime) + = provided.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) @@ -330,8 +327,8 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { let i = def.index as usize; if i < parent_substs.len() { parent_substs.type_at(i) - } else if let Some(ast_ty) = - supplied_types.get(i - parent_substs.len() - method_generics.regions.len()) { + } else if let Some(ast_ty) + = provided.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 2489a8c6941..f4e7110713d 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4621,11 +4621,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { i -= fn_start; fn_segment }; - let lifetimes = match segment.map(|(s, _)| &s.parameters) { - Some(&hir::AngleBracketedParameters(ref data)) => &data.lifetimes[..], - Some(&hir::ParenthesizedParameters(_)) => bug!(), - None => &[] - }; + let lifetimes = segment.map_or(&[][..], |(s, _)| &s.parameters.lifetimes[..]); if let Some(lifetime) = lifetimes.get(i) { AstConv::ast_region_to_region(self, lifetime, Some(def)) @@ -4648,13 +4644,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { i -= fn_start; fn_segment }; - let (types, infer_types) = match segment.map(|(s, _)| &s.parameters) { - Some(&hir::AngleBracketedParameters(ref data)) => { - (&data.types[..], data.infer_types) - } - Some(&hir::ParenthesizedParameters(_)) => bug!(), - None => (&[][..], true) - }; + let (types, infer_types) = segment.map_or((&[][..], true), |(s, _)| { + (&s.parameters.types[..], s.parameters.infer_types) + }); // Skip over the lifetimes in the same segment. if let Some((_, generics)) = segment { @@ -4728,19 +4720,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { span: Span, segment: &mut Option<(&hir::PathSegment, &ty::Generics)>, is_method_call: bool) { - let (lifetimes, types, infer_types, bindings) = { - match segment.map(|(s, _)| &s.parameters) { - Some(&hir::AngleBracketedParameters(ref data)) => { - (&data.lifetimes[..], &data.types[..], data.infer_types, &data.bindings[..]) - } - Some(&hir::ParenthesizedParameters(_)) => { - AstConv::prohibit_parenthesized_params(self, &segment.as_ref().unwrap().0, - false); - (&[][..], &[][..], true, &[][..]) - } - None => (&[][..], &[][..], true, &[][..]) - } - }; + let (lifetimes, types, infer_types, bindings) = segment.map_or( + (&[][..], &[][..], true, &[][..]), + |(s, _)| (&s.parameters.lifetimes[..], &s.parameters.types[..], + s.parameters.infer_types, &s.parameters.bindings[..])); let infer_lifetimes = lifetimes.len() == 0; let count_lifetime_params = |n| { @@ -4786,9 +4769,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } if !bindings.is_empty() { - span_err!(self.tcx.sess, bindings[0].span, E0182, - "unexpected binding of associated item in expression path \ - (only allowed in type paths)"); + AstConv::prohibit_projection(self, bindings[0].span); } // Check provided lifetime parameters. diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index c74dc24ddc3..cb430efd950 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -1636,45 +1636,6 @@ fn bar(foo: Foo) -> u32 { ``` "##, -E0182: r##" -You bound an associated type in an expression path which is not -allowed. - -Erroneous code example: - -```compile_fail,E0182 -trait Foo { - type A; - fn bar() -> isize; -} - -impl Foo for isize { - type A = usize; - fn bar() -> isize { 42 } -} - -// error: unexpected binding of associated item in expression path -let x: isize = Foo::::bar(); -``` - -To give a concrete type when using the Universal Function Call Syntax, -use "Type as Trait". Example: - -``` -trait Foo { - type A; - fn bar() -> isize; -} - -impl Foo for isize { - type A = usize; - fn bar() -> isize { 42 } -} - -let x: isize = ::bar(); // ok! -``` -"##, - E0184: r##" Explicitly implementing both Drop and Copy for a type is currently disallowed. This feature can make some sense in theory, but the current implementation is @@ -2359,21 +2320,6 @@ impl Foo { "##, */ -E0214: r##" -A generic type was described using parentheses rather than angle brackets. For -example: - -```compile_fail,E0214 -fn main() { - let v: Vec(&str) = vec!["foo"]; -} -``` - -This is not currently supported: `v` should be defined as `Vec<&str>`. -Parentheses are currently only used with generic types when defining parameters -for `Fn`-family traits. -"##, - E0220: r##" You used an associated type which isn't defined in the trait. Erroneous code example: @@ -4721,6 +4667,7 @@ register_diagnostics! { // E0172, // non-trait found in a type sum, moved to resolve // E0173, // manual implementations of unboxed closure traits are experimental // E0174, +// E0182, // merged into E0229 E0183, // E0187, // can't infer the kind of the closure // E0188, // can not cast an immutable reference to a mutable pointer diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index f4aef8ab377..92b3180c5cb 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1794,16 +1794,14 @@ impl Clean for hir::Ty { 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() - .cloned() { + 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() - .cloned() { + if let Some(lt) = provided_params.lifetimes.get(i).cloned() { if !lt.is_elided() { lt_substs.insert(lt_param.lifetime.id, lt.clean(cx)); } @@ -2314,24 +2312,21 @@ pub enum PathParameters { impl Clean for hir::PathParameters { fn clean(&self, cx: &DocContext) -> PathParameters { - match *self { - hir::AngleBracketedParameters(ref data) => { - PathParameters::AngleBracketed { - lifetimes: if data.lifetimes.iter().all(|lt| lt.is_elided()) { - vec![] - } else { - data.lifetimes.clean(cx) - }, - types: data.types.clean(cx), - bindings: data.bindings.clean(cx), - } + if self.parenthesized { + let output = self.bindings[0].ty.clean(cx); + PathParameters::Parenthesized { + inputs: self.inputs().clean(cx), + output: if output != Type::Tuple(Vec::new()) { Some(output) } else { None } } - - hir::ParenthesizedParameters(ref data) => { - PathParameters::Parenthesized { - inputs: data.inputs.clean(cx), - output: data.output.clean(cx), - } + } else { + PathParameters::AngleBracketed { + lifetimes: if self.lifetimes.iter().all(|lt| lt.is_elided()) { + vec![] + } else { + self.lifetimes.clean(cx) + }, + types: self.types.clean(cx), + bindings: self.bindings.clean(cx), } } } diff --git a/src/test/compile-fail/associated-types-eq-expr-path.rs b/src/test/compile-fail/associated-types-eq-expr-path.rs index 1f9dfdb1847..847393ba2b8 100644 --- a/src/test/compile-fail/associated-types-eq-expr-path.rs +++ b/src/test/compile-fail/associated-types-eq-expr-path.rs @@ -22,5 +22,5 @@ impl Foo for isize { pub fn main() { let x: isize = Foo::::bar(); - //~^ ERROR unexpected binding of associated item in expression path + //~^ ERROR associated type bindings are not allowed here } diff --git a/src/test/compile-fail/issue-43431.rs b/src/test/compile-fail/issue-43431.rs new file mode 100644 index 00000000000..e9f62152888 --- /dev/null +++ b/src/test/compile-fail/issue-43431.rs @@ -0,0 +1,24 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(fn_traits)] + +trait CallSingle { + fn call(&self, a: A) -> B where Self: Fn(A) -> B; +} + +impl B> CallSingle for F { + fn call(&self, a: A) -> B { + B>::call(self, (a,)) + //~^ ERROR associated type bindings are not allowed here + } +} + +fn main() {} diff --git a/src/test/compile-fail/method-call-type-binding.rs b/src/test/compile-fail/method-call-type-binding.rs index 3ae878ed1cb..6c0793ee78f 100644 --- a/src/test/compile-fail/method-call-type-binding.rs +++ b/src/test/compile-fail/method-call-type-binding.rs @@ -9,5 +9,5 @@ // except according to those terms. fn main() { - 0.clone::(); //~ ERROR unexpected binding of associated item + 0.clone::(); //~ ERROR associated type bindings are not allowed here } diff --git a/src/test/compile-fail/unboxed-closure-sugar-used-on-struct.rs b/src/test/compile-fail/unboxed-closure-sugar-used-on-struct.rs index fd6c8ad08d6..5fcde4facbe 100644 --- a/src/test/compile-fail/unboxed-closure-sugar-used-on-struct.rs +++ b/src/test/compile-fail/unboxed-closure-sugar-used-on-struct.rs @@ -16,6 +16,7 @@ struct Bar { fn foo(b: Box) { //~^ ERROR parenthesized parameters may only be used with a trait + //~| ERROR the type placeholder `_` is not allowed within types on item signatures } fn main() { }