Auto merge of #43532 - 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:
commit
a12e4f8098
src
librustc
librustc_driver
librustc_passes
librustc_typeck
librustdoc/clean
test/compile-fail
@ -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.
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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(">")?
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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<hir::Ty>],
|
||||
|
@ -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();
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
24
src/test/compile-fail/issue-43431.rs
Normal file
24
src/test/compile-fail/issue-43431.rs
Normal 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() {}
|
@ -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
|
||||
}
|
||||
|
@ -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() { }
|
||||
|
Loading…
Reference in New Issue
Block a user