aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_hir_def/src/data.rs2
-rw-r--r--crates/ra_hir_def/src/item_tree.rs1
-rw-r--r--crates/ra_hir_def/src/item_tree/lower.rs9
-rw-r--r--crates/ra_hir_def/src/type_ref.rs13
-rw-r--r--crates/ra_hir_ty/src/diagnostics/expr.rs30
-rw-r--r--crates/ra_hir_ty/src/display.rs11
-rw-r--r--crates/ra_hir_ty/src/infer/expr.rs2
-rw-r--r--crates/ra_hir_ty/src/lib.rs19
-rw-r--r--crates/ra_hir_ty/src/lower.rs13
-rw-r--r--crates/ra_hir_ty/src/traits/builtin.rs2
-rw-r--r--crates/ra_hir_ty/src/traits/chalk/mapping.rs7
11 files changed, 87 insertions, 22 deletions
diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs
index aa335f1e3..88a8ef9bf 100644
--- a/crates/ra_hir_def/src/data.rs
+++ b/crates/ra_hir_def/src/data.rs
@@ -27,6 +27,7 @@ pub struct FunctionData {
27 /// can be called as a method. 27 /// can be called as a method.
28 pub has_self_param: bool, 28 pub has_self_param: bool,
29 pub is_unsafe: bool, 29 pub is_unsafe: bool,
30 pub is_varargs: bool,
30 pub visibility: RawVisibility, 31 pub visibility: RawVisibility,
31} 32}
32 33
@@ -43,6 +44,7 @@ impl FunctionData {
43 attrs: item_tree.attrs(ModItem::from(loc.id.value).into()).clone(), 44 attrs: item_tree.attrs(ModItem::from(loc.id.value).into()).clone(),
44 has_self_param: func.has_self_param, 45 has_self_param: func.has_self_param,
45 is_unsafe: func.is_unsafe, 46 is_unsafe: func.is_unsafe,
47 is_varargs: func.is_varargs,
46 visibility: item_tree[func.visibility].clone(), 48 visibility: item_tree[func.visibility].clone(),
47 }) 49 })
48 } 50 }
diff --git a/crates/ra_hir_def/src/item_tree.rs b/crates/ra_hir_def/src/item_tree.rs
index 3e603bd55..da79d8ffd 100644
--- a/crates/ra_hir_def/src/item_tree.rs
+++ b/crates/ra_hir_def/src/item_tree.rs
@@ -503,6 +503,7 @@ pub struct Function {
503 pub has_self_param: bool, 503 pub has_self_param: bool,
504 pub is_unsafe: bool, 504 pub is_unsafe: bool,
505 pub params: Box<[TypeRef]>, 505 pub params: Box<[TypeRef]>,
506 pub is_varargs: bool,
506 pub ret_type: TypeRef, 507 pub ret_type: TypeRef,
507 pub ast_id: FileAstId<ast::FnDef>, 508 pub ast_id: FileAstId<ast::FnDef>,
508} 509}
diff --git a/crates/ra_hir_def/src/item_tree/lower.rs b/crates/ra_hir_def/src/item_tree/lower.rs
index 4182a9e3b..f79b8fca3 100644
--- a/crates/ra_hir_def/src/item_tree/lower.rs
+++ b/crates/ra_hir_def/src/item_tree/lower.rs
@@ -313,6 +313,14 @@ impl Ctx {
313 params.push(type_ref); 313 params.push(type_ref);
314 } 314 }
315 } 315 }
316
317 let mut is_varargs = false;
318 if let Some(params) = func.param_list() {
319 if let Some(last) = params.params().last() {
320 is_varargs = last.dotdotdot_token().is_some();
321 }
322 }
323
316 let ret_type = match func.ret_type().and_then(|rt| rt.type_ref()) { 324 let ret_type = match func.ret_type().and_then(|rt| rt.type_ref()) {
317 Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref), 325 Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref),
318 _ => TypeRef::unit(), 326 _ => TypeRef::unit(),
@@ -334,6 +342,7 @@ impl Ctx {
334 has_self_param, 342 has_self_param,
335 is_unsafe: func.unsafe_token().is_some(), 343 is_unsafe: func.unsafe_token().is_some(),
336 params: params.into_boxed_slice(), 344 params: params.into_boxed_slice(),
345 is_varargs,
337 ret_type, 346 ret_type,
338 ast_id, 347 ast_id,
339 }; 348 };
diff --git a/crates/ra_hir_def/src/type_ref.rs b/crates/ra_hir_def/src/type_ref.rs
index 86a77b704..e90b2a0b9 100644
--- a/crates/ra_hir_def/src/type_ref.rs
+++ b/crates/ra_hir_def/src/type_ref.rs
@@ -63,7 +63,7 @@ pub enum TypeRef {
63 Array(Box<TypeRef> /*, Expr*/), 63 Array(Box<TypeRef> /*, Expr*/),
64 Slice(Box<TypeRef>), 64 Slice(Box<TypeRef>),
65 /// A fn pointer. Last element of the vector is the return type. 65 /// A fn pointer. Last element of the vector is the return type.
66 Fn(Vec<TypeRef>), 66 Fn(Vec<TypeRef>, bool /*varargs*/),
67 // For 67 // For
68 ImplTrait(Vec<TypeBound>), 68 ImplTrait(Vec<TypeBound>),
69 DynTrait(Vec<TypeBound>), 69 DynTrait(Vec<TypeBound>),
@@ -118,7 +118,12 @@ impl TypeRef {
118 .and_then(|rt| rt.type_ref()) 118 .and_then(|rt| rt.type_ref())
119 .map(|it| TypeRef::from_ast(ctx, it)) 119 .map(|it| TypeRef::from_ast(ctx, it))
120 .unwrap_or_else(|| TypeRef::Tuple(Vec::new())); 120 .unwrap_or_else(|| TypeRef::Tuple(Vec::new()));
121 let mut is_varargs = false;
121 let mut params = if let Some(pl) = inner.param_list() { 122 let mut params = if let Some(pl) = inner.param_list() {
123 if let Some(param) = pl.params().last() {
124 is_varargs = param.dotdotdot_token().is_some();
125 }
126
122 pl.params() 127 pl.params()
123 .map(|p| p.ascribed_type()) 128 .map(|p| p.ascribed_type())
124 .map(|it| TypeRef::from_ast_opt(&ctx, it)) 129 .map(|it| TypeRef::from_ast_opt(&ctx, it))
@@ -127,7 +132,7 @@ impl TypeRef {
127 Vec::new() 132 Vec::new()
128 }; 133 };
129 params.push(ret_ty); 134 params.push(ret_ty);
130 TypeRef::Fn(params) 135 TypeRef::Fn(params, is_varargs)
131 } 136 }
132 // for types are close enough for our purposes to the inner type for now... 137 // for types are close enough for our purposes to the inner type for now...
133 ast::TypeRef::ForType(inner) => TypeRef::from_ast_opt(&ctx, inner.type_ref()), 138 ast::TypeRef::ForType(inner) => TypeRef::from_ast_opt(&ctx, inner.type_ref()),
@@ -158,7 +163,9 @@ impl TypeRef {
158 fn go(type_ref: &TypeRef, f: &mut impl FnMut(&TypeRef)) { 163 fn go(type_ref: &TypeRef, f: &mut impl FnMut(&TypeRef)) {
159 f(type_ref); 164 f(type_ref);
160 match type_ref { 165 match type_ref {
161 TypeRef::Fn(types) | TypeRef::Tuple(types) => types.iter().for_each(|t| go(t, f)), 166 TypeRef::Fn(types, _) | TypeRef::Tuple(types) => {
167 types.iter().for_each(|t| go(t, f))
168 }
162 TypeRef::RawPtr(type_ref, _) 169 TypeRef::RawPtr(type_ref, _)
163 | TypeRef::Reference(type_ref, _) 170 | TypeRef::Reference(type_ref, _)
164 | TypeRef::Array(type_ref) 171 | TypeRef::Array(type_ref)
diff --git a/crates/ra_hir_ty/src/diagnostics/expr.rs b/crates/ra_hir_ty/src/diagnostics/expr.rs
index 21ff99a8c..557d01cdc 100644
--- a/crates/ra_hir_ty/src/diagnostics/expr.rs
+++ b/crates/ra_hir_ty/src/diagnostics/expr.rs
@@ -175,6 +175,10 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
175 }; 175 };
176 176
177 let sig = db.callable_item_signature(callee); 177 let sig = db.callable_item_signature(callee);
178 if sig.value.is_varargs {
179 return None;
180 }
181
178 let params = sig.value.params(); 182 let params = sig.value.params();
179 183
180 let mut param_count = params.len(); 184 let mut param_count = params.len();
@@ -512,4 +516,30 @@ impl Foo {
512 "#, 516 "#,
513 ); 517 );
514 } 518 }
519
520 #[test]
521 fn varargs() {
522 check_diagnostics(
523 r#"
524extern "C" {
525 fn fixed(fixed: u8);
526 fn varargs(fixed: u8, ...);
527 fn varargs2(...);
528}
529
530fn f() {
531 unsafe {
532 fixed(0);
533 fixed(0, 1);
534 //^^^^^^^^^^^ Expected 1 argument, found 2
535 varargs(0);
536 varargs(0, 1);
537 varargs2();
538 varargs2(0);
539 varargs2(0, 1);
540 }
541}
542 "#,
543 )
544 }
515} 545}
diff --git a/crates/ra_hir_ty/src/display.rs b/crates/ra_hir_ty/src/display.rs
index ac68c5661..c860c254c 100644
--- a/crates/ra_hir_ty/src/display.rs
+++ b/crates/ra_hir_ty/src/display.rs
@@ -243,10 +243,17 @@ impl HirDisplay for ApplicationTy {
243 write!(f, ")")?; 243 write!(f, ")")?;
244 } 244 }
245 } 245 }
246 TypeCtor::FnPtr { .. } => { 246 TypeCtor::FnPtr { is_varargs, .. } => {
247 let sig = FnSig::from_fn_ptr_substs(&self.parameters); 247 let sig = FnSig::from_fn_ptr_substs(&self.parameters, is_varargs);
248 write!(f, "fn(")?; 248 write!(f, "fn(")?;
249 f.write_joined(sig.params(), ", ")?; 249 f.write_joined(sig.params(), ", ")?;
250 if is_varargs {
251 if sig.params().is_empty() {
252 write!(f, "...")?;
253 } else {
254 write!(f, ", ...")?;
255 }
256 }
250 write!(f, ")")?; 257 write!(f, ")")?;
251 let ret = sig.ret(); 258 let ret = sig.ret();
252 if *ret != Ty::unit() { 259 if *ret != Ty::unit() {
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs
index bd9a387f5..ab586b018 100644
--- a/crates/ra_hir_ty/src/infer/expr.rs
+++ b/crates/ra_hir_ty/src/infer/expr.rs
@@ -220,7 +220,7 @@ impl<'a> InferenceContext<'a> {
220 }; 220 };
221 sig_tys.push(ret_ty.clone()); 221 sig_tys.push(ret_ty.clone());
222 let sig_ty = Ty::apply( 222 let sig_ty = Ty::apply(
223 TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1 }, 223 TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1, is_varargs: false },
224 Substs(sig_tys.clone().into()), 224 Substs(sig_tys.clone().into()),
225 ); 225 );
226 let closure_ty = 226 let closure_ty =
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs
index d54568e67..c4c24a83b 100644
--- a/crates/ra_hir_ty/src/lib.rs
+++ b/crates/ra_hir_ty/src/lib.rs
@@ -112,7 +112,7 @@ pub enum TypeCtor {
112 /// fn foo() -> i32 { 1 } 112 /// fn foo() -> i32 { 1 }
113 /// let bar: fn() -> i32 = foo; 113 /// let bar: fn() -> i32 = foo;
114 /// ``` 114 /// ```
115 FnPtr { num_args: u16 }, 115 FnPtr { num_args: u16, is_varargs: bool },
116 116
117 /// The never type `!`. 117 /// The never type `!`.
118 Never, 118 Never,
@@ -187,7 +187,7 @@ impl TypeCtor {
187 } 187 }
188 } 188 }
189 } 189 }
190 TypeCtor::FnPtr { num_args } => num_args as usize + 1, 190 TypeCtor::FnPtr { num_args, is_varargs: _ } => num_args as usize + 1,
191 TypeCtor::Tuple { cardinality } => cardinality as usize, 191 TypeCtor::Tuple { cardinality } => cardinality as usize,
192 } 192 }
193 } 193 }
@@ -667,19 +667,20 @@ pub enum TyKind {
667#[derive(Clone, PartialEq, Eq, Debug)] 667#[derive(Clone, PartialEq, Eq, Debug)]
668pub struct FnSig { 668pub struct FnSig {
669 params_and_return: Arc<[Ty]>, 669 params_and_return: Arc<[Ty]>,
670 is_varargs: bool,
670} 671}
671 672
672/// A polymorphic function signature. 673/// A polymorphic function signature.
673pub type PolyFnSig = Binders<FnSig>; 674pub type PolyFnSig = Binders<FnSig>;
674 675
675impl FnSig { 676impl FnSig {
676 pub fn from_params_and_return(mut params: Vec<Ty>, ret: Ty) -> FnSig { 677 pub fn from_params_and_return(mut params: Vec<Ty>, ret: Ty, is_varargs: bool) -> FnSig {
677 params.push(ret); 678 params.push(ret);
678 FnSig { params_and_return: params.into() } 679 FnSig { params_and_return: params.into(), is_varargs }
679 } 680 }
680 681
681 pub fn from_fn_ptr_substs(substs: &Substs) -> FnSig { 682 pub fn from_fn_ptr_substs(substs: &Substs, is_varargs: bool) -> FnSig {
682 FnSig { params_and_return: Arc::clone(&substs.0) } 683 FnSig { params_and_return: Arc::clone(&substs.0), is_varargs }
683 } 684 }
684 685
685 pub fn params(&self) -> &[Ty] { 686 pub fn params(&self) -> &[Ty] {
@@ -724,7 +725,7 @@ impl Ty {
724 } 725 }
725 pub fn fn_ptr(sig: FnSig) -> Self { 726 pub fn fn_ptr(sig: FnSig) -> Self {
726 Ty::apply( 727 Ty::apply(
727 TypeCtor::FnPtr { num_args: sig.params().len() as u16 }, 728 TypeCtor::FnPtr { num_args: sig.params().len() as u16, is_varargs: sig.is_varargs },
728 Substs(sig.params_and_return), 729 Substs(sig.params_and_return),
729 ) 730 )
730 } 731 }
@@ -821,7 +822,9 @@ impl Ty {
821 fn callable_sig(&self, db: &dyn HirDatabase) -> Option<FnSig> { 822 fn callable_sig(&self, db: &dyn HirDatabase) -> Option<FnSig> {
822 match self { 823 match self {
823 Ty::Apply(a_ty) => match a_ty.ctor { 824 Ty::Apply(a_ty) => match a_ty.ctor {
824 TypeCtor::FnPtr { .. } => Some(FnSig::from_fn_ptr_substs(&a_ty.parameters)), 825 TypeCtor::FnPtr { is_varargs, .. } => {
826 Some(FnSig::from_fn_ptr_substs(&a_ty.parameters, is_varargs))
827 }
825 TypeCtor::FnDef(def) => { 828 TypeCtor::FnDef(def) => {
826 let sig = db.callable_item_signature(def); 829 let sig = db.callable_item_signature(def);
827 Some(sig.subst(&a_ty.parameters)) 830 Some(sig.subst(&a_ty.parameters))
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs
index 101b8aebe..6f4398e84 100644
--- a/crates/ra_hir_ty/src/lower.rs
+++ b/crates/ra_hir_ty/src/lower.rs
@@ -176,9 +176,12 @@ impl Ty {
176 Ty::apply_one(TypeCtor::Ref(*mutability), inner_ty) 176 Ty::apply_one(TypeCtor::Ref(*mutability), inner_ty)
177 } 177 }
178 TypeRef::Placeholder => Ty::Unknown, 178 TypeRef::Placeholder => Ty::Unknown,
179 TypeRef::Fn(params) => { 179 TypeRef::Fn(params, is_varargs) => {
180 let sig = Substs(params.iter().map(|tr| Ty::from_hir(ctx, tr)).collect()); 180 let sig = Substs(params.iter().map(|tr| Ty::from_hir(ctx, tr)).collect());
181 Ty::apply(TypeCtor::FnPtr { num_args: sig.len() as u16 - 1 }, sig) 181 Ty::apply(
182 TypeCtor::FnPtr { num_args: sig.len() as u16 - 1, is_varargs: *is_varargs },
183 sig,
184 )
182 } 185 }
183 TypeRef::DynTrait(bounds) => { 186 TypeRef::DynTrait(bounds) => {
184 let self_ty = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0)); 187 let self_ty = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0));
@@ -996,7 +999,7 @@ fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
996 let ret = Ty::from_hir(&ctx_ret, &data.ret_type); 999 let ret = Ty::from_hir(&ctx_ret, &data.ret_type);
997 let generics = generics(db.upcast(), def.into()); 1000 let generics = generics(db.upcast(), def.into());
998 let num_binders = generics.len(); 1001 let num_binders = generics.len();
999 Binders::new(num_binders, FnSig::from_params_and_return(params, ret)) 1002 Binders::new(num_binders, FnSig::from_params_and_return(params, ret, data.is_varargs))
1000} 1003}
1001 1004
1002/// Build the declared type of a function. This should not need to look at the 1005/// Build the declared type of a function. This should not need to look at the
@@ -1047,7 +1050,7 @@ fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnS
1047 let params = 1050 let params =
1048 fields.iter().map(|(_, field)| Ty::from_hir(&ctx, &field.type_ref)).collect::<Vec<_>>(); 1051 fields.iter().map(|(_, field)| Ty::from_hir(&ctx, &field.type_ref)).collect::<Vec<_>>();
1049 let ret = type_for_adt(db, def.into()); 1052 let ret = type_for_adt(db, def.into());
1050 Binders::new(ret.num_binders, FnSig::from_params_and_return(params, ret.value)) 1053 Binders::new(ret.num_binders, FnSig::from_params_and_return(params, ret.value, false))
1051} 1054}
1052 1055
1053/// Build the type of a tuple struct constructor. 1056/// Build the type of a tuple struct constructor.
@@ -1071,7 +1074,7 @@ fn fn_sig_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId)
1071 let params = 1074 let params =
1072 fields.iter().map(|(_, field)| Ty::from_hir(&ctx, &field.type_ref)).collect::<Vec<_>>(); 1075 fields.iter().map(|(_, field)| Ty::from_hir(&ctx, &field.type_ref)).collect::<Vec<_>>();
1073 let ret = type_for_adt(db, def.parent.into()); 1076 let ret = type_for_adt(db, def.parent.into());
1074 Binders::new(ret.num_binders, FnSig::from_params_and_return(params, ret.value)) 1077 Binders::new(ret.num_binders, FnSig::from_params_and_return(params, ret.value, false))
1075} 1078}
1076 1079
1077/// Build the type of a tuple enum variant constructor. 1080/// Build the type of a tuple enum variant constructor.
diff --git a/crates/ra_hir_ty/src/traits/builtin.rs b/crates/ra_hir_ty/src/traits/builtin.rs
index 86e22e459..60cc9a9f5 100644
--- a/crates/ra_hir_ty/src/traits/builtin.rs
+++ b/crates/ra_hir_ty/src/traits/builtin.rs
@@ -121,7 +121,7 @@ fn closure_fn_trait_impl_datum(
121 .build(), 121 .build(),
122 ); 122 );
123 let sig_ty = Ty::apply( 123 let sig_ty = Ty::apply(
124 TypeCtor::FnPtr { num_args }, 124 TypeCtor::FnPtr { num_args, is_varargs: false },
125 Substs::builder(num_args as usize + 1) 125 Substs::builder(num_args as usize + 1)
126 .fill_with_bound_vars(DebruijnIndex::INNERMOST, 0) 126 .fill_with_bound_vars(DebruijnIndex::INNERMOST, 0)
127 .build(), 127 .build(),
diff --git a/crates/ra_hir_ty/src/traits/chalk/mapping.rs b/crates/ra_hir_ty/src/traits/chalk/mapping.rs
index 06453ef82..5ba2ff51b 100644
--- a/crates/ra_hir_ty/src/traits/chalk/mapping.rs
+++ b/crates/ra_hir_ty/src/traits/chalk/mapping.rs
@@ -30,7 +30,7 @@ impl ToChalk for Ty {
30 Ty::Apply(apply_ty) => match apply_ty.ctor { 30 Ty::Apply(apply_ty) => match apply_ty.ctor {
31 TypeCtor::Ref(m) => ref_to_chalk(db, m, apply_ty.parameters), 31 TypeCtor::Ref(m) => ref_to_chalk(db, m, apply_ty.parameters),
32 TypeCtor::Array => array_to_chalk(db, apply_ty.parameters), 32 TypeCtor::Array => array_to_chalk(db, apply_ty.parameters),
33 TypeCtor::FnPtr { num_args: _ } => { 33 TypeCtor::FnPtr { num_args: _, is_varargs: _ } => {
34 let substitution = apply_ty.parameters.to_chalk(db).shifted_in(&Interner); 34 let substitution = apply_ty.parameters.to_chalk(db).shifted_in(&Interner);
35 chalk_ir::TyData::Function(chalk_ir::Fn { num_binders: 0, substitution }) 35 chalk_ir::TyData::Function(chalk_ir::Fn { num_binders: 0, substitution })
36 .intern(&Interner) 36 .intern(&Interner)
@@ -124,7 +124,10 @@ impl ToChalk for Ty {
124 substitution.shifted_out(&Interner).expect("fn ptr should have no binders"), 124 substitution.shifted_out(&Interner).expect("fn ptr should have no binders"),
125 ); 125 );
126 Ty::Apply(ApplicationTy { 126 Ty::Apply(ApplicationTy {
127 ctor: TypeCtor::FnPtr { num_args: (parameters.len() - 1) as u16 }, 127 ctor: TypeCtor::FnPtr {
128 num_args: (parameters.len() - 1) as u16,
129 is_varargs: false,
130 },
128 parameters, 131 parameters,
129 }) 132 })
130 } 133 }