Fix incorrect handling of cfg'd varargs

This commit is contained in:
Lukas Wirth 2024-07-25 11:02:19 +02:00
parent 9cbafa2d49
commit f2fa456a8c
8 changed files with 37 additions and 16 deletions

View file

@ -73,6 +73,17 @@ impl FunctionData {
flags.remove(FnFlags::HAS_SELF_PARAM);
}
}
if flags.contains(FnFlags::IS_VARARGS) {
if let Some((_, param)) = func.params.iter().enumerate().rev().find(|&(idx, _)| {
item_tree.attrs(db, krate, attr_owner(idx)).is_cfg_enabled(cfg_options)
}) {
if param.type_ref.is_some() {
flags.remove(FnFlags::IS_VARARGS);
}
} else {
flags.remove(FnFlags::IS_VARARGS);
}
}
let attrs = item_tree.attrs(db, krate, ModItem::from(loc.id.value).into());
let legacy_const_generics_indices = attrs
@ -92,7 +103,7 @@ impl FunctionData {
.filter(|&(idx, _)| {
item_tree.attrs(db, krate, attr_owner(idx)).is_cfg_enabled(cfg_options)
})
.map(|(_, param)| param.type_ref.clone())
.filter_map(|(_, param)| param.type_ref.clone())
.collect(),
ret_type: func.ret_type.clone(),
attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()),

View file

@ -741,7 +741,7 @@ pub struct Function {
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Param {
pub type_ref: Interned<TypeRef>,
pub type_ref: Option<Interned<TypeRef>>,
}
bitflags::bitflags! {

View file

@ -380,7 +380,7 @@ impl<'a> Ctx<'a> {
}
};
let type_ref = Interned::new(self_type);
params.push(Param { type_ref });
params.push(Param { type_ref: Some(type_ref) });
has_self_param = true;
}
for param in param_list.params() {
@ -388,12 +388,12 @@ impl<'a> Ctx<'a> {
let param = match param.dotdotdot_token() {
Some(_) => {
has_var_args = true;
Param { type_ref: Interned::new(TypeRef::Error) }
Param { type_ref: None }
}
None => {
let type_ref = TypeRef::from_ast_opt(&self.body_ctx, param.ty());
let ty = Interned::new(type_ref);
Param { type_ref: ty }
Param { type_ref: Some(ty) }
}
};
params.push(param);

View file

@ -291,7 +291,7 @@ impl Printer<'_> {
if idx == 0 && flags.contains(FnFlags::HAS_SELF_PARAM) {
w!(this, "self: ");
}
if idx != params.len() {
if let Some(type_ref) = type_ref {
this.print_type_ref(type_ref);
} else {
wln!(this, "...");

View file

@ -812,9 +812,7 @@ impl<'a> InferenceContext<'a> {
None => self.err_ty(),
};
if let Some(ty) = param_tys.last_mut() {
*ty = va_list_ty;
}
param_tys.push(va_list_ty);
}
let mut param_tys = param_tys.into_iter().chain(iter::repeat(self.table.new_type_var()));
if let Some(self_param) = self.body.self_param {

View file

@ -1126,6 +1126,23 @@ fn var_args() {
pub struct VaListImpl<'f>;
fn my_fn(foo: ...) {}
//^^^ VaListImpl<'?>
fn my_fn2(bar: u32, foo: ...) {}
//^^^ VaListImpl<'?>
"#,
);
}
#[test]
fn var_args_cond() {
check_types(
r#"
#[lang = "va_list"]
pub struct VaListImpl<'f>;
fn my_fn(bar: u32, #[cfg(FALSE)] foo: ..., #[cfg(not(FALSE))] foo: u32) {
foo;
//^^^ u32
}
"#,
);
}

View file

@ -99,13 +99,7 @@ impl HirDisplay for Function {
}
// FIXME: Use resolved `param.ty` once we no longer discard lifetimes
for (type_ref, param) in data
.params
.iter()
.zip(self.assoc_fn_params(db))
.take(data.params.len() - data.is_varargs() as usize)
.skip(skip_self)
{
for (type_ref, param) in data.params.iter().zip(self.assoc_fn_params(db)).skip(skip_self) {
let local = param.as_local(db).map(|it| it.name(db));
if !first {
f.write_str(", ")?;

View file

@ -56,6 +56,7 @@ macro_rules! define_symbols {
define_symbols! {
@WITH_NAME:
dotdotdot = "...",
INTEGER_0 = "0",
INTEGER_1 = "1",
INTEGER_2 = "2",