mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 00:34:06 +00:00
Auto merge of #42492 - petrochenkov:methlife, r=nikomatsakis
Support generic lifetime arguments in method calls Fixes https://github.com/rust-lang/rust/issues/42403 Fixes https://github.com/rust-lang/rust/issues/42115 Lifetimes in a method call `x.f::<'a, 'b, T, U>()` are treated exactly like lifetimes in the equivalent UFCS call `X::f::<'a, 'b, T, U>`. In addition, if the method has late bound lifetime parameters (explicit or implicit), then explicitly specifying lifetime arguments is not permitted (guarded by a compatibility lint). [breaking-change] because previously lifetimes in method calls were accepted unconditionally. r? @eddyb
This commit is contained in:
commit
83c659ef65
@ -346,6 +346,7 @@ impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for ty::Ge
|
||||
// `def_id.index` (`def_id.krate` is the same as the item's).
|
||||
type_param_to_index: _, // Don't hash this
|
||||
has_self,
|
||||
has_late_bound_regions,
|
||||
} = *self;
|
||||
|
||||
parent.hash_stable(hcx, hasher);
|
||||
@ -354,6 +355,7 @@ impl<'a, 'gcx, 'tcx> HashStable<StableHashingContext<'a, 'gcx, 'tcx>> for ty::Ge
|
||||
regions.hash_stable(hcx, hasher);
|
||||
types.hash_stable(hcx, hasher);
|
||||
has_self.hash_stable(hcx, hasher);
|
||||
has_late_bound_regions.hash_stable(hcx, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -204,6 +204,12 @@ declare_lint! {
|
||||
"detects parenthesized generic parameters in type and module names"
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
pub LATE_BOUND_LIFETIME_ARGUMENTS,
|
||||
Warn,
|
||||
"detects generic lifetime arguments in path segments with late bound lifetime parameters"
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
pub DEPRECATED,
|
||||
Warn,
|
||||
@ -249,6 +255,7 @@ impl LintPass for HardwiredLints {
|
||||
LEGACY_CONSTRUCTOR_VISIBILITY,
|
||||
MISSING_FRAGMENT_SPECIFIER,
|
||||
PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES,
|
||||
LATE_BOUND_LIFETIME_ARGUMENTS,
|
||||
DEPRECATED
|
||||
)
|
||||
}
|
||||
|
@ -719,6 +719,7 @@ pub struct Generics {
|
||||
pub type_param_to_index: BTreeMap<DefIndex, u32>,
|
||||
|
||||
pub has_self: bool,
|
||||
pub has_late_bound_regions: bool,
|
||||
}
|
||||
|
||||
impl Generics {
|
||||
|
@ -235,7 +235,11 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
|
||||
FutureIncompatibleInfo {
|
||||
id: LintId::of(PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES),
|
||||
reference: "issue #42238 <https://github.com/rust-lang/rust/issues/42238>",
|
||||
}
|
||||
},
|
||||
FutureIncompatibleInfo {
|
||||
id: LintId::of(LATE_BOUND_LIFETIME_ARGUMENTS),
|
||||
reference: "issue #42868 <https://github.com/rust-lang/rust/issues/42868>",
|
||||
},
|
||||
]);
|
||||
|
||||
// Register renamed and removed lints
|
||||
|
@ -127,21 +127,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
}
|
||||
ExprKind::MethodCall(ref segment, ..) => {
|
||||
if let Some(ref params) = segment.parameters {
|
||||
match **params {
|
||||
PathParameters::AngleBracketed(ref param_data) => {
|
||||
if !param_data.bindings.is_empty() {
|
||||
let binding_span = param_data.bindings[0].span;
|
||||
self.err_handler().span_err(binding_span,
|
||||
"type bindings cannot be used in method calls");
|
||||
}
|
||||
}
|
||||
PathParameters::Parenthesized(..) => {
|
||||
if let PathParameters::Parenthesized(..) = **params {
|
||||
self.err_handler().span_err(expr.span,
|
||||
"parenthesized parameters cannot be used on method calls");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
use super::{probe, MethodCallee};
|
||||
|
||||
use astconv::AstConv;
|
||||
use check::{FnCtxt, LvalueOp, callee};
|
||||
use hir::def_id::DefId;
|
||||
use rustc::ty::subst::Substs;
|
||||
@ -280,62 +281,38 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
|
||||
fn instantiate_method_substs(&mut self,
|
||||
pick: &probe::Pick<'tcx>,
|
||||
segment: &hir::PathSegment,
|
||||
substs: &Substs<'tcx>)
|
||||
parent_substs: &Substs<'tcx>)
|
||||
-> &'tcx Substs<'tcx> {
|
||||
let supplied_method_types = match segment.parameters {
|
||||
hir::AngleBracketedParameters(ref data) => &data.types,
|
||||
_ => bug!("unexpected generic arguments: {:?}", segment.parameters),
|
||||
};
|
||||
|
||||
// Determine the values for the generic parameters of the method.
|
||||
// If they were not explicitly supplied, just construct fresh
|
||||
// variables.
|
||||
let num_supplied_types = supplied_method_types.len();
|
||||
let method_generics = self.tcx.generics_of(pick.item.def_id);
|
||||
let num_method_types = method_generics.types.len();
|
||||
|
||||
if num_supplied_types > 0 && num_supplied_types != num_method_types {
|
||||
if num_method_types == 0 {
|
||||
struct_span_err!(self.tcx.sess,
|
||||
self.span,
|
||||
E0035,
|
||||
"does not take type parameters")
|
||||
.span_label(self.span, "called with unneeded type parameters")
|
||||
.emit();
|
||||
} else {
|
||||
struct_span_err!(self.tcx.sess,
|
||||
self.span,
|
||||
E0036,
|
||||
"incorrect number of type parameters given for this method: \
|
||||
expected {}, found {}",
|
||||
num_method_types,
|
||||
num_supplied_types)
|
||||
.span_label(self.span,
|
||||
format!("Passed {} type argument{}, expected {}",
|
||||
num_supplied_types,
|
||||
if num_supplied_types != 1 { "s" } else { "" },
|
||||
num_method_types))
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
let mut fn_segment = Some((segment, method_generics));
|
||||
self.fcx.check_path_parameter_count(self.span, &mut fn_segment, true);
|
||||
|
||||
// Create subst for early-bound lifetime parameters, combining
|
||||
// parameters from the type and those from the method.
|
||||
//
|
||||
// FIXME -- permit users to manually specify lifetimes
|
||||
let supplied_start = substs.len() + method_generics.regions.len();
|
||||
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());
|
||||
Substs::for_item(self.tcx, pick.item.def_id, |def, _| {
|
||||
let i = def.index as usize;
|
||||
if i < substs.len() {
|
||||
substs.region_at(i)
|
||||
if i < parent_substs.len() {
|
||||
parent_substs.region_at(i)
|
||||
} else if let Some(lifetime) =
|
||||
supplied_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)
|
||||
}
|
||||
}, |def, cur_substs| {
|
||||
let i = def.index as usize;
|
||||
if i < substs.len() {
|
||||
substs.type_at(i)
|
||||
} else if let Some(ast_ty) = supplied_method_types.get(i - supplied_start) {
|
||||
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()) {
|
||||
self.to_ty(ast_ty)
|
||||
} else {
|
||||
self.type_var_for_def(self.span, def, cur_substs)
|
||||
|
@ -4491,8 +4491,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
// variables. If the user provided some types, we may still need
|
||||
// to add defaults. If the user provided *too many* types, that's
|
||||
// a problem.
|
||||
self.check_path_parameter_count(span, &mut type_segment);
|
||||
self.check_path_parameter_count(span, &mut fn_segment);
|
||||
self.check_path_parameter_count(span, &mut type_segment, false);
|
||||
self.check_path_parameter_count(span, &mut fn_segment, false);
|
||||
|
||||
let (fn_start, has_self) = match (type_segment, fn_segment) {
|
||||
(_, Some((_, generics))) => {
|
||||
@ -4618,7 +4618,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
/// Report errors if the provided parameters are too few or too many.
|
||||
fn check_path_parameter_count(&self,
|
||||
span: Span,
|
||||
segment: &mut Option<(&hir::PathSegment, &ty::Generics)>) {
|
||||
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)) => {
|
||||
@ -4632,6 +4633,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
None => (&[][..], &[][..], true, &[][..])
|
||||
}
|
||||
};
|
||||
let infer_lifetimes = lifetimes.len() == 0;
|
||||
|
||||
let count_lifetime_params = |n| {
|
||||
format!("{} lifetime parameter{}", n, if n == 1 { "" } else { "s" })
|
||||
@ -4640,32 +4642,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
format!("{} type parameter{}", n, if n == 1 { "" } else { "s" })
|
||||
};
|
||||
|
||||
// Check provided lifetime parameters.
|
||||
let lifetime_defs = segment.map_or(&[][..], |(_, generics)| &generics.regions);
|
||||
if lifetimes.len() > lifetime_defs.len() {
|
||||
let expected_text = count_lifetime_params(lifetime_defs.len());
|
||||
let actual_text = count_lifetime_params(lifetimes.len());
|
||||
struct_span_err!(self.tcx.sess, span, E0088,
|
||||
"too many lifetime parameters provided: \
|
||||
expected at most {}, found {}",
|
||||
expected_text, actual_text)
|
||||
.span_label(span, format!("expected {}", expected_text))
|
||||
.emit();
|
||||
} else if lifetimes.len() > 0 && lifetimes.len() < lifetime_defs.len() {
|
||||
let expected_text = count_lifetime_params(lifetime_defs.len());
|
||||
let actual_text = count_lifetime_params(lifetimes.len());
|
||||
struct_span_err!(self.tcx.sess, span, E0090,
|
||||
"too few lifetime parameters provided: \
|
||||
expected {}, found {}",
|
||||
expected_text, actual_text)
|
||||
.span_label(span, format!("expected {}", expected_text))
|
||||
.emit();
|
||||
}
|
||||
|
||||
// The case where there is not enough lifetime parameters is not checked,
|
||||
// because this is not possible - a function never takes lifetime parameters.
|
||||
// See discussion for Pull Request 36208.
|
||||
|
||||
// Check provided type parameters.
|
||||
let type_defs = segment.map_or(&[][..], |(_, generics)| {
|
||||
if generics.parent.is_none() {
|
||||
@ -4690,7 +4666,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
// type parameters, we force instantiate_value_path to
|
||||
// use inference variables instead of the provided types.
|
||||
*segment = None;
|
||||
} else if !infer_types && types.len() < required_len {
|
||||
} else if types.len() < required_len && !infer_types {
|
||||
let expected_text = count_type_params(required_len);
|
||||
let actual_text = count_type_params(types.len());
|
||||
struct_span_err!(self.tcx.sess, span, E0089,
|
||||
@ -4706,6 +4682,51 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
"unexpected binding of associated item in expression path \
|
||||
(only allowed in type paths)");
|
||||
}
|
||||
|
||||
// Check provided lifetime parameters.
|
||||
let lifetime_defs = segment.map_or(&[][..], |(_, generics)| &generics.regions);
|
||||
let required_len = lifetime_defs.len();
|
||||
|
||||
// Prohibit explicit lifetime arguments if late bound lifetime parameters are present.
|
||||
let has_late_bound_lifetime_defs =
|
||||
segment.map_or(false, |(_, generics)| generics.has_late_bound_regions);
|
||||
if has_late_bound_lifetime_defs && !lifetimes.is_empty() {
|
||||
// Report this as a lint only if no error was reported previously.
|
||||
if !is_method_call && (lifetimes.len() > lifetime_defs.len() ||
|
||||
lifetimes.len() < required_len && !infer_lifetimes) {
|
||||
self.tcx.sess.span_err(lifetimes[0].span,
|
||||
"cannot specify lifetime arguments explicitly \
|
||||
if late bound lifetime parameters are present");
|
||||
*segment = None;
|
||||
} else {
|
||||
self.tcx.sess.add_lint(lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS,
|
||||
lifetimes[0].id, lifetimes[0].span,
|
||||
format!("cannot specify lifetime arguments explicitly \
|
||||
if late bound lifetime parameters are present"));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if lifetimes.len() > lifetime_defs.len() {
|
||||
let span = lifetimes[lifetime_defs.len()].span;
|
||||
let expected_text = count_lifetime_params(lifetime_defs.len());
|
||||
let actual_text = count_lifetime_params(lifetimes.len());
|
||||
struct_span_err!(self.tcx.sess, span, E0088,
|
||||
"too many lifetime parameters provided: \
|
||||
expected at most {}, found {}",
|
||||
expected_text, actual_text)
|
||||
.span_label(span, format!("expected {}", expected_text))
|
||||
.emit();
|
||||
} else if lifetimes.len() < required_len && !infer_lifetimes {
|
||||
let expected_text = count_lifetime_params(lifetime_defs.len());
|
||||
let actual_text = count_lifetime_params(lifetimes.len());
|
||||
struct_span_err!(self.tcx.sess, span, E0090,
|
||||
"too few lifetime parameters provided: \
|
||||
expected {}, found {}",
|
||||
expected_text, actual_text)
|
||||
.span_label(span, format!("expected {}", expected_text))
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
fn structurally_resolve_type_or_else<F>(&self, sp: Span, ty: Ty<'tcx>, f: F)
|
||||
|
@ -772,6 +772,95 @@ fn trait_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
tcx.alloc_trait_def(def)
|
||||
}
|
||||
|
||||
fn has_late_bound_regions<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
node: hir_map::Node<'tcx>)
|
||||
-> bool {
|
||||
struct LateBoundRegionsDetector<'a, 'tcx: 'a> {
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
binder_depth: u32,
|
||||
has_late_bound_regions: bool,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for LateBoundRegionsDetector<'a, 'tcx> {
|
||||
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
|
||||
NestedVisitorMap::None
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
|
||||
if self.has_late_bound_regions { return }
|
||||
match ty.node {
|
||||
hir::TyBareFn(..) => {
|
||||
self.binder_depth += 1;
|
||||
intravisit::walk_ty(self, ty);
|
||||
self.binder_depth -= 1;
|
||||
}
|
||||
_ => intravisit::walk_ty(self, ty)
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_poly_trait_ref(&mut self,
|
||||
tr: &'tcx hir::PolyTraitRef,
|
||||
m: hir::TraitBoundModifier) {
|
||||
if self.has_late_bound_regions { return }
|
||||
self.binder_depth += 1;
|
||||
intravisit::walk_poly_trait_ref(self, tr, m);
|
||||
self.binder_depth -= 1;
|
||||
}
|
||||
|
||||
fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) {
|
||||
if self.has_late_bound_regions { return }
|
||||
|
||||
match self.tcx.named_region_map.defs.get(<.id).cloned() {
|
||||
Some(rl::Region::Static) | Some(rl::Region::EarlyBound(..)) => {}
|
||||
Some(rl::Region::LateBound(debruijn, _)) |
|
||||
Some(rl::Region::LateBoundAnon(debruijn, _))
|
||||
if debruijn.depth < self.binder_depth => {}
|
||||
_ => self.has_late_bound_regions = true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn has_late_bound_regions<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
generics: &'tcx hir::Generics,
|
||||
decl: &'tcx hir::FnDecl)
|
||||
-> bool {
|
||||
let mut visitor = LateBoundRegionsDetector {
|
||||
tcx, binder_depth: 1, has_late_bound_regions: false
|
||||
};
|
||||
for lifetime in &generics.lifetimes {
|
||||
if tcx.named_region_map.late_bound.contains(&lifetime.lifetime.id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
visitor.visit_fn_decl(decl);
|
||||
visitor.has_late_bound_regions
|
||||
}
|
||||
|
||||
match node {
|
||||
hir_map::NodeTraitItem(item) => match item.node {
|
||||
hir::TraitItemKind::Method(ref sig, _) =>
|
||||
has_late_bound_regions(tcx, &sig.generics, &sig.decl),
|
||||
_ => false,
|
||||
},
|
||||
hir_map::NodeImplItem(item) => match item.node {
|
||||
hir::ImplItemKind::Method(ref sig, _) =>
|
||||
has_late_bound_regions(tcx, &sig.generics, &sig.decl),
|
||||
_ => false,
|
||||
},
|
||||
hir_map::NodeForeignItem(item) => match item.node {
|
||||
hir::ForeignItemFn(ref fn_decl, _, ref generics) =>
|
||||
has_late_bound_regions(tcx, generics, fn_decl),
|
||||
_ => false,
|
||||
},
|
||||
hir_map::NodeItem(item) => match item.node {
|
||||
hir::ItemFn(ref fn_decl, .., ref generics, _) =>
|
||||
has_late_bound_regions(tcx, generics, fn_decl),
|
||||
_ => false,
|
||||
},
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
def_id: DefId)
|
||||
-> &'tcx ty::Generics {
|
||||
@ -959,7 +1048,8 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
regions: regions,
|
||||
types: types,
|
||||
type_param_to_index: type_param_to_index,
|
||||
has_self: has_self || parent_has_self
|
||||
has_self: has_self || parent_has_self,
|
||||
has_late_bound_regions: has_late_bound_regions(tcx, node),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -332,92 +332,6 @@ fn main() {
|
||||
```
|
||||
"##,
|
||||
|
||||
E0035: r##"
|
||||
You tried to give a type parameter where it wasn't needed. Erroneous code
|
||||
example:
|
||||
|
||||
```compile_fail,E0035
|
||||
struct Test;
|
||||
|
||||
impl Test {
|
||||
fn method(&self) {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = Test;
|
||||
|
||||
x.method::<i32>(); // Error: Test::method doesn't need type parameter!
|
||||
}
|
||||
```
|
||||
|
||||
To fix this error, just remove the type parameter:
|
||||
|
||||
```
|
||||
struct Test;
|
||||
|
||||
impl Test {
|
||||
fn method(&self) {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = Test;
|
||||
|
||||
x.method(); // OK, we're good!
|
||||
}
|
||||
```
|
||||
"##,
|
||||
|
||||
E0036: r##"
|
||||
This error occurrs when you pass too many or not enough type parameters to
|
||||
a method. Erroneous code example:
|
||||
|
||||
```compile_fail,E0036
|
||||
struct Test;
|
||||
|
||||
impl Test {
|
||||
fn method<T>(&self, v: &[T]) -> usize {
|
||||
v.len()
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = Test;
|
||||
let v = &[0];
|
||||
|
||||
x.method::<i32, i32>(v); // error: only one type parameter is expected!
|
||||
}
|
||||
```
|
||||
|
||||
To fix it, just specify a correct number of type parameters:
|
||||
|
||||
```
|
||||
struct Test;
|
||||
|
||||
impl Test {
|
||||
fn method<T>(&self, v: &[T]) -> usize {
|
||||
v.len()
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = Test;
|
||||
let v = &[0];
|
||||
|
||||
x.method::<i32>(v); // OK, we're good!
|
||||
}
|
||||
```
|
||||
|
||||
Please note on the last example that we could have called `method` like this:
|
||||
|
||||
```
|
||||
# struct Test;
|
||||
# impl Test { fn method<T>(&self, v: &[T]) -> usize { v.len() } }
|
||||
# let x = Test;
|
||||
# let v = &[0];
|
||||
x.method(v);
|
||||
```
|
||||
"##,
|
||||
|
||||
E0040: r##"
|
||||
It is not allowed to manually call destructors in Rust. It is also not
|
||||
necessary to do this since `drop` is called automatically whenever a value goes
|
||||
@ -4681,6 +4595,8 @@ error, just declare a function.
|
||||
}
|
||||
|
||||
register_diagnostics! {
|
||||
// E0035, merged into E0087/E0089
|
||||
// E0036, merged into E0087/E0089
|
||||
// E0068,
|
||||
// E0085,
|
||||
// E0086,
|
||||
|
@ -9,14 +9,9 @@
|
||||
// except according to those terms.
|
||||
|
||||
fn f() {}
|
||||
fn g<'a>() {}
|
||||
fn g<'a>() -> &'a u8 { loop {} }
|
||||
|
||||
fn main() {
|
||||
f::<'static>();
|
||||
//~^ ERROR expected at most 0 lifetime parameters, found 1 lifetime parameter [E0088]
|
||||
//~| NOTE expected 0 lifetime parameters
|
||||
|
||||
g::<'static, 'static>();
|
||||
//~^ ERROR expected at most 0 lifetime parameters, found 2 lifetime parameters [E0088]
|
||||
//~| NOTE expected 0 lifetime parameters
|
||||
f::<'static>(); //~ ERROR E0088
|
||||
g::<'static, 'static>(); //~ ERROR E0088
|
||||
}
|
||||
|
36
src/test/compile-fail/constructor-lifetime-args.rs
Normal file
36
src/test/compile-fail/constructor-lifetime-args.rs
Normal file
@ -0,0 +1,36 @@
|
||||
// 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.
|
||||
|
||||
// All lifetime parameters in struct constructors are currently considered early bound,
|
||||
// i.e. `S::<ARGS>` is interpreted kinda like an associated item `S::<ARGS>::ctor`.
|
||||
// This behavior is a bit weird, because if equivalent constructor were written manually
|
||||
// it would get late bound lifetime parameters.
|
||||
// Variant constructors behave in the same way, lifetime parameters are considered
|
||||
// belonging to the enum and being early bound.
|
||||
// https://github.com/rust-lang/rust/issues/30904
|
||||
|
||||
struct S<'a, 'b>(&'a u8, &'b u8);
|
||||
enum E<'a, 'b> {
|
||||
V(&'a u8),
|
||||
U(&'b u8),
|
||||
}
|
||||
|
||||
fn main() {
|
||||
S(&0, &0); // OK
|
||||
S::<'static>(&0, &0);
|
||||
//~^ ERROR expected 2 lifetime parameters, found 1 lifetime parameter
|
||||
S::<'static, 'static, 'static>(&0, &0);
|
||||
//~^ ERROR expected at most 2 lifetime parameters, found 3 lifetime parameters
|
||||
E::V(&0); // OK
|
||||
E::V::<'static>(&0);
|
||||
//~^ ERROR expected 2 lifetime parameters, found 1 lifetime parameter
|
||||
E::V::<'static, 'static, 'static>(&0);
|
||||
//~^ ERROR expected at most 2 lifetime parameters, found 3 lifetime parameters
|
||||
}
|
97
src/test/compile-fail/method-call-lifetime-args-lint.rs
Normal file
97
src/test/compile-fail/method-call-lifetime-args-lint.rs
Normal file
@ -0,0 +1,97 @@
|
||||
// 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.
|
||||
|
||||
#![deny(late_bound_lifetime_arguments)]
|
||||
#![allow(unused)]
|
||||
|
||||
struct S;
|
||||
|
||||
impl S {
|
||||
fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {}
|
||||
fn late_implicit(self, _: &u8, _: &u8) {}
|
||||
fn late_early<'a, 'b>(self, _: &'a u8) -> &'b u8 { loop {} }
|
||||
fn late_implicit_early<'b>(self, _: &u8) -> &'b u8 { loop {} }
|
||||
|
||||
// 'late lifetimes here belong to nested types not to the tested functions.
|
||||
fn early_tricky_explicit<'a>(_: for<'late> fn(&'late u8),
|
||||
_: Box<for<'late> Fn(&'late u8)>)
|
||||
-> &'a u8 { loop {} }
|
||||
fn early_tricky_implicit<'a>(_: fn(&u8),
|
||||
_: Box<Fn(&u8)>)
|
||||
-> &'a u8 { loop {} }
|
||||
}
|
||||
|
||||
fn method_call() {
|
||||
S.late(&0, &0); // OK
|
||||
S.late::<'static>(&0, &0);
|
||||
//~^ ERROR cannot specify lifetime arguments explicitly
|
||||
//~| WARN this was previously accepted
|
||||
S.late::<'static, 'static>(&0, &0);
|
||||
//~^ ERROR cannot specify lifetime arguments explicitly
|
||||
//~| WARN this was previously accepted
|
||||
S.late::<'static, 'static, 'static>(&0, &0);
|
||||
//~^ ERROR cannot specify lifetime arguments explicitly
|
||||
//~| WARN this was previously accepted
|
||||
S.late_early(&0); // OK
|
||||
S.late_early::<'static>(&0);
|
||||
//~^ ERROR cannot specify lifetime arguments explicitly
|
||||
//~| WARN this was previously accepted
|
||||
S.late_early::<'static, 'static>(&0);
|
||||
//~^ ERROR cannot specify lifetime arguments explicitly
|
||||
//~| WARN this was previously accepted
|
||||
S.late_early::<'static, 'static, 'static>(&0);
|
||||
//~^ ERROR cannot specify lifetime arguments explicitly
|
||||
//~| WARN this was previously accepted
|
||||
|
||||
S.late_implicit(&0, &0); // OK
|
||||
S.late_implicit::<'static>(&0, &0);
|
||||
//~^ ERROR cannot specify lifetime arguments explicitly
|
||||
//~| WARN this was previously accepted
|
||||
S.late_implicit::<'static, 'static>(&0, &0);
|
||||
//~^ ERROR cannot specify lifetime arguments explicitly
|
||||
//~| WARN this was previously accepted
|
||||
S.late_implicit::<'static, 'static, 'static>(&0, &0);
|
||||
//~^ ERROR cannot specify lifetime arguments explicitly
|
||||
//~| WARN this was previously accepted
|
||||
S.late_implicit_early(&0); // OK
|
||||
S.late_implicit_early::<'static>(&0);
|
||||
//~^ ERROR cannot specify lifetime arguments explicitly
|
||||
//~| WARN this was previously accepted
|
||||
S.late_implicit_early::<'static, 'static>(&0);
|
||||
//~^ ERROR cannot specify lifetime arguments explicitly
|
||||
//~| WARN this was previously accepted
|
||||
S.late_implicit_early::<'static, 'static, 'static>(&0);
|
||||
//~^ ERROR cannot specify lifetime arguments explicitly
|
||||
//~| WARN this was previously accepted
|
||||
|
||||
S::early_tricky_explicit::<'static>(loop {}, loop {}); // OK
|
||||
S::early_tricky_implicit::<'static>(loop {}, loop {}); // OK
|
||||
}
|
||||
|
||||
fn ufcs() {
|
||||
S::late_early::<'static>(S, &0);
|
||||
//~^ ERROR cannot specify lifetime arguments explicitly
|
||||
//~| WARN this was previously accepted
|
||||
|
||||
S::late_implicit_early::<'static>(S, &0);
|
||||
//~^ ERROR cannot specify lifetime arguments explicitly
|
||||
//~| WARN this was previously accepted
|
||||
}
|
||||
|
||||
fn lint_not_inference_error() {
|
||||
fn f<'early, 'late, T: 'early>() {}
|
||||
|
||||
// Make sure `u8` is substituted and not replaced with an inference variable
|
||||
f::<'static, u8>;
|
||||
//~^ ERROR cannot specify lifetime arguments explicitly
|
||||
//~| WARN this was previously accepted
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// 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.
|
||||
//
|
||||
@ -8,17 +8,18 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
struct Test;
|
||||
#![feature(rustc_attrs)]
|
||||
#![allow(unused)]
|
||||
|
||||
impl Test {
|
||||
fn method<T>(&self, v: &[T]) -> usize {
|
||||
v.len()
|
||||
}
|
||||
struct S;
|
||||
|
||||
impl S {
|
||||
fn early_and_type<'a, T>(self) -> &'a T { loop {} }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = Test;
|
||||
let v = &[0];
|
||||
x.method::<i32, i32>(v); //~ ERROR E0036
|
||||
//~| NOTE Passed 2 type arguments, expected 1
|
||||
fn test() {
|
||||
S.early_and_type::<u16>();
|
||||
}
|
||||
|
||||
#[rustc_error]
|
||||
fn main() {} //~ ERROR compilation successful
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// 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.
|
||||
//
|
||||
@ -8,14 +8,6 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
struct Test;
|
||||
|
||||
impl Test {
|
||||
fn method(&self) {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = Test;
|
||||
x.method::<i32>(); //~ ERROR E0035
|
||||
//~| NOTE called with unneeded type parameters
|
||||
0.clone::<'a>(); //~ ERROR use of undeclared lifetime name `'a`
|
||||
}
|
82
src/test/compile-fail/method-call-lifetime-args.rs
Normal file
82
src/test/compile-fail/method-call-lifetime-args.rs
Normal file
@ -0,0 +1,82 @@
|
||||
// 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.
|
||||
|
||||
struct S;
|
||||
|
||||
impl S {
|
||||
fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {}
|
||||
fn late_implicit(self, _: &u8, _: &u8) {}
|
||||
fn early<'a, 'b>(self) -> (&'a u8, &'b u8) { loop {} }
|
||||
fn late_early<'a, 'b>(self, _: &'a u8) -> &'b u8 { loop {} }
|
||||
fn late_implicit_early<'b>(self, _: &u8) -> &'b u8 { loop {} }
|
||||
fn late_implicit_self_early<'b>(&self) -> &'b u8 { loop {} }
|
||||
fn late_unused_early<'a, 'b>(self) -> &'b u8 { loop {} }
|
||||
fn life_and_type<'a, T>(self) -> &'a T { loop {} }
|
||||
}
|
||||
|
||||
fn method_call() {
|
||||
S.early(); // OK
|
||||
S.early::<'static>();
|
||||
//~^ ERROR expected 2 lifetime parameters, found 1 lifetime parameter
|
||||
S.early::<'static, 'static, 'static>();
|
||||
//~^ ERROR expected at most 2 lifetime parameters, found 3 lifetime parameters
|
||||
let _: &u8 = S.life_and_type::<'static>();
|
||||
S.life_and_type::<u8>();
|
||||
S.life_and_type::<'static, u8>();
|
||||
}
|
||||
|
||||
fn ufcs() {
|
||||
S::late(S, &0, &0); // OK
|
||||
S::late::<'static>(S, &0, &0);
|
||||
//~^ ERROR cannot specify lifetime arguments explicitly
|
||||
S::late::<'static, 'static>(S, &0, &0);
|
||||
//~^ ERROR cannot specify lifetime arguments explicitly
|
||||
S::late::<'static, 'static, 'static>(S, &0, &0);
|
||||
//~^ ERROR cannot specify lifetime arguments explicitly
|
||||
S::late_early(S, &0); // OK
|
||||
S::late_early::<'static, 'static>(S, &0);
|
||||
//~^ ERROR cannot specify lifetime arguments explicitly
|
||||
S::late_early::<'static, 'static, 'static>(S, &0);
|
||||
//~^ ERROR cannot specify lifetime arguments explicitly
|
||||
|
||||
S::late_implicit(S, &0, &0); // OK
|
||||
S::late_implicit::<'static>(S, &0, &0);
|
||||
//~^ ERROR cannot specify lifetime arguments explicitly
|
||||
S::late_implicit::<'static, 'static>(S, &0, &0);
|
||||
//~^ ERROR cannot specify lifetime arguments explicitly
|
||||
S::late_implicit::<'static, 'static, 'static>(S, &0, &0);
|
||||
//~^ ERROR cannot specify lifetime arguments explicitly
|
||||
S::late_implicit_early(S, &0); // OK
|
||||
S::late_implicit_early::<'static, 'static>(S, &0);
|
||||
//~^ ERROR cannot specify lifetime arguments explicitly
|
||||
S::late_implicit_early::<'static, 'static, 'static>(S, &0);
|
||||
//~^ ERROR cannot specify lifetime arguments explicitly
|
||||
S::late_implicit_self_early(&S); // OK
|
||||
S::late_implicit_self_early::<'static, 'static>(&S);
|
||||
//~^ ERROR cannot specify lifetime arguments explicitly
|
||||
S::late_implicit_self_early::<'static, 'static, 'static>(&S);
|
||||
//~^ ERROR cannot specify lifetime arguments explicitly
|
||||
S::late_unused_early(S); // OK
|
||||
S::late_unused_early::<'static, 'static>(S);
|
||||
//~^ ERROR cannot specify lifetime arguments explicitly
|
||||
S::late_unused_early::<'static, 'static, 'static>(S);
|
||||
//~^ ERROR cannot specify lifetime arguments explicitly
|
||||
|
||||
S::early(S); // OK
|
||||
S::early::<'static>(S);
|
||||
//~^ ERROR expected 2 lifetime parameters, found 1 lifetime parameter
|
||||
S::early::<'static, 'static, 'static>(S);
|
||||
//~^ ERROR expected at most 2 lifetime parameters, found 3 lifetime parameters
|
||||
let _: &u8 = S::life_and_type::<'static>(S);
|
||||
S::life_and_type::<u8>(S);
|
||||
S::life_and_type::<'static, u8>(S);
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -9,5 +9,5 @@
|
||||
// except according to those terms.
|
||||
|
||||
fn main() {
|
||||
0.clone::<T = u8>(); //~ ERROR type bindings cannot be used in method calls
|
||||
0.clone::<T = u8>(); //~ ERROR unexpected binding of associated item
|
||||
}
|
||||
|
@ -15,9 +15,8 @@ impl bar for i32 { fn dup(&self) -> i32 { *self } fn blah<X>(&self) {} }
|
||||
impl bar for u32 { fn dup(&self) -> u32 { *self } fn blah<X>(&self) {} }
|
||||
|
||||
fn main() {
|
||||
10.dup::<i32>(); //~ ERROR does not take type parameters
|
||||
10.blah::<i32, i32>();
|
||||
//~^ ERROR incorrect number of type parameters given for this method: expected 1, found 2
|
||||
10.dup::<i32>(); //~ ERROR expected at most 0 type parameters, found 1 type parameter
|
||||
10.blah::<i32, i32>(); //~ ERROR expected at most 1 type parameter, found 2 type parameters
|
||||
(box 10 as Box<bar>).dup();
|
||||
//~^ ERROR E0038
|
||||
//~| ERROR E0038
|
||||
|
@ -369,7 +369,7 @@ impl Foo {
|
||||
impl Foo {
|
||||
#[rustc_dirty(label="Hir", cfg="cfail2")]
|
||||
#[rustc_clean(label="Hir", cfg="cfail3")]
|
||||
#[rustc_metadata_clean(cfg="cfail2")] // Apparently unused lifetimes don't show up in the type.
|
||||
#[rustc_metadata_clean(cfg="cfail2")]
|
||||
#[rustc_metadata_clean(cfg="cfail3")]
|
||||
pub fn add_lifetime_parameter_to_method<'a>(&self) { }
|
||||
}
|
||||
|
@ -448,7 +448,7 @@ trait TraitAddLifetimeParameterToMethod {
|
||||
trait TraitAddLifetimeParameterToMethod {
|
||||
#[rustc_dirty(label="Hir", cfg="cfail2")]
|
||||
#[rustc_clean(label="Hir", cfg="cfail3")]
|
||||
#[rustc_metadata_clean(cfg="cfail2")] // Unused lifetimes don't seem to show up in type?
|
||||
#[rustc_metadata_dirty(cfg="cfail2")]
|
||||
#[rustc_metadata_clean(cfg="cfail3")]
|
||||
fn method<'a>();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user