]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_ast_passes/ast_validation.rs
Auto merge of #71664 - Dylan-DPC:rollup-eng60x9, r=Dylan-DPC
[rust.git] / src / librustc_ast_passes / ast_validation.rs
index 4c7edfc83fa333b319a09910dadbfc191d0d0c9a..395fd7460850f1de623bfbe733735eaa5d31501d 100644 (file)
@@ -6,6 +6,7 @@
 // This pass is supposed to perform only simple checks not requiring name resolution
 // or type checking or some other kind of complex analysis.
 
+use itertools::{Either, Itertools};
 use rustc_ast::ast::*;
 use rustc_ast::attr;
 use rustc_ast::expand::is_proc_macro_attr;
@@ -560,28 +561,6 @@ fn check_c_varadic_type(&self, fk: FnKind<'a>) {
         }
     }
 
-    /// We currently do not permit const generics in `const fn`,
-    /// as this is tantamount to allowing compile-time dependent typing.
-    ///
-    /// FIXME(const_generics): Is this really true / necessary? Discuss with @varkor.
-    /// At any rate, the restriction feels too syntactic. Consider moving it to e.g. typeck.
-    fn check_const_fn_const_generic(&self, span: Span, sig: &FnSig, generics: &Generics) {
-        if let Const::Yes(const_span) = sig.header.constness {
-            // Look for const generics and error if we find any.
-            for param in &generics.params {
-                if let GenericParamKind::Const { .. } = param.kind {
-                    self.err_handler()
-                        .struct_span_err(
-                            span,
-                            "const parameters are not permitted in const functions",
-                        )
-                        .span_label(const_span, "`const` because of this")
-                        .emit();
-                }
-            }
-        }
-    }
-
     fn check_item_named(&self, ident: Ident, kind: &str) {
         if ident.name != kw::Underscore {
             return;
@@ -640,6 +619,33 @@ fn deny_items(&self, trait_items: &[P<AssocItem>], ident_span: Span) {
         }
     }
 
+    fn correct_generic_order_suggestion(&self, data: &AngleBracketedArgs) -> String {
+        // Lifetimes always come first.
+        let lt_sugg = data.args.iter().filter_map(|arg| match arg {
+            AngleBracketedArg::Arg(lt @ GenericArg::Lifetime(_)) => {
+                Some(pprust::to_string(|s| s.print_generic_arg(lt)))
+            }
+            _ => None,
+        });
+        let args_sugg = data.args.iter().filter_map(|a| match a {
+            AngleBracketedArg::Arg(GenericArg::Lifetime(_)) | AngleBracketedArg::Constraint(_) => {
+                None
+            }
+            AngleBracketedArg::Arg(arg) => Some(pprust::to_string(|s| s.print_generic_arg(arg))),
+        });
+        // Constraints always come last.
+        let constraint_sugg = data.args.iter().filter_map(|a| match a {
+            AngleBracketedArg::Arg(_) => None,
+            AngleBracketedArg::Constraint(c) => {
+                Some(pprust::to_string(|s| s.print_assoc_constraint(c)))
+            }
+        });
+        format!(
+            "<{}>",
+            lt_sugg.chain(args_sugg).chain(constraint_sugg).collect::<Vec<String>>().join(", ")
+        )
+    }
+
     /// Enforce generic args coming before constraints in `<...>` of a path segment.
     fn check_generic_args_before_constraints(&self, data: &AngleBracketedArgs) {
         // Early exit in case it's partitioned as it should be.
@@ -647,36 +653,12 @@ fn check_generic_args_before_constraints(&self, data: &AngleBracketedArgs) {
             return;
         }
         // Find all generic argument coming after the first constraint...
-        let constraint_spans = data
-            .args
-            .iter()
-            .filter_map(|arg| match arg {
-                AngleBracketedArg::Constraint(c) => Some(c.span),
-                _ => None,
-            })
-            .collect::<Vec<_>>();
-        let arg_spans = data
-            .args
-            .iter()
-            .filter_map(|arg| match arg {
-                AngleBracketedArg::Arg(a) => Some(a.span()),
-                _ => None,
-            })
-            .collect::<Vec<_>>();
-        let snippet_span = match &constraint_spans[..] {
-            [single] => *single,
-            [first, .., last] => first.to(*last),
-            [] => unreachable!(),
-        };
-        let removal_span = match &arg_spans[..] {
-            [first, ..] => snippet_span.until(*first),
-            [] => unreachable!(),
-        };
-        let sugg_span = match &arg_spans[..] {
-            [.., last] => last.shrink_to_hi(),
-            [] => unreachable!(),
-        };
-        let snippet = self.session.source_map().span_to_snippet(snippet_span).unwrap();
+        let (constraint_spans, arg_spans): (Vec<Span>, Vec<Span>) =
+            data.args.iter().partition_map(|arg| match arg {
+                AngleBracketedArg::Constraint(c) => Either::Left(c.span),
+                AngleBracketedArg::Arg(a) => Either::Right(a.span()),
+            });
+        let args_len = arg_spans.len();
         let constraint_len = constraint_spans.len();
         // ...and then error:
         self.err_handler()
@@ -684,22 +666,21 @@ fn check_generic_args_before_constraints(&self, data: &AngleBracketedArgs) {
                 arg_spans.clone(),
                 "generic arguments must come before the first constraint",
             )
-            .span_labels(
-                constraint_spans,
+            .span_label(constraint_spans[0], &format!("constraint{}", pluralize!(constraint_len)))
+            .span_label(
+                *arg_spans.iter().last().unwrap(),
+                &format!("generic argument{}", pluralize!(args_len)),
+            )
+            .span_labels(constraint_spans, "")
+            .span_labels(arg_spans, "")
+            .span_suggestion_verbose(
+                data.span,
                 &format!(
-                    "the constraint{} {} provided here",
+                    "move the constraint{} after the generic argument{}",
                     pluralize!(constraint_len),
-                    if constraint_len == 1 { "is" } else { "are" }
+                    pluralize!(args_len)
                 ),
-            )
-            .span_labels(arg_spans, "generic argument")
-            .multipart_suggestion(
-                "move the constraints after the generic arguments",
-                vec![
-                    (removal_span, String::new()),
-                    (sugg_span.shrink_to_lo(), ", ".to_string()),
-                    (sugg_span, snippet),
-                ],
+                self.correct_generic_order_suggestion(&data),
                 Applicability::MachineApplicable,
             )
             .emit();
@@ -963,9 +944,8 @@ fn visit_item(&mut self, item: &'a Item) {
                         .emit();
                 }
             }
-            ItemKind::Fn(def, ref sig, ref generics, ref body) => {
+            ItemKind::Fn(def, _, _, ref body) => {
                 self.check_defaultness(item.span, def);
-                self.check_const_fn_const_generic(item.span, sig, generics);
 
                 if body.is_none() {
                     let msg = "free function without a body";