Skip to content

Commit

Permalink
fix: return type of extern functions must also be primitive
Browse files Browse the repository at this point in the history
  • Loading branch information
baszalmstra committed Mar 7, 2020
1 parent f796fda commit e5e9f91
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 12 deletions.
2 changes: 1 addition & 1 deletion crates/mun_hir/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -545,7 +545,7 @@ pub struct ExternNonPrimitiveParam {

impl Diagnostic for ExternNonPrimitiveParam {
fn message(&self) -> String {
"extern functions can only have primitives as parameters".to_string()
"extern functions can only have primitives as parameter- and return types".to_string()
}

fn source(&self) -> InFile<SyntaxNodePtr> {
Expand Down
33 changes: 24 additions & 9 deletions crates/mun_hir/src/expr/validator.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::code_model::src::HasSource;
use crate::diagnostics::{ExternCannotHaveBody, ExternNonPrimitiveParam};
use crate::expr::BodySourceMap;
use crate::in_file::InFile;
use crate::{diagnostics::DiagnosticSink, Body, Expr, Function, HirDatabase, InferenceResult};
use mun_syntax::{AstNode, SyntaxNodePtr};
use std::sync::Arc;
Expand Down Expand Up @@ -52,16 +53,30 @@ impl<'a, 'b, 'd, DB: HirDatabase> ExprValidator<'a, 'b, 'd, DB> {
}),
}

// Validate the arguments
for (arg, _) in &self.body.params {
let param_id = &self.infer[*arg];
if param_id.as_struct().is_some() {
if let Some(sig) = self.func.ty(self.db).callable_sig(self.db) {
let fn_data = self.func.data(self.db);
for (arg_ty, ty_ref) in sig.params().iter().zip(fn_data.params()) {
if arg_ty.as_struct().is_some() {
let arg_ptr = fn_data
.type_ref_source_map()
.type_ref_syntax(*ty_ref)
.map(|ptr| ptr.syntax_node_ptr())
.unwrap();
self.sink.push(ExternNonPrimitiveParam {
param: InFile::new(self.func.source(self.db).file_id, arg_ptr),
})
}
}

let return_ty = sig.ret();
if return_ty.as_struct().is_some() {
let arg_ptr = fn_data
.type_ref_source_map()
.type_ref_syntax(*fn_data.ret_type())
.map(|ptr| ptr.syntax_node_ptr())
.unwrap();
self.sink.push(ExternNonPrimitiveParam {
param: self
.body_source_map
.pat_syntax(*arg)
.unwrap()
.map(|arg| arg.syntax_node_ptr()),
param: InFile::new(self.func.source(self.db).file_id, arg_ptr),
})
}
}
Expand Down
5 changes: 3 additions & 2 deletions crates/mun_hir/src/ty/snapshots/tests__extern_fn.snap
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
---
source: crates/mun_hir/src/ty/tests.rs
expression: "extern fn foo(a:int, b:int): int;\nfn main() {\n foo(3,4);\n}\n\nextern fn with_body() {} // extern functions cannot have bodies\n\nstruct S;\nextern fn with_non_primitive(s:S); // extern functions can only have primitives as parameters"
expression: "extern fn foo(a:int, b:int): int;\nfn main() {\n foo(3,4);\n}\n\nextern fn with_body() {} // extern functions cannot have bodies\n\nstruct S;\nextern fn with_non_primitive(s:S); // extern functions can only have primitives as parameters\nextern fn with_non_primitive_return(): S; // extern functions can only have primitives as parameters"
---
[63; 87): extern functions cannot have bodies
[170; 171): extern functions can only have primitives as parameters
[172; 173): extern functions can only have primitives as parameter- and return types
[275; 276): extern functions can only have primitives as parameter- and return types
[14; 15) 'a': int
[21; 22) 'b': int
[44; 61) '{ ...,4); }': nothing
Expand Down
1 change: 1 addition & 0 deletions crates/mun_hir/src/ty/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ fn extern_fn() {
struct S;
extern fn with_non_primitive(s:S); // extern functions can only have primitives as parameters
extern fn with_non_primitive_return(): S; // extern functions can only have primitives as parameters
"#,
)
}
Expand Down

0 comments on commit e5e9f91

Please sign in to comment.