Refactor generic argument count check in astconv

This commit is contained in:
varkor 2018-08-07 18:53:43 +01:00
parent a14bc713e7
commit 49c45734c0
17 changed files with 139 additions and 142 deletions

View File

@ -919,7 +919,7 @@ impl<'a, 'gcx, 'tcx> Generics {
for param in &self.params { for param in &self.params {
match param.kind { match param.kind {
GenericParamDefKind::Lifetime => own_counts.lifetimes += 1, GenericParamDefKind::Lifetime => own_counts.lifetimes += 1,
GenericParamDefKind::Type {..} => own_counts.types += 1, GenericParamDefKind::Type { .. } => own_counts.types += 1,
}; };
} }

View File

@ -29,7 +29,7 @@ use std::slice;
use require_c_abi_if_variadic; use require_c_abi_if_variadic;
use util::common::ErrorReported; use util::common::ErrorReported;
use util::nodemap::{FxHashSet, FxHashMap}; use util::nodemap::{FxHashSet, FxHashMap};
use errors::FatalError; use errors::{FatalError, DiagnosticId};
use std::iter; use std::iter;
use syntax::ast; use syntax::ast;
@ -89,11 +89,6 @@ struct ConvertedBinding<'tcx> {
span: Span, span: Span,
} }
struct ParamRange {
required: usize,
accepted: usize
}
/// Dummy type used for the `Self` of a `TraitRef` created for converting /// Dummy type used for the `Self` of a `TraitRef` created for converting
/// a trait object, and which gets removed in `ExistentialTraitRef`. /// a trait object, and which gets removed in `ExistentialTraitRef`.
/// This type must not appear anywhere in other converted types. /// This type must not appear anywhere in other converted types.
@ -346,56 +341,21 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
self_ty: Option<Ty<'tcx>>) self_ty: Option<Ty<'tcx>>)
-> (&'tcx Substs<'tcx>, Vec<ConvertedBinding<'tcx>>) -> (&'tcx Substs<'tcx>, Vec<ConvertedBinding<'tcx>>)
{ {
let tcx = self.tcx(); // 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).
debug!("create_substs_for_ast_path(def_id={:?}, self_ty={:?}, \ debug!("create_substs_for_ast_path(def_id={:?}, self_ty={:?}, \
generic_args={:?})", generic_args={:?})",
def_id, self_ty, generic_args); def_id, self_ty, generic_args);
// If the type is parameterized by this region, then replace this let tcx = self.tcx();
// region with the current anon region binding (in other words, let generic_params = tcx.generics_of(def_id);
// whatever & would get replaced with).
let mut lt_provided = 0;
let mut ty_provided = 0;
for arg in &generic_args.args {
match arg {
GenericArg::Lifetime(_) => lt_provided += 1,
GenericArg::Type(_) => ty_provided += 1,
}
}
let decl_generics = tcx.generics_of(def_id);
let mut lt_accepted = 0;
let mut ty_params = ParamRange { required: 0, accepted: 0 };
for param in &decl_generics.params {
match param.kind {
GenericParamDefKind::Lifetime => {
lt_accepted += 1;
}
GenericParamDefKind::Type { has_default, .. } => {
ty_params.accepted += 1;
if !has_default {
ty_params.required += 1;
}
}
};
}
if self_ty.is_some() {
ty_params.required -= 1;
ty_params.accepted -= 1;
}
if lt_accepted != lt_provided {
report_lifetime_number_error(tcx, span, lt_provided, lt_accepted);
}
// If a self-type was declared, one should be provided. // If a self-type was declared, one should be provided.
assert_eq!(decl_generics.has_self, self_ty.is_some()); assert_eq!(generic_params.has_self, self_ty.is_some());
// Check the number of type parameters supplied by the user. let has_self = generic_params.has_self;
if !infer_types || ty_provided > ty_params.required { check_generic_arg_count(tcx, span, &generic_params, &generic_args, has_self, infer_types);
check_type_argument_count(tcx, span, ty_provided, ty_params);
}
let is_object = self_ty.map_or(false, |ty| ty.sty == TRAIT_OBJECT_DUMMY_SELF); let is_object = self_ty.map_or(false, |ty| ty.sty == TRAIT_OBJECT_DUMMY_SELF);
let default_needs_object_self = |param: &ty::GenericParamDef| { let default_needs_object_self = |param: &ty::GenericParamDef| {
@ -492,8 +452,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
} }
}).collect(); }).collect();
debug!("create_substs_for_ast_path(decl_generics={:?}, self_ty={:?}) -> {:?}", debug!("create_substs_for_ast_path(generic_params={:?}, self_ty={:?}) -> {:?}",
decl_generics, self_ty, substs); generic_params, self_ty, substs);
(substs, assoc_bindings) (substs, assoc_bindings)
} }
@ -1537,70 +1497,107 @@ fn split_auto_traits<'a, 'b, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
(auto_traits, trait_bounds) (auto_traits, trait_bounds)
} }
fn check_type_argument_count(tcx: TyCtxt, pub fn check_generic_arg_count(
span: Span, tcx: TyCtxt,
supplied: usize, span: Span,
ty_params: ParamRange) def: &ty::Generics,
{ args: &hir::GenericArgs,
let (required, accepted) = (ty_params.required, ty_params.accepted); has_self: bool,
if supplied < required { infer_types: bool,
let expected = if required < accepted { ) {
"expected at least" // At this stage we are guaranteed that the generic arguments are in the correct order, e.g.
} else { // that lifetimes will proceed types. So it suffices to check the number of each generic
"expected" // arguments in order to validate them with respect to the generic parameters.
}; let param_counts = def.own_counts();
let arguments_plural = if required == 1 { "" } else { "s" }; let arg_counts = args.own_counts();
struct_span_err!(tcx.sess, span, E0243, let mut defaults: ty::GenericParamCount = Default::default();
"wrong number of type arguments: {} {}, found {}", for param in &def.params {
expected, required, supplied) match param.kind {
.span_label(span, GenericParamDefKind::Lifetime => {}
format!("{} {} type argument{}", GenericParamDefKind::Type { has_default, .. } => defaults.types += has_default as usize,
expected,
required,
arguments_plural))
.emit();
} else if supplied > accepted {
let expected = if required < accepted {
format!("expected at most {}", accepted)
} else {
format!("expected {}", accepted)
}; };
let arguments_plural = if accepted == 1 { "" } else { "s" };
struct_span_err!(tcx.sess, span, E0244,
"wrong number of type arguments: {}, found {}",
expected, supplied)
.span_label(
span,
format!("{} type argument{}",
if accepted == 0 { "expected no" } else { &expected },
arguments_plural)
)
.emit();
} }
}
fn report_lifetime_number_error(tcx: TyCtxt, span: Span, number: usize, expected: usize) { let check_kind_count = |error_code_less: &str,
let label = if number < expected { error_code_more: &str,
if expected == 1 { kind,
format!("expected {} lifetime parameter", expected) required,
} else { permitted,
format!("expected {} lifetime parameters", expected) provided| {
// We enforce the following: `required` <= `provided` <= `permitted`.
// For kinds without defaults (i.e. lifetimes), `required == permitted`.
// For other kinds (i.e. types), `permitted` may be greater than `required`.
if required <= provided && provided <= permitted {
return;
} }
} else {
let additional = number - expected; // Unfortunately lifetime and type parameter mismatches are typically styled
if additional == 1 { // differently in diagnostics, which means we have a few cases to consider here.
"unexpected lifetime parameter".to_string() let (bound, quantifier) = if required != permitted {
if provided < required {
(required, "at least ")
} else { // provided > permitted
(permitted, "at most ")
}
} else { } else {
format!("{} unexpected lifetime parameters", additional) (required, "")
} };
let label = if required == permitted && provided > permitted {
let diff = provided - permitted;
format!(
"{}unexpected {} argument{}",
if diff != 1 { format!("{} ", diff) } else { String::new() },
kind,
if diff != 1 { "s" } else { "" },
)
} else {
format!(
"expected {}{} {} argument{}",
quantifier,
bound,
kind,
if required != 1 { "s" } else { "" },
)
};
tcx.sess.struct_span_err_with_code(
span,
&format!(
"wrong number of {} arguments: expected {}{}, found {}",
kind,
quantifier,
bound,
provided,
),
DiagnosticId::Error({
if provided <= permitted {
error_code_less
} else {
error_code_more
}
}.into())
).span_label(span, label).emit();
}; };
struct_span_err!(tcx.sess, span, E0107,
"wrong number of lifetime parameters: expected {}, found {}", check_kind_count(
expected, number) "E0107",
.span_label(span, label) "E0107",
.emit(); "lifetime",
param_counts.lifetimes,
param_counts.lifetimes,
arg_counts.lifetimes,
);
if !infer_types || arg_counts.types > param_counts.types - defaults.types - has_self as usize {
check_kind_count(
"E0243",
"E0244", // FIXME: E0243 and E0244 should be unified.
"type",
param_counts.types - defaults.types - has_self as usize,
param_counts.types - has_self as usize,
arg_counts.types,
);
}
} }
// A helper struct for conveniently grouping a set of bounds which we pass to // A helper struct for conveniently grouping a set of bounds which we pass to

View File

@ -41,7 +41,7 @@ fn foo<'a>() {
//~^ ERROR too many type parameters provided //~^ ERROR too many type parameters provided
let _ = S::<'a,isize>::new::<f64>(1, 1.0); let _ = S::<'a,isize>::new::<f64>(1, 1.0);
//~^ ERROR wrong number of lifetime parameters //~^ ERROR wrong number of lifetime arguments
let _: S2 = Trait::new::<isize,f64>(1, 1.0); let _: S2 = Trait::new::<isize,f64>(1, 1.0);
//~^ ERROR too many type parameters provided //~^ ERROR too many type parameters provided

View File

@ -20,13 +20,13 @@ enum Bar {
struct Baz<'a, 'b, 'c> { struct Baz<'a, 'b, 'c> {
buzz: Buzz<'a>, buzz: Buzz<'a>,
//~^ ERROR E0107 //~^ ERROR E0107
//~| expected 2 lifetime parameters //~| expected 2 lifetime arguments
bar: Bar<'a>, bar: Bar<'a>,
//~^ ERROR E0107 //~^ ERROR E0107
//~| unexpected lifetime parameter //~| unexpected lifetime argument
foo2: Foo<'a, 'b, 'c>, foo2: Foo<'a, 'b, 'c>,
//~^ ERROR E0107 //~^ ERROR E0107
//~| 2 unexpected lifetime parameters //~| 2 unexpected lifetime arguments
} }
fn main() {} fn main() {}

View File

@ -1,20 +1,20 @@
error[E0107]: wrong number of lifetime parameters: expected 2, found 1 error[E0107]: wrong number of lifetime arguments: expected 2, found 1
--> $DIR/E0107.rs:21:11 --> $DIR/E0107.rs:21:11
| |
LL | buzz: Buzz<'a>, LL | buzz: Buzz<'a>,
| ^^^^^^^^ expected 2 lifetime parameters | ^^^^^^^^ expected 2 lifetime arguments
error[E0107]: wrong number of lifetime parameters: expected 0, found 1 error[E0107]: wrong number of lifetime arguments: expected 0, found 1
--> $DIR/E0107.rs:24:10 --> $DIR/E0107.rs:24:10
| |
LL | bar: Bar<'a>, LL | bar: Bar<'a>,
| ^^^^^^^ unexpected lifetime parameter | ^^^^^^^ unexpected lifetime argument
error[E0107]: wrong number of lifetime parameters: expected 1, found 3 error[E0107]: wrong number of lifetime arguments: expected 1, found 3
--> $DIR/E0107.rs:27:11 --> $DIR/E0107.rs:27:11
| |
LL | foo2: Foo<'a, 'b, 'c>, LL | foo2: Foo<'a, 'b, 'c>,
| ^^^^^^^^^^^^^^^ 2 unexpected lifetime parameters | ^^^^^^^^^^^^^^^ 2 unexpected lifetime arguments
error: aborting due to 3 previous errors error: aborting due to 3 previous errors

View File

@ -2,7 +2,7 @@ error[E0244]: wrong number of type arguments: expected 0, found 2
--> $DIR/E0244.rs:12:23 --> $DIR/E0244.rs:12:23
| |
LL | struct Bar<S, T> { x: Foo<S, T> } LL | struct Bar<S, T> { x: Foo<S, T> }
| ^^^^^^^^^ expected no type arguments | ^^^^^^^^^ 2 unexpected type arguments
error: aborting due to previous error error: aborting due to previous error

View File

@ -2,7 +2,7 @@ error[E0244]: wrong number of type arguments: expected at most 2, found 3
--> $DIR/generic-type-more-params-with-defaults.rs:19:12 --> $DIR/generic-type-more-params-with-defaults.rs:19:12
| |
LL | let _: Vec<isize, Heap, bool>; LL | let _: Vec<isize, Heap, bool>;
| ^^^^^^^^^^^^^^^^^^^^^^ expected at most 2 type arguments | ^^^^^^^^^^^^^^^^^^^^^^ expected at most 2 type argument
error: aborting due to previous error error: aborting due to previous error

View File

@ -8,10 +8,10 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
// Test that `Box` cannot be used with a lifetime parameter. // Test that `Box` cannot be used with a lifetime argument.
struct Foo<'a> { struct Foo<'a> {
x: Box<'a, isize> //~ ERROR wrong number of lifetime parameters x: Box<'a, isize> //~ ERROR wrong number of lifetime arguments
} }
pub fn main() { pub fn main() {

View File

@ -1,8 +1,8 @@
error[E0107]: wrong number of lifetime parameters: expected 0, found 1 error[E0107]: wrong number of lifetime arguments: expected 0, found 1
--> $DIR/issue-18423.rs:14:8 --> $DIR/issue-18423.rs:14:8
| |
LL | x: Box<'a, isize> //~ ERROR wrong number of lifetime parameters LL | x: Box<'a, isize> //~ ERROR wrong number of lifetime arguments
| ^^^^^^^^^^^^^^ unexpected lifetime parameter | ^^^^^^^^^^^^^^ unexpected lifetime argument
error: aborting due to previous error error: aborting due to previous error

View File

@ -13,7 +13,7 @@ error[E0244]: wrong number of type arguments: expected 0, found 1
--> $DIR/issue-3214.rs:16:22 --> $DIR/issue-3214.rs:16:22
| |
LL | impl<T> Drop for foo<T> { LL | impl<T> Drop for foo<T> {
| ^^^^^^ expected no type arguments | ^^^^^^ unexpected type argument
error: aborting due to 2 previous errors error: aborting due to 2 previous errors

View File

@ -21,7 +21,7 @@ fn main() {
let _: S<'static, 'static +>; let _: S<'static, 'static +>;
//~^ at least one non-builtin trait is required for an object type //~^ at least one non-builtin trait is required for an object type
let _: S<'static, 'static>; let _: S<'static, 'static>;
//~^ ERROR wrong number of lifetime parameters: expected 1, found 2 //~^ ERROR wrong number of lifetime arguments: expected 1, found 2
//~| ERROR wrong number of type arguments: expected 1, found 0 //~| ERROR wrong number of type arguments: expected 1, found 0
let _: S<'static +, 'static>; let _: S<'static +, 'static>;
//~^ ERROR lifetime parameters must be declared prior to type parameters //~^ ERROR lifetime parameters must be declared prior to type parameters

View File

@ -18,12 +18,12 @@ struct MyStruct1<T: Copy<T>>;
//~^ ERROR wrong number of type arguments: expected 0, found 1 [E0244] //~^ ERROR wrong number of type arguments: expected 0, found 1 [E0244]
struct MyStruct2<'a, T: Copy<'a>>; struct MyStruct2<'a, T: Copy<'a>>;
//~^ ERROR: wrong number of lifetime parameters: expected 0, found 1 //~^ ERROR: wrong number of lifetime arguments: expected 0, found 1
fn foo2<'a, T:Copy<'a, U>, U>(x: T) {} fn foo2<'a, T:Copy<'a, U>, U>(x: T) {}
//~^ ERROR wrong number of type arguments: expected 0, found 1 [E0244] //~^ ERROR wrong number of type arguments: expected 0, found 1 [E0244]
//~| ERROR: wrong number of lifetime parameters: expected 0, found 1 //~| ERROR: wrong number of lifetime arguments: expected 0, found 1
fn main() { fn main() {
} }

View File

@ -2,37 +2,37 @@ error[E0244]: wrong number of type arguments: expected 0, found 1
--> $DIR/typeck-builtin-bound-type-parameters.rs:11:11 --> $DIR/typeck-builtin-bound-type-parameters.rs:11:11
| |
LL | fn foo1<T:Copy<U>, U>(x: T) {} LL | fn foo1<T:Copy<U>, U>(x: T) {}
| ^^^^^^^ expected no type arguments | ^^^^^^^ unexpected type argument
error[E0244]: wrong number of type arguments: expected 0, found 1 error[E0244]: wrong number of type arguments: expected 0, found 1
--> $DIR/typeck-builtin-bound-type-parameters.rs:14:14 --> $DIR/typeck-builtin-bound-type-parameters.rs:14:14
| |
LL | trait Trait: Copy<Send> {} LL | trait Trait: Copy<Send> {}
| ^^^^^^^^^^ expected no type arguments | ^^^^^^^^^^ unexpected type argument
error[E0244]: wrong number of type arguments: expected 0, found 1 error[E0244]: wrong number of type arguments: expected 0, found 1
--> $DIR/typeck-builtin-bound-type-parameters.rs:17:21 --> $DIR/typeck-builtin-bound-type-parameters.rs:17:21
| |
LL | struct MyStruct1<T: Copy<T>>; LL | struct MyStruct1<T: Copy<T>>;
| ^^^^^^^ expected no type arguments | ^^^^^^^ unexpected type argument
error[E0107]: wrong number of lifetime parameters: expected 0, found 1 error[E0107]: wrong number of lifetime arguments: expected 0, found 1
--> $DIR/typeck-builtin-bound-type-parameters.rs:20:25 --> $DIR/typeck-builtin-bound-type-parameters.rs:20:25
| |
LL | struct MyStruct2<'a, T: Copy<'a>>; LL | struct MyStruct2<'a, T: Copy<'a>>;
| ^^^^^^^^ unexpected lifetime parameter | ^^^^^^^^ unexpected lifetime argument
error[E0107]: wrong number of lifetime parameters: expected 0, found 1 error[E0107]: wrong number of lifetime arguments: expected 0, found 1
--> $DIR/typeck-builtin-bound-type-parameters.rs:24:15 --> $DIR/typeck-builtin-bound-type-parameters.rs:24:15
| |
LL | fn foo2<'a, T:Copy<'a, U>, U>(x: T) {} LL | fn foo2<'a, T:Copy<'a, U>, U>(x: T) {}
| ^^^^^^^^^^^ unexpected lifetime parameter | ^^^^^^^^^^^ unexpected lifetime argument
error[E0244]: wrong number of type arguments: expected 0, found 1 error[E0244]: wrong number of type arguments: expected 0, found 1
--> $DIR/typeck-builtin-bound-type-parameters.rs:24:15 --> $DIR/typeck-builtin-bound-type-parameters.rs:24:15
| |
LL | fn foo2<'a, T:Copy<'a, U>, U>(x: T) {} LL | fn foo2<'a, T:Copy<'a, U>, U>(x: T) {}
| ^^^^^^^^^^^ expected no type arguments | ^^^^^^^^^^^ unexpected type argument
error: aborting due to 6 previous errors error: aborting due to 6 previous errors

View File

@ -2,7 +2,7 @@ error[E0244]: wrong number of type arguments: expected 1, found 2
--> $DIR/typeck_type_placeholder_lifetime_1.rs:19:12 --> $DIR/typeck_type_placeholder_lifetime_1.rs:19:12
| |
LL | let c: Foo<_, _> = Foo { r: &5 }; LL | let c: Foo<_, _> = Foo { r: &5 };
| ^^^^^^^^^ expected 1 type argument | ^^^^^^^^^ unexpected type argument
error: aborting due to previous error error: aborting due to previous error

View File

@ -2,7 +2,7 @@ error[E0244]: wrong number of type arguments: expected 1, found 2
--> $DIR/typeck_type_placeholder_lifetime_2.rs:19:12 --> $DIR/typeck_type_placeholder_lifetime_2.rs:19:12
| |
LL | let c: Foo<_, usize> = Foo { r: &5 }; LL | let c: Foo<_, usize> = Foo { r: &5 };
| ^^^^^^^^^^^^^ expected 1 type argument | ^^^^^^^^^^^^^ unexpected type argument
error: aborting due to previous error error: aborting due to previous error

View File

@ -38,7 +38,7 @@ fn test<'a,'b>() {
} }
fn test2(x: &Foo<(isize,),Output=()>, y: &Foo(isize)) { fn test2(x: &Foo<(isize,),Output=()>, y: &Foo(isize)) {
//~^ ERROR wrong number of lifetime parameters: expected 1, found 0 //~^ ERROR wrong number of lifetime arguments: expected 1, found 0
// Here, the omitted lifetimes are expanded to distinct things. // Here, the omitted lifetimes are expanded to distinct things.
same_type(x, y) same_type(x, y)
} }

View File

@ -2,7 +2,7 @@ error[E0244]: wrong number of type arguments: expected 0, found 1
--> $DIR/unboxed-closure-sugar-wrong-trait.rs:15:8 --> $DIR/unboxed-closure-sugar-wrong-trait.rs:15:8
| |
LL | fn f<F:Trait(isize) -> isize>(x: F) {} LL | fn f<F:Trait(isize) -> isize>(x: F) {}
| ^^^^^^^^^^^^^^^^^^^^^ expected no type arguments | ^^^^^^^^^^^^^^^^^^^^^ unexpected type argument
error[E0220]: associated type `Output` not found for `Trait` error[E0220]: associated type `Output` not found for `Trait`
--> $DIR/unboxed-closure-sugar-wrong-trait.rs:15:24 --> $DIR/unboxed-closure-sugar-wrong-trait.rs:15:24