about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGary Guo <gary@garyguo.net>2021-06-09 20:56:41 +0100
committerGary Guo <gary@garyguo.net>2021-08-02 04:17:01 +0100
commit9b90e7e9802499ef3b4299149e0da1a16668a2f1 (patch)
tree19cf2491abdec03bec4ef8574d2cb0925501dad8
parent337181e07d3cd33c0aec2f17c12279bc9afca88f (diff)
downloadrust-9b90e7e9802499ef3b4299149e0da1a16668a2f1.tar.gz
rust-9b90e7e9802499ef3b4299149e0da1a16668a2f1.zip
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`
-rw-r--r--compiler/rustc_feature/src/active.rs3
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs2
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_typeck/src/astconv/generics.rs35
-rw-r--r--src/doc/unstable-book/src/language-features/explicit-generic-args-with-impl-trait.md53
-rw-r--r--src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args-for-impl.rs7
-rw-r--r--src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args-for-impl.stderr17
-rw-r--r--src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args.rs9
-rw-r--r--src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/feature-gate.rs7
-rw-r--r--src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/feature-gate.stderr9
10 files changed, 139 insertions, 4 deletions
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 638330c904d..db8d01e31b7 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 9a718102cf1..a15eecd2414 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 1ac489f600a..95b92fd34c8 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 eb6265dec89..9e700d9e8d8 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 00000000000..479571d85fe
--- /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<T: ?Sized>(_f: impl AsRef<T>) {}
+
+fn main() {
+    foo::<str>("".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::<str>("".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<T: ?Sized>(_f: impl AsRef<T>) {}
+fn bar<T: ?Sized, F: AsRef<T>>(_f: F) {}
+
+fn main() {
+    bar::<str, _>("".to_string()); // Okay
+    bar::<str, String>("".to_string()); // Okay
+
+    foo::<str>("".to_string()); // Okay
+    foo::<str, String>("".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 00000000000..832a3e3b7b1
--- /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<T: ?Sized>(_f: impl AsRef<T>) {}
+
+fn main() {
+    foo::<str, String>("".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 00000000000..739e55e2943
--- /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::<str, String>("".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<T: ?Sized>(_f: impl AsRef<T>) {}
+   |    ^^^ -
+
+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 00000000000..a6585bcf848
--- /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<T: ?Sized>(_f: impl AsRef<T>) {}
+
+fn main() {
+    foo::<str>("".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 00000000000..0e4d6986d46
--- /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<T: ?Sized>(_f: impl AsRef<T>) {}
+
+fn main() {
+    foo::<str>("".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 00000000000..6adc4e6b239
--- /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::<str>("".to_string());
+   |           ^^^ explicit generic argument not allowed
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0632`.