Auto merge of - petrochenkov:pgargs, r=nikomatsakis

Desugar parenthesized generic arguments in HIR

Fixes ICE in https://github.com/rust-lang/rust/issues/43431 and maybe some other similar issues.

r? @eddyb
This commit is contained in:
bors 2017-08-24 03:48:25 +00:00
commit a12e4f8098
18 changed files with 266 additions and 440 deletions

View File

@ -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.

View File

@ -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,

View File

@ -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. `<<std::vec::Vec<T>>::IntoIter>::Item`
// * final path is `<<<std::vec::Vec<T>>::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)
}

View File

@ -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<Ty>> {
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<Lifetime>,
/// 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<A=Bar>`.
pub bindings: HirVec<TypeBinding>,
/// 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<P<Ty>>,
/// `C`
pub output: Option<P<Ty>>,
pub fn inputs(&self) -> &[P<Ty>] {
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.

View File

@ -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(&parameters.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 &parameters.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, &parameters.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(">")?
}
}

View File

@ -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 {

View File

@ -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(&params.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(&params.lifetimes);
} else {
for l in &data.lifetimes { self.visit_lifetime(l); }
for l in &params.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(&params.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(&lt) = 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 &params.bindings { self.visit_assoc_type_binding(b); }
}
fn visit_fn_like_elision(&mut self, inputs: &'tcx [P<hir::Ty>],

View File

@ -833,10 +833,6 @@ pub fn phase_2_configure_and_expand<F>(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<F>(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();

View File

@ -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");
}
}
}
_ => {}
}

View File

@ -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(&parameters.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 {

View File

@ -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)

View File

@ -4620,11 +4620,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))
@ -4647,13 +4643,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 {
@ -4727,19 +4719,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| {
@ -4785,9 +4768,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.

View File

@ -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::<A=usize>::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 = <isize as Foo>::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

View File

@ -1794,16 +1794,14 @@ impl Clean<Type> 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<PathParameters> 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),
}
}
}

View File

@ -22,5 +22,5 @@ impl Foo for isize {
pub fn main() {
let x: isize = Foo::<A=usize>::bar();
//~^ ERROR unexpected binding of associated item in expression path
//~^ ERROR associated type bindings are not allowed here
}

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(fn_traits)]
trait CallSingle<A, B> {
fn call(&self, a: A) -> B where Self: Fn(A) -> B;
}
impl<A, B, F: Fn(A) -> B> CallSingle<A, B> for F {
fn call(&self, a: A) -> B {
<Self as Fn(A) -> B>::call(self, (a,))
//~^ ERROR associated type bindings are not allowed here
}
}
fn main() {}

View File

@ -9,5 +9,5 @@
// except according to those terms.
fn main() {
0.clone::<T = u8>(); //~ ERROR unexpected binding of associated item
0.clone::<T = u8>(); //~ ERROR associated type bindings are not allowed here
}

View File

@ -16,6 +16,7 @@ struct Bar<A> {
fn foo(b: Box<Bar()>) {
//~^ ERROR parenthesized parameters may only be used with a trait
//~| ERROR the type placeholder `_` is not allowed within types on item signatures
}
fn main() { }