From fcc76e93a0531e9e2db4ce2e0f68ab7988931755 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Fri, 17 Dec 2021 18:39:51 +0100 Subject: [PATCH] Initial support for `#[rustc_legacy_const_generics]` --- crates/hir_def/src/data.rs | 32 ++++++++++++++++ crates/hir_ty/src/diagnostics/expr.rs | 37 +++++++++++++------ crates/hir_ty/src/lib.rs | 18 ++++++++- crates/hir_ty/src/lower.rs | 6 ++- .../src/handlers/mismatched_arg_count.rs | 32 ++++++++++++++++ 5 files changed, 110 insertions(+), 15 deletions(-) diff --git a/crates/hir_def/src/data.rs b/crates/hir_def/src/data.rs index b9f8c2f297..bf8bd931a5 100644 --- a/crates/hir_def/src/data.rs +++ b/crates/hir_def/src/data.rs @@ -26,6 +26,7 @@ pub struct FunctionData { pub attrs: Attrs, pub visibility: RawVisibility, pub abi: Option>, + pub legacy_const_generics_indices: Vec, flags: FnFlags, } @@ -58,6 +59,14 @@ impl FunctionData { 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 @@ impl FunctionData { 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 @@ impl FunctionData { } } +fn parse_rustc_legacy_const_generics(tt: &tt::Subtree) -> Vec { + 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, diff --git a/crates/hir_ty/src/diagnostics/expr.rs b/crates/hir_ty/src/diagnostics/expr.rs index 195c53c17e..7e1bf9ceea 100644 --- a/crates/hir_ty/src/diagnostics/expr.rs +++ b/crates/hir_ty/src/diagnostics/expr.rs @@ -235,20 +235,33 @@ impl ExprValidator { 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, - }); } } diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs index 320b170ee4..3e5f2d29df 100644 --- a/crates/hir_ty/src/lib.rs +++ b/crates/hir_ty/src/lib.rs @@ -175,6 +175,7 @@ pub fn make_canonical>( 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 type PolyFnSig = Binders; impl CallableSig { pub fn from_params_and_return(mut params: Vec, 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 @@ impl 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 @@ impl Fold for CallableSig { { 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, + }) } } diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs index 7373c9eb8b..596bf9ee0f 100644 --- a/crates/hir_ty/src/lower.rs +++ b/crates/hir_ty/src/lower.rs @@ -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 diff --git a/crates/ide_diagnostics/src/handlers/mismatched_arg_count.rs b/crates/ide_diagnostics/src/handlers/mismatched_arg_count.rs index 78716fc099..95a3ac1d51 100644 --- a/crates/ide_diagnostics/src/handlers/mismatched_arg_count.rs +++ b/crates/ide_diagnostics/src/handlers/mismatched_arg_count.rs @@ -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( + a: u8, + b: i8, +) {} + +fn f() { + mixed(0, "", -1, true); + mixed::<"", true>(0, -1); +} + +#[rustc_legacy_const_generics(1, 3)] +fn b( + 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 } "#, )