]> git.lizzy.rs Git - rust.git/commitdiff
Thread varargs through r-a
authorJonas Schievink <jonas.schievink@ferrous-systems.com>
Tue, 14 Jul 2020 16:23:45 +0000 (18:23 +0200)
committerJonas Schievink <jonasschievink@gmail.com>
Tue, 14 Jul 2020 18:27:47 +0000 (20:27 +0200)
crates/ra_hir_def/src/data.rs
crates/ra_hir_def/src/item_tree.rs
crates/ra_hir_def/src/item_tree/lower.rs
crates/ra_hir_def/src/type_ref.rs
crates/ra_hir_ty/src/diagnostics/expr.rs
crates/ra_hir_ty/src/display.rs
crates/ra_hir_ty/src/infer/expr.rs
crates/ra_hir_ty/src/lib.rs
crates/ra_hir_ty/src/lower.rs
crates/ra_hir_ty/src/traits/builtin.rs
crates/ra_hir_ty/src/traits/chalk/mapping.rs

index aa335f1e302dd6d3eb6a54d5c01b1e86684fc3fb..88a8ef9bffebedec08f3181688aed1bd15c2c518 100644 (file)
@@ -27,6 +27,7 @@ pub struct FunctionData {
     /// can be called as a method.
     pub has_self_param: bool,
     pub is_unsafe: bool,
+    pub is_varargs: bool,
     pub visibility: RawVisibility,
 }
 
@@ -43,6 +44,7 @@ pub(crate) fn fn_data_query(db: &dyn DefDatabase, func: FunctionId) -> Arc<Funct
             attrs: item_tree.attrs(ModItem::from(loc.id.value).into()).clone(),
             has_self_param: func.has_self_param,
             is_unsafe: func.is_unsafe,
+            is_varargs: func.is_varargs,
             visibility: item_tree[func.visibility].clone(),
         })
     }
index 3e603bd55841e5c6a0a05ee59971fcb42913fdb7..da79d8ffd87f77e161e2fb2ad65a213cff945423 100644 (file)
@@ -503,6 +503,7 @@ pub struct Function {
     pub has_self_param: bool,
     pub is_unsafe: bool,
     pub params: Box<[TypeRef]>,
+    pub is_varargs: bool,
     pub ret_type: TypeRef,
     pub ast_id: FileAstId<ast::FnDef>,
 }
index 4182a9e3b650ecf6a9fec0a515c7f6cfbeb86dc3..f79b8fca3d79b876ca465884f2d320c030956118 100644 (file)
@@ -313,6 +313,14 @@ fn lower_function(&mut self, func: &ast::FnDef) -> Option<FileItemTreeId<Functio
                 params.push(type_ref);
             }
         }
+
+        let mut is_varargs = false;
+        if let Some(params) = func.param_list() {
+            if let Some(last) = params.params().last() {
+                is_varargs = last.dotdotdot_token().is_some();
+            }
+        }
+
         let ret_type = match func.ret_type().and_then(|rt| rt.type_ref()) {
             Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref),
             _ => TypeRef::unit(),
@@ -334,6 +342,7 @@ fn lower_function(&mut self, func: &ast::FnDef) -> Option<FileItemTreeId<Functio
             has_self_param,
             is_unsafe: func.unsafe_token().is_some(),
             params: params.into_boxed_slice(),
+            is_varargs,
             ret_type,
             ast_id,
         };
index 86a77b7046d44cc082d901d80a12bfd680e2b876..e90b2a0b9289e7c295ed368a9eed2eab9e0b5627 100644 (file)
@@ -63,7 +63,7 @@ pub enum TypeRef {
     Array(Box<TypeRef> /*, Expr*/),
     Slice(Box<TypeRef>),
     /// A fn pointer. Last element of the vector is the return type.
-    Fn(Vec<TypeRef>),
+    Fn(Vec<TypeRef>, bool /*varargs*/),
     // For
     ImplTrait(Vec<TypeBound>),
     DynTrait(Vec<TypeBound>),
@@ -118,7 +118,12 @@ pub(crate) fn from_ast(ctx: &LowerCtx, node: ast::TypeRef) -> Self {
                     .and_then(|rt| rt.type_ref())
                     .map(|it| TypeRef::from_ast(ctx, it))
                     .unwrap_or_else(|| TypeRef::Tuple(Vec::new()));
+                let mut is_varargs = false;
                 let mut params = if let Some(pl) = inner.param_list() {
+                    if let Some(param) = pl.params().last() {
+                        is_varargs = param.dotdotdot_token().is_some();
+                    }
+
                     pl.params()
                         .map(|p| p.ascribed_type())
                         .map(|it| TypeRef::from_ast_opt(&ctx, it))
@@ -127,7 +132,7 @@ pub(crate) fn from_ast(ctx: &LowerCtx, node: ast::TypeRef) -> Self {
                     Vec::new()
                 };
                 params.push(ret_ty);
-                TypeRef::Fn(params)
+                TypeRef::Fn(params, is_varargs)
             }
             // for types are close enough for our purposes to the inner type for now...
             ast::TypeRef::ForType(inner) => TypeRef::from_ast_opt(&ctx, inner.type_ref()),
@@ -158,7 +163,9 @@ pub fn walk(&self, f: &mut impl FnMut(&TypeRef)) {
         fn go(type_ref: &TypeRef, f: &mut impl FnMut(&TypeRef)) {
             f(type_ref);
             match type_ref {
-                TypeRef::Fn(types) | TypeRef::Tuple(types) => types.iter().for_each(|t| go(t, f)),
+                TypeRef::Fn(types, _) | TypeRef::Tuple(types) => {
+                    types.iter().for_each(|t| go(t, f))
+                }
                 TypeRef::RawPtr(type_ref, _)
                 | TypeRef::Reference(type_ref, _)
                 | TypeRef::Array(type_ref)
index 21ff99a8c966f5e4ad10c710ea9cb9859f2902d8..557d01cdc9fd23246acabc7153f702b5dd7c43fb 100644 (file)
@@ -175,6 +175,10 @@ fn validate_call(&mut self, db: &dyn HirDatabase, call_id: ExprId, expr: &Expr)
         };
 
         let sig = db.callable_item_signature(callee);
+        if sig.value.is_varargs {
+            return None;
+        }
+
         let params = sig.value.params();
 
         let mut param_count = params.len();
@@ -512,4 +516,30 @@ fn new() {
         "#,
         );
     }
+
+    #[test]
+    fn varargs() {
+        check_diagnostics(
+            r#"
+extern "C" {
+    fn fixed(fixed: u8);
+    fn varargs(fixed: u8, ...);
+    fn varargs2(...);
+}
+
+fn f() {
+    unsafe {
+        fixed(0);
+        fixed(0, 1);
+      //^^^^^^^^^^^ Expected 1 argument, found 2
+        varargs(0);
+        varargs(0, 1);
+        varargs2();
+        varargs2(0);
+        varargs2(0, 1);
+    }
+}
+        "#,
+        )
+    }
 }
index ac68c5661edcb397ad6e1c8160b9ec101f6de4d5..c860c254ca43ae7f41b64dbad02c68d882166f69 100644 (file)
@@ -243,10 +243,17 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
                     write!(f, ")")?;
                 }
             }
-            TypeCtor::FnPtr { .. } => {
-                let sig = FnSig::from_fn_ptr_substs(&self.parameters);
+            TypeCtor::FnPtr { is_varargs, .. } => {
+                let sig = FnSig::from_fn_ptr_substs(&self.parameters, is_varargs);
                 write!(f, "fn(")?;
                 f.write_joined(sig.params(), ", ")?;
+                if is_varargs {
+                    if sig.params().is_empty() {
+                        write!(f, "...")?;
+                    } else {
+                        write!(f, ", ...")?;
+                    }
+                }
                 write!(f, ")")?;
                 let ret = sig.ret();
                 if *ret != Ty::unit() {
index bd9a387f5881c8fe235d262a506d1df2339e2b47..ab586b018dd0a95a7b4cd014215db730d3b8e874 100644 (file)
@@ -220,7 +220,7 @@ fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
                 };
                 sig_tys.push(ret_ty.clone());
                 let sig_ty = Ty::apply(
-                    TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1 },
+                    TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1, is_varargs: false },
                     Substs(sig_tys.clone().into()),
                 );
                 let closure_ty =
index d54568e67a1588c37433027b3dc5b9cfcf538951..c4c24a83b0cb319db0172b3725945e48787c3fe7 100644 (file)
@@ -112,7 +112,7 @@ pub enum TypeCtor {
     /// fn foo() -> i32 { 1 }
     /// let bar: fn() -> i32 = foo;
     /// ```
-    FnPtr { num_args: u16 },
+    FnPtr { num_args: u16, is_varargs: bool },
 
     /// The never type `!`.
     Never,
@@ -187,7 +187,7 @@ pub fn num_ty_params(self, db: &dyn HirDatabase) -> usize {
                     }
                 }
             }
-            TypeCtor::FnPtr { num_args } => num_args as usize + 1,
+            TypeCtor::FnPtr { num_args, is_varargs: _ } => num_args as usize + 1,
             TypeCtor::Tuple { cardinality } => cardinality as usize,
         }
     }
@@ -667,19 +667,20 @@ pub enum TyKind {
 #[derive(Clone, PartialEq, Eq, Debug)]
 pub struct FnSig {
     params_and_return: Arc<[Ty]>,
+    is_varargs: bool,
 }
 
 /// A polymorphic function signature.
 pub type PolyFnSig = Binders<FnSig>;
 
 impl FnSig {
-    pub fn from_params_and_return(mut params: Vec<Ty>, ret: Ty) -> FnSig {
+    pub fn from_params_and_return(mut params: Vec<Ty>, ret: Ty, is_varargs: bool) -> FnSig {
         params.push(ret);
-        FnSig { params_and_return: params.into() }
+        FnSig { params_and_return: params.into(), is_varargs }
     }
 
-    pub fn from_fn_ptr_substs(substs: &Substs) -> FnSig {
-        FnSig { params_and_return: Arc::clone(&substs.0) }
+    pub fn from_fn_ptr_substs(substs: &Substs, is_varargs: bool) -> FnSig {
+        FnSig { params_and_return: Arc::clone(&substs.0), is_varargs }
     }
 
     pub fn params(&self) -> &[Ty] {
@@ -724,7 +725,7 @@ pub fn unit() -> Self {
     }
     pub fn fn_ptr(sig: FnSig) -> Self {
         Ty::apply(
-            TypeCtor::FnPtr { num_args: sig.params().len() as u16 },
+            TypeCtor::FnPtr { num_args: sig.params().len() as u16, is_varargs: sig.is_varargs },
             Substs(sig.params_and_return),
         )
     }
@@ -821,7 +822,9 @@ fn builtin_deref(&self) -> Option<Ty> {
     fn callable_sig(&self, db: &dyn HirDatabase) -> Option<FnSig> {
         match self {
             Ty::Apply(a_ty) => match a_ty.ctor {
-                TypeCtor::FnPtr { .. } => Some(FnSig::from_fn_ptr_substs(&a_ty.parameters)),
+                TypeCtor::FnPtr { is_varargs, .. } => {
+                    Some(FnSig::from_fn_ptr_substs(&a_ty.parameters, is_varargs))
+                }
                 TypeCtor::FnDef(def) => {
                     let sig = db.callable_item_signature(def);
                     Some(sig.subst(&a_ty.parameters))
index 101b8aebe5e54b1a71eaca9619660d7d55dda62a..6f4398e842230679f58925c429d61db37881dea2 100644 (file)
@@ -176,9 +176,12 @@ pub fn from_hir_ext(ctx: &TyLoweringContext<'_>, type_ref: &TypeRef) -> (Self, O
                 Ty::apply_one(TypeCtor::Ref(*mutability), inner_ty)
             }
             TypeRef::Placeholder => Ty::Unknown,
-            TypeRef::Fn(params) => {
+            TypeRef::Fn(params, is_varargs) => {
                 let sig = Substs(params.iter().map(|tr| Ty::from_hir(ctx, tr)).collect());
-                Ty::apply(TypeCtor::FnPtr { num_args: sig.len() as u16 - 1 }, sig)
+                Ty::apply(
+                    TypeCtor::FnPtr { num_args: sig.len() as u16 - 1, is_varargs: *is_varargs },
+                    sig,
+                )
             }
             TypeRef::DynTrait(bounds) => {
                 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 {
     let ret = Ty::from_hir(&ctx_ret, &data.ret_type);
     let generics = generics(db.upcast(), def.into());
     let num_binders = generics.len();
-    Binders::new(num_binders, FnSig::from_params_and_return(params, ret))
+    Binders::new(num_binders, FnSig::from_params_and_return(params, ret, data.is_varargs))
 }
 
 /// 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
     let params =
         fields.iter().map(|(_, field)| Ty::from_hir(&ctx, &field.type_ref)).collect::<Vec<_>>();
     let ret = type_for_adt(db, def.into());
-    Binders::new(ret.num_binders, FnSig::from_params_and_return(params, ret.value))
+    Binders::new(ret.num_binders, FnSig::from_params_and_return(params, ret.value, false))
 }
 
 /// Build the type of a tuple struct constructor.
@@ -1071,7 +1074,7 @@ fn fn_sig_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId)
     let params =
         fields.iter().map(|(_, field)| Ty::from_hir(&ctx, &field.type_ref)).collect::<Vec<_>>();
     let ret = type_for_adt(db, def.parent.into());
-    Binders::new(ret.num_binders, FnSig::from_params_and_return(params, ret.value))
+    Binders::new(ret.num_binders, FnSig::from_params_and_return(params, ret.value, false))
 }
 
 /// Build the type of a tuple enum variant constructor.
index 86e22e459542a669ac49a86b7fb333b749412917..60cc9a9f50c212be1f4997700a1dfe4de0ef4371 100644 (file)
@@ -121,7 +121,7 @@ fn closure_fn_trait_impl_datum(
             .build(),
     );
     let sig_ty = Ty::apply(
-        TypeCtor::FnPtr { num_args },
+        TypeCtor::FnPtr { num_args, is_varargs: false },
         Substs::builder(num_args as usize + 1)
             .fill_with_bound_vars(DebruijnIndex::INNERMOST, 0)
             .build(),
index 06453ef820810eba1520232df03f10d6a8476c7a..5ba2ff51b8881274bd7b3dafaa549759de54349c 100644 (file)
@@ -30,7 +30,7 @@ fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Ty<Interner> {
             Ty::Apply(apply_ty) => match apply_ty.ctor {
                 TypeCtor::Ref(m) => ref_to_chalk(db, m, apply_ty.parameters),
                 TypeCtor::Array => array_to_chalk(db, apply_ty.parameters),
-                TypeCtor::FnPtr { num_args: _ } => {
+                TypeCtor::FnPtr { num_args: _, is_varargs: _ } => {
                     let substitution = apply_ty.parameters.to_chalk(db).shifted_in(&Interner);
                     chalk_ir::TyData::Function(chalk_ir::Fn { num_binders: 0, substitution })
                         .intern(&Interner)
@@ -124,7 +124,10 @@ fn from_chalk(db: &dyn HirDatabase, chalk: chalk_ir::Ty<Interner>) -> Self {
                     substitution.shifted_out(&Interner).expect("fn ptr should have no binders"),
                 );
                 Ty::Apply(ApplicationTy {
-                    ctor: TypeCtor::FnPtr { num_args: (parameters.len() - 1) as u16 },
+                    ctor: TypeCtor::FnPtr {
+                        num_args: (parameters.len() - 1) as u16,
+                        is_varargs: false,
+                    },
                     parameters,
                 })
             }