From 9b90e7e9802499ef3b4299149e0da1a16668a2f1 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Wed, 9 Jun 2021 20:56:41 +0100 Subject: [PATCH] Implement a `explicit_generic_args_with_impl_trait` feature gate When this gate is enabled, explicit generic arguments can be specified even if `impl Trait` is used in argument position. Generic arguments can only be specified for explicit generic parameters but not for the synthetic type parameters from `impl Trait` --- compiler/rustc_feature/src/active.rs | 3 ++ .../infer/error_reporting/need_type_info.rs | 2 +- compiler/rustc_span/src/symbol.rs | 1 + compiler/rustc_typeck/src/astconv/generics.rs | 35 ++++++++++-- .../explicit-generic-args-with-impl-trait.md | 53 +++++++++++++++++++ .../explicit-generic-args-for-impl.rs | 7 +++ .../explicit-generic-args-for-impl.stderr | 17 ++++++ .../explicit-generic-args.rs | 9 ++++ .../feature-gate.rs | 7 +++ .../feature-gate.stderr | 9 ++++ 10 files changed, 139 insertions(+), 4 deletions(-) create mode 100644 src/doc/unstable-book/src/language-features/explicit-generic-args-with-impl-trait.md create mode 100644 src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args-for-impl.rs create mode 100644 src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args-for-impl.stderr create mode 100644 src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args.rs create mode 100644 src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/feature-gate.rs create mode 100644 src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/feature-gate.stderr diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 638330c904d75..db8d01e31b74d 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -687,6 +687,9 @@ declare_features! ( /// Trait upcasting is casting, e.g., `dyn Foo -> dyn Bar` where `Foo: Bar`. (incomplete, trait_upcasting, "1.56.0", Some(65991), None), + /// Allows explicit generic arguments specification with `impl Trait` present. + (active, explicit_generic_args_with_impl_trait, "1.56.0", Some(83701), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index 9a718102cf11d..a15eecd2414c2 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -769,7 +769,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // (#83606): Do not emit a suggestion if the parent has an `impl Trait` // as an argument otherwise it will cause the E0282 error. - if !has_impl_trait { + if !has_impl_trait || self.tcx.features().explicit_generic_args_with_impl_trait { err.span_suggestion_verbose( span, "consider specifying the const argument", diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 1ac489f600a40..95b92fd34c8aa 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -554,6 +554,7 @@ symbols! { expected, expf32, expf64, + explicit_generic_args_with_impl_trait, export_name, expr, extended_key_value_attributes, diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs index eb6265dec89c0..9e700d9e8d8ba 100644 --- a/compiler/rustc_typeck/src/astconv/generics.rs +++ b/compiler/rustc_typeck/src/astconv/generics.rs @@ -459,7 +459,32 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let default_counts = gen_params.own_defaults(); let param_counts = gen_params.own_counts(); - let named_type_param_count = param_counts.types - has_self as usize; + + // Subtracting from param count to ensure type params synthesized from `impl Trait` + // cannot be explictly specified even with `explicit_generic_args_with_impl_trait` + // feature enabled. + let synth_type_param_count = if tcx.features().explicit_generic_args_with_impl_trait { + gen_params + .params + .iter() + .filter(|param| { + matches!( + param.kind, + ty::GenericParamDefKind::Type { + synthetic: Some( + hir::SyntheticTyParamKind::ImplTrait + | hir::SyntheticTyParamKind::FromAttr + ), + .. + } + ) + }) + .count() + } else { + 0 + }; + let named_type_param_count = + param_counts.types - has_self as usize - synth_type_param_count; let infer_lifetimes = gen_pos != GenericArgPosition::Type && !gen_args.has_lifetime_params(); @@ -588,6 +613,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { param_counts.consts + named_type_param_count - default_counts.types - default_counts.consts + - synth_type_param_count }; debug!("expected_min: {:?}", expected_min); debug!("arg_counts.lifetimes: {:?}", gen_args.num_lifetime_params()); @@ -617,7 +643,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { seg: &hir::PathSegment<'_>, generics: &ty::Generics, ) -> bool { - let explicit = !seg.infer_args; + if seg.infer_args || tcx.features().explicit_generic_args_with_impl_trait { + return false; + } + let impl_trait = generics.params.iter().any(|param| { matches!( param.kind, @@ -630,7 +659,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ) }); - if explicit && impl_trait { + if impl_trait { let spans = seg .args() .args diff --git a/src/doc/unstable-book/src/language-features/explicit-generic-args-with-impl-trait.md b/src/doc/unstable-book/src/language-features/explicit-generic-args-with-impl-trait.md new file mode 100644 index 0000000000000..479571d85fe05 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/explicit-generic-args-with-impl-trait.md @@ -0,0 +1,53 @@ +# `explicit_generic_args_with_impl_trait` + +The tracking issue for this feature is: [#83701] + +[#83701]: https://github.com/rust-lang/rust/issues/83701 + +------------------------ + +The `explicit_generic_args_with_impl_trait` feature gate lets you specify generic arguments even +when `impl Trait` is used in argument position. + +A simple example is: + +```rust +#![feature(explicit_generic_args_with_impl_trait)] + +fn foo(_f: impl AsRef) {} + +fn main() { + foo::("".to_string()); +} +``` + +This is currently rejected: + +```text +error[E0632]: cannot provide explicit generic arguments when `impl Trait` is used in argument position + --> src/main.rs:6:11 + | +6 | foo::("".to_string()); + | ^^^ explicit generic argument not allowed + +``` + +However it would compile if `explicit_generic_args_with_impl_trait` is enabled. + +Note that the synthetic type parameters from `impl Trait` are still implicit and you +cannot explicitly specify these: + +```rust,compile_fail +#![feature(explicit_generic_args_with_impl_trait)] + +fn foo(_f: impl AsRef) {} +fn bar>(_f: F) {} + +fn main() { + bar::("".to_string()); // Okay + bar::("".to_string()); // Okay + + foo::("".to_string()); // Okay + foo::("".to_string()); // Error, you cannot specify `impl Trait` explicitly +} +``` diff --git a/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args-for-impl.rs b/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args-for-impl.rs new file mode 100644 index 0000000000000..832a3e3b7b10d --- /dev/null +++ b/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args-for-impl.rs @@ -0,0 +1,7 @@ +#![feature(explicit_generic_args_with_impl_trait)] + +fn foo(_f: impl AsRef) {} + +fn main() { + foo::("".to_string()); //~ ERROR E0107 +} diff --git a/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args-for-impl.stderr b/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args-for-impl.stderr new file mode 100644 index 0000000000000..739e55e294381 --- /dev/null +++ b/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args-for-impl.stderr @@ -0,0 +1,17 @@ +error[E0107]: this function takes at most 1 generic argument but 2 generic arguments were supplied + --> $DIR/explicit-generic-args-for-impl.rs:6:5 + | +LL | foo::("".to_string()); + | ^^^ ------ help: remove this generic argument + | | + | expected at most 1 generic argument + | +note: function defined here, with at most 1 generic parameter: `T` + --> $DIR/explicit-generic-args-for-impl.rs:3:4 + | +LL | fn foo(_f: impl AsRef) {} + | ^^^ - + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0107`. diff --git a/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args.rs b/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args.rs new file mode 100644 index 0000000000000..a6585bcf84862 --- /dev/null +++ b/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args.rs @@ -0,0 +1,9 @@ +// check-pass + +#![feature(explicit_generic_args_with_impl_trait)] + +fn foo(_f: impl AsRef) {} + +fn main() { + foo::("".to_string()); +} diff --git a/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/feature-gate.rs b/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/feature-gate.rs new file mode 100644 index 0000000000000..0e4d6986d46ec --- /dev/null +++ b/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/feature-gate.rs @@ -0,0 +1,7 @@ +// gate-test-explicit_generic_args_with_impl_trait + +fn foo(_f: impl AsRef) {} + +fn main() { + foo::("".to_string()); //~ ERROR E0632 +} diff --git a/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/feature-gate.stderr b/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/feature-gate.stderr new file mode 100644 index 0000000000000..6adc4e6b23968 --- /dev/null +++ b/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/feature-gate.stderr @@ -0,0 +1,9 @@ +error[E0632]: cannot provide explicit generic arguments when `impl Trait` is used in argument position + --> $DIR/feature-gate.rs:6:11 + | +LL | foo::("".to_string()); + | ^^^ explicit generic argument not allowed + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0632`.