]> git.lizzy.rs Git - rust.git/blobdiff - compiler/rustc_trait_selection/src/traits/on_unimplemented.rs
Allow substitutions in `rustc_on_unimplemented` predicate
[rust.git] / compiler / rustc_trait_selection / src / traits / on_unimplemented.rs
index 4840995275afaab42460166295f33b6197b8f975..bdf677a63b632d0de11c2700f64e62a0f81809f5 100644 (file)
@@ -19,6 +19,7 @@ pub struct OnUnimplementedDirective {
     pub label: Option<OnUnimplementedFormatString>,
     pub note: Option<OnUnimplementedFormatString>,
     pub enclosing_scope: Option<OnUnimplementedFormatString>,
+    pub append_const_msg: Option<Option<Symbol>>,
 }
 
 #[derive(Default)]
@@ -27,6 +28,11 @@ pub struct OnUnimplementedNote {
     pub label: Option<String>,
     pub note: Option<String>,
     pub enclosing_scope: Option<String>,
+    /// Append a message for `~const Trait` errors. `None` means not requested and
+    /// should fallback to a generic message, `Some(None)` suggests using the default
+    /// appended message, `Some(Some(s))` suggests use the `s` message instead of the
+    /// default one..
+    pub append_const_msg: Option<Option<Symbol>>,
 }
 
 fn parse_error(
@@ -56,6 +62,10 @@ fn parse(
         let mut errored = false;
         let mut item_iter = items.iter();
 
+        let parse_value = |value_str| {
+            OnUnimplementedFormatString::try_parse(tcx, trait_def_id, value_str, span).map(Some)
+        };
+
         let condition = if is_root {
             None
         } else {
@@ -80,7 +90,14 @@ fn parse(
                         None,
                     )
                 })?;
-            attr::eval_condition(cond, &tcx.sess.parse_sess, Some(tcx.features()), &mut |_| true);
+            attr::eval_condition(cond, &tcx.sess.parse_sess, Some(tcx.features()), &mut |item| {
+                if let Some(symbol) = item.value_str() {
+                    if parse_value(symbol).is_err() {
+                        errored = true;
+                    }
+                }
+                true
+            });
             Some(cond.clone())
         };
 
@@ -89,10 +106,7 @@ fn parse(
         let mut note = None;
         let mut enclosing_scope = None;
         let mut subcommands = vec![];
-
-        let parse_value = |value_str| {
-            OnUnimplementedFormatString::try_parse(tcx, trait_def_id, value_str, span).map(Some)
-        };
+        let mut append_const_msg = None;
 
         for item in item_iter {
             if item.has_name(sym::message) && message.is_none() {
@@ -131,6 +145,14 @@ fn parse(
                     }
                     continue;
                 }
+            } else if item.has_name(sym::append_const_msg) && append_const_msg.is_none() {
+                if let Some(msg) = item.value_str() {
+                    append_const_msg = Some(Some(msg));
+                    continue;
+                } else if item.is_word() {
+                    append_const_msg = Some(None);
+                    continue;
+                }
             }
 
             // nothing found
@@ -153,6 +175,7 @@ fn parse(
                 label,
                 note,
                 enclosing_scope,
+                append_const_msg,
             })
         }
     }
@@ -183,6 +206,7 @@ pub fn of_item(
                 )?),
                 note: None,
                 enclosing_scope: None,
+                append_const_msg: None,
             }))
         } else {
             return Err(ErrorReported);
@@ -201,8 +225,12 @@ pub fn evaluate(
         let mut label = None;
         let mut note = None;
         let mut enclosing_scope = None;
+        let mut append_const_msg = None;
         info!("evaluate({:?}, trait_ref={:?}, options={:?})", self, trait_ref, options);
 
+        let options_map: FxHashMap<Symbol, String> =
+            options.iter().filter_map(|(k, v)| v.as_ref().map(|v| (*k, v.to_owned()))).collect();
+
         for command in self.subcommands.iter().chain(Some(self)).rev() {
             if let Some(ref condition) = command.condition {
                 if !attr::eval_condition(
@@ -211,7 +239,11 @@ pub fn evaluate(
                     Some(tcx.features()),
                     &mut |c| {
                         c.ident().map_or(false, |ident| {
-                            options.contains(&(ident.name, c.value_str().map(|s| s.to_string())))
+                            let value = c.value_str().map(|s| {
+                                OnUnimplementedFormatString(s).format(tcx, trait_ref, &options_map)
+                            });
+
+                            options.contains(&(ident.name, value))
                         })
                     },
                 ) {
@@ -235,15 +267,16 @@ pub fn evaluate(
             if let Some(ref enclosing_scope_) = command.enclosing_scope {
                 enclosing_scope = Some(enclosing_scope_.clone());
             }
+
+            append_const_msg = command.append_const_msg.clone();
         }
 
-        let options: FxHashMap<Symbol, String> =
-            options.iter().filter_map(|(k, v)| v.as_ref().map(|v| (*k, v.to_owned()))).collect();
         OnUnimplementedNote {
-            label: label.map(|l| l.format(tcx, trait_ref, &options)),
-            message: message.map(|m| m.format(tcx, trait_ref, &options)),
-            note: note.map(|n| n.format(tcx, trait_ref, &options)),
-            enclosing_scope: enclosing_scope.map(|e_s| e_s.format(tcx, trait_ref, &options)),
+            label: label.map(|l| l.format(tcx, trait_ref, &options_map)),
+            message: message.map(|m| m.format(tcx, trait_ref, &options_map)),
+            note: note.map(|n| n.format(tcx, trait_ref, &options_map)),
+            enclosing_scope: enclosing_scope.map(|e_s| e_s.format(tcx, trait_ref, &options_map)),
+            append_const_msg,
         }
     }
 }
@@ -285,6 +318,12 @@ fn verify(
                     Position::ArgumentNamed(s) if s == sym::from_desugaring => (),
                     // `{ItemContext}` is allowed
                     Position::ArgumentNamed(s) if s == sym::ItemContext => (),
+                    // `{integral}` and `{integer}` and `{float}` are allowed
+                    Position::ArgumentNamed(s)
+                        if s == sym::integral || s == sym::integer_ || s == sym::float =>
+                    {
+                        ()
+                    }
                     // So is `{A}` if A is a type parameter
                     Position::ArgumentNamed(s) => {
                         match generics.params.iter().find(|param| param.name == s) {
@@ -364,6 +403,12 @@ pub fn format(
                                 &empty_string
                             } else if s == sym::ItemContext {
                                 &item_context
+                            } else if s == sym::integral {
+                                "{integral}"
+                            } else if s == sym::integer_ {
+                                "{integer}"
+                            } else if s == sym::float {
+                                "{float}"
                             } else {
                                 bug!(
                                     "broken on_unimplemented {:?} for {:?}: \