diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index a1dd2caf786c207951ab26e97024d7e13734be44..3e227872848efb36efcd10ac1cde8ef167f5787e 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -346,6 +346,7 @@ fn hash_stable(&self, // `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 @@ fn hash_stable(&self, regions.hash_stable(hcx, hasher); types.hash_stable(hcx, hasher); has_self.hash_stable(hcx, hasher); + has_late_bound_regions.hash_stable(hcx, hasher); } } diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 2d088c4f6d1727729aaccd4d065e33b28669f985..cbe642a9a76a65b3afca29288f97de502778745e 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -204,6 +204,12 @@ "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 @@ fn get_lints(&self) -> LintArray { LEGACY_CONSTRUCTOR_VISIBILITY, MISSING_FRAGMENT_SPECIFIER, PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES, + LATE_BOUND_LIFETIME_ARGUMENTS, DEPRECATED ) } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 5aaba526e265f8a40b5494f0a49cb7dc592de58d..1fee0dd98634ae3af07784b751bb122348240322 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -719,6 +719,7 @@ pub struct Generics { pub type_param_to_index: BTreeMap, pub has_self: bool, + pub has_late_bound_regions: bool, } impl Generics { diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index a03f12c3dfbca09dd054c2f732c4a6cda7bcd5f9..21dca7f6c61c413234671a38817e6aabba2c9231 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -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 ", - } + }, + FutureIncompatibleInfo { + id: LintId::of(LATE_BOUND_LIFETIME_ARGUMENTS), + reference: "issue #42868 ", + }, ]); // Register renamed and removed lints diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 72c7b92fe6e309e149eed66844ccb2f526a51c4f..99a49dbd7d732122c8a458ef8cac9804d5488005 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -127,18 +127,9 @@ fn visit_expr(&mut self, expr: &'a Expr) { } 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(..) => { - self.err_handler().span_err(expr.span, - "parenthesized parameters cannot be used on method calls"); - } + if let PathParameters::Parenthesized(..) = **params { + self.err_handler().span_err(expr.span, + "parenthesized parameters cannot be used on method calls"); } } } diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 0829951e12debfdaaed9d6d6d15f6aa5c89fc109..ad4ee5a9d6dcf2c7dea25f84cf8c0616edc94a9a 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -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 @@ fn extract_existential_trait_ref(&mut self, self_ty: Ty<'tcx>, mut closure 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) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index cdbe5e14e90948fabb469189226f1d6465283578..af11cacb247b6b6b90bef620d7a28e58b0768893 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4491,8 +4491,8 @@ pub fn instantiate_value_path(&self, // 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 @@ pub fn instantiate_value_path(&self, /// 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 @@ fn check_path_parameter_count(&self, 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 @@ fn check_path_parameter_count(&self, 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 @@ fn check_path_parameter_count(&self, // 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 @@ fn check_path_parameter_count(&self, "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(&self, sp: Span, ty: Ty<'tcx>, f: F) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 002a148c459a3be506f7196e64ee7b91b8ab3f1b..72bd084330dd3ca62d92373d351431533685dd09 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -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), }) } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 87e59683fd2a8d49a40593051312a84bad1f7211..1e26a734e7640d8e90765077522e6dba4ffade1d 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -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::(); // 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(&self, v: &[T]) -> usize { - v.len() - } -} - -fn main() { - let x = Test; - let v = &[0]; - - x.method::(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(&self, v: &[T]) -> usize { - v.len() - } -} - -fn main() { - let x = Test; - let v = &[0]; - - x.method::(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(&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 @@ fn i_am_a_function() {} } register_diagnostics! { +// E0035, merged into E0087/E0089 +// E0036, merged into E0087/E0089 // E0068, // E0085, // E0086, diff --git a/src/test/compile-fail/E0088.rs b/src/test/compile-fail/E0088.rs index de188677a1121ba4513916fa06d8313b6dd92902..db84a4edc487c98914f839dd8e9f92415f2d8a65 100644 --- a/src/test/compile-fail/E0088.rs +++ b/src/test/compile-fail/E0088.rs @@ -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 } diff --git a/src/test/compile-fail/constructor-lifetime-args.rs b/src/test/compile-fail/constructor-lifetime-args.rs new file mode 100644 index 0000000000000000000000000000000000000000..50db9707355f4e69c2321fa639fbf9d959ae7eba --- /dev/null +++ b/src/test/compile-fail/constructor-lifetime-args.rs @@ -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 or the MIT license +// , 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::` is interpreted kinda like an associated item `S::::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 +} diff --git a/src/test/compile-fail/method-call-lifetime-args-lint.rs b/src/test/compile-fail/method-call-lifetime-args-lint.rs new file mode 100644 index 0000000000000000000000000000000000000000..b2a94e0af420d41a5b045e96521bf4df02a93335 --- /dev/null +++ b/src/test/compile-fail/method-call-lifetime-args-lint.rs @@ -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 or the MIT license +// , 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 Fn(&'late u8)>) + -> &'a u8 { loop {} } + fn early_tricky_implicit<'a>(_: fn(&u8), + _: Box) + -> &'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() {} diff --git a/src/test/compile-fail/E0036.rs b/src/test/compile-fail/method-call-lifetime-args-subst-index.rs similarity index 55% rename from src/test/compile-fail/E0036.rs rename to src/test/compile-fail/method-call-lifetime-args-subst-index.rs index ecb6dac66f218f138ec68d2d1029091438669ffe..a9505e4f936a1b5bfe89ab821225fdc4002ced45 100644 --- a/src/test/compile-fail/E0036.rs +++ b/src/test/compile-fail/method-call-lifetime-args-subst-index.rs @@ -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(&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::(v); //~ ERROR E0036 - //~| NOTE Passed 2 type arguments, expected 1 +fn test() { + S.early_and_type::(); } + +#[rustc_error] +fn main() {} //~ ERROR compilation successful diff --git a/src/test/compile-fail/E0035.rs b/src/test/compile-fail/method-call-lifetime-args-unresolved.rs similarity index 63% rename from src/test/compile-fail/E0035.rs rename to src/test/compile-fail/method-call-lifetime-args-unresolved.rs index 9322d21d2a88d325d5913cd989aa93eae3fe4223..4910bfaf4f60d7c98830968b0dc08881c8fd08bc 100644 --- a/src/test/compile-fail/E0035.rs +++ b/src/test/compile-fail/method-call-lifetime-args-unresolved.rs @@ -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::(); //~ ERROR E0035 - //~| NOTE called with unneeded type parameters + 0.clone::<'a>(); //~ ERROR use of undeclared lifetime name `'a` } diff --git a/src/test/compile-fail/method-call-lifetime-args.rs b/src/test/compile-fail/method-call-lifetime-args.rs new file mode 100644 index 0000000000000000000000000000000000000000..f0a87c7470386b3f3500e2bead3446e0d3ef7ce7 --- /dev/null +++ b/src/test/compile-fail/method-call-lifetime-args.rs @@ -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 or the MIT license +// , 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::(); + 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::(S); + S::life_and_type::<'static, u8>(S); +} + +fn main() {} diff --git a/src/test/compile-fail/method-call-type-binding.rs b/src/test/compile-fail/method-call-type-binding.rs index acffb06ebecf2cc4cbfdef6441e2cd8cf9d1190a..3ae878ed1cbc0659929d47885f8daaa90ce154ab 100644 --- a/src/test/compile-fail/method-call-type-binding.rs +++ b/src/test/compile-fail/method-call-type-binding.rs @@ -9,5 +9,5 @@ // except according to those terms. fn main() { - 0.clone::(); //~ ERROR type bindings cannot be used in method calls + 0.clone::(); //~ ERROR unexpected binding of associated item } diff --git a/src/test/compile-fail/trait-test-2.rs b/src/test/compile-fail/trait-test-2.rs index 2d4df77f960452a126928ce40ee05fb108324012..b08aab6da852a71c6dfd3db0dce616c0d737a18b 100644 --- a/src/test/compile-fail/trait-test-2.rs +++ b/src/test/compile-fail/trait-test-2.rs @@ -15,9 +15,8 @@ impl bar for i32 { fn dup(&self) -> i32 { *self } fn blah(&self) {} } impl bar for u32 { fn dup(&self) -> u32 { *self } fn blah(&self) {} } fn main() { - 10.dup::(); //~ ERROR does not take type parameters - 10.blah::(); - //~^ ERROR incorrect number of type parameters given for this method: expected 1, found 2 + 10.dup::(); //~ ERROR expected at most 0 type parameters, found 1 type parameter + 10.blah::(); //~ ERROR expected at most 1 type parameter, found 2 type parameters (box 10 as Box).dup(); //~^ ERROR E0038 //~| ERROR E0038 diff --git a/src/test/incremental/hashes/inherent_impls.rs b/src/test/incremental/hashes/inherent_impls.rs index 899aefa24a033b0e3d4eeeb666b96c7e3b9c86d2..daddc0c9f5459a3af5c09c80158be76b96651db5 100644 --- a/src/test/incremental/hashes/inherent_impls.rs +++ b/src/test/incremental/hashes/inherent_impls.rs @@ -369,7 +369,7 @@ pub fn add_lifetime_parameter_to_method(&self) { } 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) { } } diff --git a/src/test/incremental/hashes/trait_defs.rs b/src/test/incremental/hashes/trait_defs.rs index e47556a790b62652835cc525e652fb5e69536da2..44950ee8a601f90865698e22d955bc9a07344bf5 100644 --- a/src/test/incremental/hashes/trait_defs.rs +++ b/src/test/incremental/hashes/trait_defs.rs @@ -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>(); }