]> git.lizzy.rs Git - rust.git/commitdiff
Initial support for `#[rustc_legacy_const_generics]`
authorJonas Schievink <jonas.schievink@ferrous-systems.com>
Fri, 17 Dec 2021 17:39:51 +0000 (18:39 +0100)
committerJonas Schievink <jonas.schievink@ferrous-systems.com>
Fri, 17 Dec 2021 17:45:56 +0000 (18:45 +0100)
crates/hir_def/src/data.rs
crates/hir_ty/src/diagnostics/expr.rs
crates/hir_ty/src/lib.rs
crates/hir_ty/src/lower.rs
crates/ide_diagnostics/src/handlers/mismatched_arg_count.rs

index b9f8c2f297acace94f1444db980c32cbec4266bf..bf8bd931a571a2d9db90ce1d5226bf887448a144 100644 (file)
@@ -26,6 +26,7 @@ pub struct FunctionData {
     pub attrs: Attrs,
     pub visibility: RawVisibility,
     pub abi: Option<Interned<str>>,
+    pub legacy_const_generics_indices: Vec<u32>,
     flags: FnFlags,
 }
 
@@ -58,6 +59,14 @@ pub(crate) fn fn_data_query(db: &dyn DefDatabase, func: FunctionId) -> Arc<Funct
             flags.bits |= FnFlags::IS_IN_EXTERN_BLOCK;
         }
 
+        let legacy_const_generics_indices = item_tree
+            .attrs(db, krate, ModItem::from(loc.id.value).into())
+            .by_key("rustc_legacy_const_generics")
+            .tt_values()
+            .next()
+            .map(|arg| parse_rustc_legacy_const_generics(arg))
+            .unwrap_or_default();
+
         Arc::new(FunctionData {
             name: func.name.clone(),
             params: enabled_params
@@ -72,6 +81,7 @@ pub(crate) fn fn_data_query(db: &dyn DefDatabase, func: FunctionId) -> Arc<Funct
             attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()),
             visibility: item_tree[func.visibility].clone(),
             abi: func.abi.clone(),
+            legacy_const_generics_indices,
             flags,
         })
     }
@@ -111,6 +121,28 @@ pub fn is_varargs(&self) -> bool {
     }
 }
 
+fn parse_rustc_legacy_const_generics(tt: &tt::Subtree) -> Vec<u32> {
+    let mut indices = Vec::new();
+    for args in tt.token_trees.chunks(2) {
+        match &args[0] {
+            tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) => match lit.text.parse() {
+                Ok(index) => indices.push(index),
+                Err(_) => break,
+            },
+            _ => break,
+        }
+
+        if let Some(comma) = args.get(1) {
+            match comma {
+                tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if punct.char == ',' => {}
+                _ => break,
+            }
+        }
+    }
+
+    indices
+}
+
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct TypeAliasData {
     pub name: Name,
index 195c53c17e211fb3a2f514e53a2f87b4a668e51a..7e1bf9ceea0666f84837f8e7c9a495404ca4a0d5 100644 (file)
@@ -235,20 +235,33 @@ fn validate_call(&mut self, db: &dyn HirDatabase, call_id: ExprId, expr: &Expr)
             return;
         }
 
-        let params = sig.params();
+        if sig.legacy_const_generics_indices.is_empty() {
+            let mut param_count = sig.params().len();
 
-        let mut param_count = params.len();
-
-        if arg_count != param_count {
-            if is_method_call {
-                param_count -= 1;
-                arg_count -= 1;
+            if arg_count != param_count {
+                if is_method_call {
+                    param_count -= 1;
+                    arg_count -= 1;
+                }
+                self.diagnostics.push(BodyValidationDiagnostic::MismatchedArgCount {
+                    call_expr: call_id,
+                    expected: param_count,
+                    found: arg_count,
+                });
+            }
+        } else {
+            // With `#[rustc_legacy_const_generics]` there are basically two parameter counts that
+            // are allowed.
+            let count_non_legacy = sig.params().len();
+            let count_legacy = sig.params().len() + sig.legacy_const_generics_indices.len();
+            if arg_count != count_non_legacy && arg_count != count_legacy {
+                self.diagnostics.push(BodyValidationDiagnostic::MismatchedArgCount {
+                    call_expr: call_id,
+                    // Since most users will use the legacy way to call them, report against that.
+                    expected: count_legacy,
+                    found: arg_count,
+                });
             }
-            self.diagnostics.push(BodyValidationDiagnostic::MismatchedArgCount {
-                call_expr: call_id,
-                expected: param_count,
-                found: arg_count,
-            });
         }
     }
 
index 320b170ee40f7cca139e2b4a084c01e443a06aa9..3e5f2d29df9024c3eda543199e2cf31c44edc1b5 100644 (file)
@@ -175,6 +175,7 @@ pub fn make_canonical<T: HasInterner<Interner = Interner>>(
 pub struct CallableSig {
     params_and_return: Arc<[Ty]>,
     is_varargs: bool,
+    legacy_const_generics_indices: Arc<[u32]>,
 }
 
 has_interner!(CallableSig);
@@ -185,7 +186,11 @@ pub struct CallableSig {
 impl CallableSig {
     pub fn from_params_and_return(mut params: Vec<Ty>, ret: Ty, is_varargs: bool) -> CallableSig {
         params.push(ret);
-        CallableSig { params_and_return: params.into(), is_varargs }
+        CallableSig {
+            params_and_return: params.into(),
+            is_varargs,
+            legacy_const_generics_indices: Arc::new([]),
+        }
     }
 
     pub fn from_fn_ptr(fn_ptr: &FnPointer) -> CallableSig {
@@ -202,9 +207,14 @@ pub fn from_fn_ptr(fn_ptr: &FnPointer) -> CallableSig {
                 .map(|arg| arg.assert_ty_ref(&Interner).clone())
                 .collect(),
             is_varargs: fn_ptr.sig.variadic,
+            legacy_const_generics_indices: Arc::new([]),
         }
     }
 
+    pub fn set_legacy_const_generics_indices(&mut self, indices: &[u32]) {
+        self.legacy_const_generics_indices = indices.into();
+    }
+
     pub fn to_fn_ptr(&self) -> FnPointer {
         FnPointer {
             num_binders: 0,
@@ -238,7 +248,11 @@ fn fold_with<'i, E>(
     {
         let vec = self.params_and_return.to_vec();
         let folded = vec.fold_with(folder, outer_binder)?;
-        Ok(CallableSig { params_and_return: folded.into(), is_varargs: self.is_varargs })
+        Ok(CallableSig {
+            params_and_return: folded.into(),
+            is_varargs: self.is_varargs,
+            legacy_const_generics_indices: self.legacy_const_generics_indices,
+        })
     }
 }
 
index 7373c9eb8b4b84c143f25cabd295c0abe91b9137..596bf9ee0fd657ccc620e86970b9facb4e7828fc 100644 (file)
@@ -1286,7 +1286,11 @@ fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
         .with_type_param_mode(TypeParamLoweringMode::Variable);
     let ret = ctx_ret.lower_ty(&data.ret_type);
     let generics = generics(db.upcast(), def.into());
-    make_binders(&generics, CallableSig::from_params_and_return(params, ret, data.is_varargs()))
+    let mut sig = CallableSig::from_params_and_return(params, ret, data.is_varargs());
+    if !data.legacy_const_generics_indices.is_empty() {
+        sig.set_legacy_const_generics_indices(&data.legacy_const_generics_indices);
+    }
+    make_binders(&generics, sig)
 }
 
 /// Build the declared type of a function. This should not need to look at the
index 78716fc09936d6d0ed342b94729d2617470b5abe..95a3ac1d519ba417abd4c4af3dcb5b3bc8208f57 100644 (file)
@@ -305,6 +305,38 @@ fn main() {
         fixed(0);
         varargs(1, 2, 3);
     }
+}
+            "#,
+        )
+    }
+
+    #[test]
+    fn legacy_const_generics() {
+        check_diagnostics(
+            r#"
+#[rustc_legacy_const_generics(1, 3)]
+fn mixed<const N1: &'static str, const N2: bool>(
+    a: u8,
+    b: i8,
+) {}
+
+fn f() {
+    mixed(0, "", -1, true);
+    mixed::<"", true>(0, -1);
+}
+
+#[rustc_legacy_const_generics(1, 3)]
+fn b<const N1: u8, const N2: u8>(
+    a: u8,
+    b: u8,
+) {}
+
+fn g() {
+    b(0, 1, 2, 3);
+    b::<1, 3>(0, 2);
+
+    b(0, 1, 2);
+           //^ error: expected 4 arguments, found 3
 }
             "#,
         )