about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2022-06-04 00:42:50 +0200
committerGitHub <noreply@github.com>2022-06-04 00:42:50 +0200
commit401be78f2c6fa3ded6b529765ccfe160636a6285 (patch)
treefd855a26f4fa61c8b044addfd9890c6473a8078c
parente33c6edfc04d0ba5f4e0d996100263ee9d2fef79 (diff)
parentcd03fe18d8a24434c1510d08c88231fbe9d6b8bf (diff)
downloadrust-401be78f2c6fa3ded6b529765ccfe160636a6285.tar.gz
rust-401be78f2c6fa3ded6b529765ccfe160636a6285.zip
Rollup merge of #97656 - EdwinRy:error_ast_low_type_contraint_parentheses, r=cjgillot
Add a suggestion to replace parentheses with angle brackets on associated trait constraint

This implements a requested suggestion FIXME in [`compiler/rustc_ast_lowering/src/lib.rs` ](https://github.com/rust-lang/rust/blob/9598b4b594c97dff66feb93522e22db500deea07/compiler/rustc_ast_lowering/src/lib.rs#L921)

The suggestion asks for the parentheses to either be replaced with angle brackets or removed completely depending on whether there are arguments provided within.

![image](https://user-images.githubusercontent.com/20026256/171770414-ab60bfe2-ae27-44b0-964d-9ffcc32a7475.png)

![image](https://user-images.githubusercontent.com/20026256/171770383-ca8a2766-b3aa-43e3-8ba4-ae18874886ce.png)

r? `@oli-obk`
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs46
-rw-r--r--src/test/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs5
-rw-r--r--src/test/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr31
3 files changed, 73 insertions, 9 deletions
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index d1ea76b3922..12fc1dbc4da 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -46,7 +46,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::sync::Lrc;
-use rustc_errors::struct_span_err;
+use rustc_errors::{struct_span_err, Applicability};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Namespace, PartialRes, PerNS, Res};
 use rustc_hir::def_id::{DefId, DefPathHash, LocalDefId, CRATE_DEF_ID};
@@ -857,7 +857,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         itctx: ImplTraitContext,
     ) -> hir::TypeBinding<'hir> {
         debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", constraint, itctx);
-
         // lower generic arguments of identifier in constraint
         let gen_args = if let Some(ref gen_args) = constraint.gen_args {
             let gen_args_ctor = match gen_args {
@@ -865,12 +864,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     self.lower_angle_bracketed_parameter_data(data, ParamMode::Explicit, itctx).0
                 }
                 GenericArgs::Parenthesized(ref data) => {
-                    let mut err = self.sess.struct_span_err(
-                        gen_args.span(),
-                        "parenthesized generic arguments cannot be used in associated type constraints"
-                    );
-                    // FIXME: try to write a suggestion here
-                    err.emit();
+                    self.assoc_ty_contraint_param_error_emit(data);
                     self.lower_angle_bracketed_parameter_data(
                         &data.as_angle_bracketed_args(),
                         ParamMode::Explicit,
@@ -984,6 +978,42 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         }
     }
 
+    fn assoc_ty_contraint_param_error_emit(&self, data: &ParenthesizedArgs) -> () {
+        let mut err = self.sess.struct_span_err(
+            data.span,
+            "parenthesized generic arguments cannot be used in associated type constraints",
+        );
+        // Suggest removing empty parentheses: "Trait()" -> "Trait"
+        if data.inputs.is_empty() {
+            let parentheses_span =
+                data.inputs_span.shrink_to_lo().to(data.inputs_span.shrink_to_hi());
+            err.multipart_suggestion(
+                "remove these parentheses",
+                vec![(parentheses_span, String::new())],
+                Applicability::MaybeIncorrect,
+            );
+        }
+        // Suggest replacing parentheses with angle brackets `Trait(params...)` to `Trait<params...>`
+        else {
+            // Start of parameters to the 1st argument
+            let open_param = data.inputs_span.shrink_to_lo().to(data
+                .inputs
+                .first()
+                .unwrap()
+                .span
+                .shrink_to_lo());
+            // End of last argument to end of parameters
+            let close_param =
+                data.inputs.last().unwrap().span.shrink_to_hi().to(data.inputs_span.shrink_to_hi());
+            err.multipart_suggestion(
+                &format!("use angle brackets instead",),
+                vec![(open_param, String::from("<")), (close_param, String::from(">"))],
+                Applicability::MaybeIncorrect,
+            );
+        }
+        err.emit();
+    }
+
     fn lower_generic_arg(
         &mut self,
         arg: &ast::GenericArg,
diff --git a/src/test/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs b/src/test/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs
index f01da8c61ed..c55b0530c9d 100644
--- a/src/test/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs
+++ b/src/test/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs
@@ -10,4 +10,9 @@ fn foo<'a>(arg: Box<dyn X<Y('a) = &'a ()>>) {}
   //~| ERROR this associated type takes 0 generic arguments but 1 generic argument
   //~| ERROR this associated type takes 1 lifetime argument but 0 lifetime arguments
 
+
+fn bar<'a>(arg: Box<dyn X<Y() = ()>>) {}
+  //~^ ERROR: parenthesized generic arguments cannot be used
+  //~| ERROR this associated type takes 1 lifetime argument but 0 lifetime arguments
+
 fn main() {}
diff --git a/src/test/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr b/src/test/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr
index 6014a02c4d9..162214063e7 100644
--- a/src/test/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr
+++ b/src/test/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr
@@ -9,6 +9,19 @@ error: parenthesized generic arguments cannot be used in associated type constra
    |
 LL | fn foo<'a>(arg: Box<dyn X<Y('a) = &'a ()>>) {}
    |                           ^^^^^
+   |
+help: use angle brackets instead
+   |
+LL | fn foo<'a>(arg: Box<dyn X<Y<'a> = &'a ()>>) {}
+   |                            ~  ~
+
+error: parenthesized generic arguments cannot be used in associated type constraints
+  --> $DIR/gat-trait-path-parenthesised-args.rs:14:27
+   |
+LL | fn bar<'a>(arg: Box<dyn X<Y() = ()>>) {}
+   |                           ^--
+   |                            |
+   |                            help: remove these parentheses
 
 error[E0107]: this associated type takes 1 lifetime argument but 0 lifetime arguments were supplied
   --> $DIR/gat-trait-path-parenthesised-args.rs:7:27
@@ -40,6 +53,22 @@ note: associated type defined here, with 0 generic parameters
 LL |   type Y<'a>;
    |        ^
 
-error: aborting due to 4 previous errors
+error[E0107]: this associated type takes 1 lifetime argument but 0 lifetime arguments were supplied
+  --> $DIR/gat-trait-path-parenthesised-args.rs:14:27
+   |
+LL | fn bar<'a>(arg: Box<dyn X<Y() = ()>>) {}
+   |                           ^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/gat-trait-path-parenthesised-args.rs:4:8
+   |
+LL |   type Y<'a>;
+   |        ^ --
+help: add missing lifetime argument
+   |
+LL | fn bar<'a>(arg: Box<dyn X<Y('a) = ()>>) {}
+   |                             ++
+
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0107`.