diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 3cd435e756e..2573a967985 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -17,6 +17,7 @@ use rustc_data_structures::array_vec::ArrayVec; use hir::{self, GenericArg, GenericArgs}; use hir::def::Def; use hir::def_id::DefId; +use hir::HirVec; use middle::resolve_lifetime as rl; use namespace::Namespace; use rustc::ty::subst::{Kind, Subst, Substs}; @@ -34,6 +35,7 @@ use lint; use std::iter; use syntax::ast; +use syntax::ptr::P; use syntax::feature_gate::{GateIssue, emit_feature_err}; use syntax_pos::{Span, MultiSpan}; @@ -90,9 +92,9 @@ struct ConvertedBinding<'tcx> { span: Span, } -pub struct GenericArgMismatchErrorCode { - pub lifetimes: (&'static str, &'static str), - pub types: (&'static str, &'static str), +struct GenericArgMismatchErrorCode { + lifetimes: (&'static str, &'static str), + types: (&'static str, &'static str), } /// Dummy type used for the `Self` of a `TraitRef` created for converting @@ -193,9 +195,72 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { substs } + /// Report error if there is an explicit type parameter when using `impl Trait`. + fn check_impl_trait( + tcx: TyCtxt, + span: Span, + seg: &hir::PathSegment, + generics: &ty::Generics, + ) -> bool { + let explicit = !seg.infer_types; + let impl_trait = generics.params.iter().any(|param| match param.kind { + ty::GenericParamDefKind::Type { + synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), .. + } => true, + _ => false, + }); + + if explicit && impl_trait { + let mut err = struct_span_err! { + tcx.sess, + span, + E0632, + "cannot provide explicit type parameters when `impl Trait` is \ + used in argument position." + }; + + err.emit(); + } + + impl_trait + } + + /// Check that the correct number of generic arguments have been provided. + /// Used specifically for function calls. + pub fn check_generic_arg_count_for_call( + tcx: TyCtxt, + span: Span, + def: &ty::Generics, + seg: &hir::PathSegment, + is_method_call: bool, + ) -> bool { + let empty_args = P(hir::GenericArgs { + args: HirVec::new(), bindings: HirVec::new(), parenthesized: false, + }); + let suppress_mismatch = Self::check_impl_trait(tcx, span, seg, &def); + Self::check_generic_arg_count( + tcx, + span, + def, + if let Some(ref args) = seg.args { + args + } else { + &empty_args + }, + false, // `is_declaration` + is_method_call, + def.parent.is_none() && def.has_self, // `has_self` + seg.infer_types || suppress_mismatch, // `infer_types` + GenericArgMismatchErrorCode { + lifetimes: ("E0090", "E0088"), + types: ("E0089", "E0087"), + }, + ) + } + /// Check that the correct number of generic arguments have been provided. /// This is used both for type declarations and function calls. - pub fn check_generic_arg_count( + fn check_generic_arg_count( tcx: TyCtxt, span: Span, def: &ty::Generics, diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 88c540915af..e848508b8c0 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -10,11 +10,10 @@ use super::{probe, MethodCallee}; -use astconv::{AstConv, GenericArgMismatchErrorCode}; +use astconv::AstConv; use check::{FnCtxt, PlaceOp, callee, Needs}; use hir::GenericArg; use hir::def_id::DefId; -use hir::HirVec; use rustc::ty::subst::Substs; use rustc::traits; use rustc::ty::{self, Ty, GenericParamDefKind}; @@ -25,7 +24,6 @@ use rustc::ty::fold::TypeFoldable; use rustc::infer::{self, InferOk}; use rustc::hir; use syntax_pos::Span; -use syntax::ptr::P; use std::ops::Deref; @@ -310,34 +308,24 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { fn instantiate_method_substs( &mut self, pick: &probe::Pick<'tcx>, - segment: &hir::PathSegment, + seg: &hir::PathSegment, parent_substs: &Substs<'tcx>, ) -> &'tcx Substs<'tcx> { // Determine the values for the generic parameters of the method. // If they were not explicitly supplied, just construct fresh // variables. - let method_generics = self.tcx.generics_of(pick.item.def_id); - let suppress_mismatch = self.fcx.check_impl_trait(self.span, segment, &method_generics); - AstConv::check_generic_arg_count( + let generics = self.tcx.generics_of(pick.item.def_id); + AstConv::check_generic_arg_count_for_call( self.tcx, self.span, - &method_generics, - &segment.args.clone().unwrap_or_else(|| P(hir::GenericArgs { - args: HirVec::new(), bindings: HirVec::new(), parenthesized: false, - })), - false, // `is_declaration` + &generics, + &seg, true, // `is_method_call` - method_generics.parent.is_none() && method_generics.has_self, - segment.infer_types || suppress_mismatch, - GenericArgMismatchErrorCode { - lifetimes: ("E0090", "E0088"), - types: ("E0089", "E0087"), - }, ); // Create subst for early-bound lifetime parameters, combining // parameters from the type and those from the method. - assert_eq!(method_generics.parent_count, parent_substs.len()); + assert_eq!(generics.parent_count, parent_substs.len()); AstConv::create_substs_for_generic_args( self.tcx, @@ -348,7 +336,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // Provide the generic args, and whether types should be inferred. |_| { // The last argument of the returned tuple here is unimportant. - if let Some(ref data) = segment.args { + if let Some(ref data) = seg.args { (Some(data), false) } else { (None, false) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 17adfda0bac..3ed42b6b261 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -84,10 +84,9 @@ pub use self::compare_method::{compare_impl_method, compare_const_impl}; use self::method::MethodCallee; use self::TupleArgumentsFlag::*; -use astconv::{AstConv, GenericArgMismatchErrorCode}; +use astconv::AstConv; use hir::GenericArg; use hir::def::Def; -use hir::HirVec; use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use std::slice; use namespace::Namespace; @@ -4945,22 +4944,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // `impl Trait` is treated as a normal generic parameter internally, // but we don't allow users to specify the parameter's value // explicitly, so we have to do some error-checking here. - let suppress_mismatch = self.check_impl_trait(span, seg, &generics); - suppress_errors.insert(index, AstConv::check_generic_arg_count( + suppress_errors.insert(index, AstConv::check_generic_arg_count_for_call( self.tcx, span, &generics, - &seg.args.clone().unwrap_or_else(|| P(hir::GenericArgs { - args: HirVec::new(), bindings: HirVec::new(), parenthesized: false, - })), - false, // `is_declaration` + &seg, false, // `is_method_call` - generics.parent.is_none() && generics.has_self, - seg.infer_types || suppress_mismatch, - GenericArgMismatchErrorCode { - lifetimes: ("E0090", "E0088"), // FIXME: E0090 and E0088 should be unified. - types: ("E0089", "E0087"), // FIXME: E0089 and E0087 should be unified. - }, )); } @@ -5112,35 +5101,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { directly, not through a function pointer"); } - /// Report error if there is an explicit type parameter when using `impl Trait`. - fn check_impl_trait(&self, - span: Span, - seg: &hir::PathSegment, - generics: &ty::Generics) - -> bool { - let explicit = !seg.infer_types; - let impl_trait = generics.params.iter().any(|param| match param.kind { - ty::GenericParamDefKind::Type { - synthetic: Some(hir::SyntheticTyParamKind::ImplTrait), .. - } => true, - _ => false, - }); - - if explicit && impl_trait { - let mut err = struct_span_err! { - self.tcx.sess, - span, - E0632, - "cannot provide explicit type parameters when `impl Trait` is \ - used in argument position." - }; - - err.emit(); - } - - impl_trait - } - // Resolves `typ` by a single level if `typ` is a type variable. // If no resolution is possible, then an error is reported. // Numeric inference variables may be left unresolved. diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 4d957c9aa45..c01102272ae 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -1041,32 +1041,34 @@ enum NightsWatch {} "##, E0087: r##" -Too many type parameters were supplied for a function. For example: +Too many type arguments were supplied for a function. For example: ```compile_fail,E0087 fn foo() {} fn main() { - foo::(); // error, expected 1 parameter, found 2 parameters + foo::(); // error: wrong number of type arguments: + // expected 1, found 2 } ``` -The number of supplied parameters must exactly match the number of defined type +The number of supplied arguments must exactly match the number of defined type parameters. "##, E0088: r##" -You gave too many lifetime parameters. Erroneous code example: +You gave too many lifetime arguments. Erroneous code example: ```compile_fail,E0088 fn f() {} fn main() { - f::<'static>() // error: too many lifetime parameters provided + f::<'static>() // error: wrong number of lifetime arguments: + // expected 0, found 1 } ``` -Please check you give the right number of lifetime parameters. Example: +Please check you give the right number of lifetime arguments. Example: ``` fn f() {} @@ -1101,17 +1103,17 @@ fn main() { "##, E0089: r##" -Not enough type parameters were supplied for a function. For example: +Too few type arguments were supplied for a function. For example: ```compile_fail,E0089 fn foo() {} fn main() { - foo::(); // error, expected 2 parameters, found 1 parameter + foo::(); // error: wrong number of type arguments: expected 2, found 1 } ``` -Note that if a function takes multiple type parameters but you want the compiler +Note that if a function takes multiple type arguments but you want the compiler to infer some of them, you can use type placeholders: ```compile_fail,E0089 @@ -1119,24 +1121,26 @@ fn foo(x: T) {} fn main() { let x: bool = true; - foo::(x); // error, expected 2 parameters, found 1 parameter + foo::(x); // error: wrong number of type arguments: + // expected 2, found 1 foo::<_, f64>(x); // same as `foo::(x)` } ``` "##, E0090: r##" -You gave too few lifetime parameters. Example: +You gave too few lifetime arguments. Example: ```compile_fail,E0090 fn foo<'a: 'b, 'b: 'a>() {} fn main() { - foo::<'static>(); // error, expected 2 lifetime parameters + foo::<'static>(); // error: wrong number of lifetime arguments: + // expected 2, found 1 } ``` -Please check you give the right number of lifetime parameters. Example: +Please check you give the right number of lifetime arguments. Example: ``` fn foo<'a: 'b, 'b: 'a>() {}