Skip to content

Commit

Permalink
sema: fix type safety checking of variadic arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
mertcandav committed Jan 24, 2024
1 parent d888ee1 commit f84f5b2
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 52 deletions.
8 changes: 6 additions & 2 deletions std/jule/sema/builtin.jule
Original file line number Diff line number Diff line change
Expand Up @@ -497,8 +497,12 @@ fn builtin_caller_append(mut &e: &Eval, mut &fc: &FnCallExpr, mut &d: &Data): &D
result: t.kind,
caller: BUILTIN_CALLER_COMMON_PLAIN,
}
d.kind = &TypeKind{kind: f}
d.model = &CommonIdentExprModel{ident: "append"}
d.kind = &TypeKind{
kind: f,
}
d.model = &CommonIdentExprModel{
ident: "append",
}

d = builtin_caller_common_plain(e, fc, d)
if d != nil {
Expand Down
93 changes: 69 additions & 24 deletions std/jule/sema/eval.jule
Original file line number Diff line number Diff line change
Expand Up @@ -1083,8 +1083,10 @@ impl Eval {

ret &Data{
mutable: true,
kind: &TypeKind{kind: arr},
model: model,
kind: &TypeKind{
kind: arr,
},
model: model,
}
}

Expand Down Expand Up @@ -1113,8 +1115,10 @@ impl Eval {

ret &Data{
mutable: true,
kind: &TypeKind{kind: slc},
model: model,
kind: &TypeKind{
kind: slc,
},
model: model,
}
}

Expand Down Expand Up @@ -1421,7 +1425,11 @@ impl Eval {

fn slicing_arr(self, mut &d: &Data) {
let mut elem_type = d.kind.arr().elem
d.kind = &TypeKind{kind: &Slc{elem: elem_type}}
d.kind = &TypeKind{
kind: &Slc{
elem: elem_type,
},
}

d.lvalue = false

Expand Down Expand Up @@ -3228,25 +3236,62 @@ impl Eval {
let mut d: &Data = nil

match type kind {
| &LitExpr: d = self.eval_lit((&LitExpr)(kind))
| &IdentExpr: d = self.eval_ident((&IdentExpr)(kind))
| &UnaryExpr: d = self.eval_unary((&UnaryExpr)(kind))
| &VariadicExpr: d = self.eval_variadic((&VariadicExpr)(kind))
| &UnsafeExpr: d = self.eval_unsafe((&UnsafeExpr)(kind))
| &SliceExpr: d = self.eval_slice_expr((&SliceExpr)(kind))
| &IndexingExpr: d = self.eval_indexing((&IndexingExpr)(kind))
| &SlicingExpr: d = self.eval_slicing((&SlicingExpr)(kind))
| &CastExpr: d = self.eval_cast((&CastExpr)(kind))
| &NsSelectionExpr: d = self.eval_ns_selection((&NsSelectionExpr)(kind))
| &StructLit: d = self.eval_struct_lit((&StructLit)(kind))
| &TypeDecl: d = self.eval_type((&TypeDecl)(kind))
| &FnCallExpr: d = self.eval_fn_call((&FnCallExpr)(kind))
| &SubIdentExpr: d = self.eval_sub_ident((&SubIdentExpr)(kind))
| &TupleExpr: d = self.eval_tuple((&TupleExpr)(kind))
| &BraceLit: d = self.eval_brace_lit((&BraceLit)(kind))
| &FnDecl: d = self.eval_anon_fn((&FnDecl)(kind))
| &BinopExpr: d = self.eval_binop((&BinopExpr)(kind))
| &TernaryExpr: d = self.eval_ternary((&TernaryExpr)(kind))
| &LitExpr:
d = self.eval_lit((&LitExpr)(kind))

| &IdentExpr:
d = self.eval_ident((&IdentExpr)(kind))

| &UnaryExpr:
d = self.eval_unary((&UnaryExpr)(kind))

| &VariadicExpr:
d = self.eval_variadic((&VariadicExpr)(kind))

| &UnsafeExpr:
d = self.eval_unsafe((&UnsafeExpr)(kind))

| &SliceExpr:
d = self.eval_slice_expr((&SliceExpr)(kind))

| &IndexingExpr:
d = self.eval_indexing((&IndexingExpr)(kind))

| &SlicingExpr:
d = self.eval_slicing((&SlicingExpr)(kind))

| &CastExpr:
d = self.eval_cast((&CastExpr)(kind))

| &NsSelectionExpr:
d = self.eval_ns_selection((&NsSelectionExpr)(kind))

| &StructLit:
d = self.eval_struct_lit((&StructLit)(kind))

| &TypeDecl:
d = self.eval_type((&TypeDecl)(kind))

| &FnCallExpr:
d = self.eval_fn_call((&FnCallExpr)(kind))

| &SubIdentExpr:
d = self.eval_sub_ident((&SubIdentExpr)(kind))

| &TupleExpr:
d = self.eval_tuple((&TupleExpr)(kind))

| &BraceLit:
d = self.eval_brace_lit((&BraceLit)(kind))

| &FnDecl:
d = self.eval_anon_fn((&FnDecl)(kind))

| &BinopExpr:
d = self.eval_binop((&BinopExpr)(kind))

| &TernaryExpr:
d = self.eval_ternary((&TernaryExpr)(kind))
}

if d == nil {
Expand Down
13 changes: 8 additions & 5 deletions std/jule/sema/sema.jule
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,10 @@ fn build_param_vars(mut &f: &FnIns): []&Var {

match {
| p.decl.is_self():
v.kind.kind = &TypeKind{kind: f.owner}
v.kind.kind = &TypeKind{
variadic: false,
kind: f.owner,
}
v.reference = true

if p.decl.is_ref() {
Expand All @@ -138,6 +141,7 @@ fn build_param_vars(mut &f: &FnIns): []&Var {

| p.decl.variadic:
v.kind.kind = &TypeKind{
variadic: false,
kind: &Slc{
elem: &TypeKind{
cpp_ident: p.kind.cpp_ident,
Expand Down Expand Up @@ -861,10 +865,10 @@ impl Sema {
self.push_err(error_token, LogMsg.InvalidExpr)
ret
}
if d.kind.variadic {
/*if d.kind.variadic {
self.push_err(error_token, LogMsg.InvalidExpr)
ret
}
}*/
if dest_is_ref {
if !dest.equals(d.kind) {
self.push_err(error_token, LogMsg.IncompatibleTypes, dest.to_str(), d.kind.to_str())
Expand Down Expand Up @@ -2011,8 +2015,7 @@ impl Sema {
}

if v.is_type_inferred() {
// Build new TypeSymbol because
// auto-type symbols are nil.
// Build new TypeSymbol because auto-type symbols are nil.
v.kind = &TypeSymbol{kind: v.value.data.kind}

self.check_data_for_type_inference(v.value.data, v.value.expr.token)
Expand Down
4 changes: 3 additions & 1 deletion std/jule/sema/type.jule
Original file line number Diff line number Diff line change
Expand Up @@ -898,7 +898,9 @@ impl TypeChecker {
}

let mut old_sema_file = ins.decl.sema.file
defer { ins.decl.sema.set_current_file(old_sema_file) }
defer {
ins.decl.sema.set_current_file(old_sema_file)
}

let mut tc = TypeChecker{
s: ins.decl.sema,
Expand Down
52 changes: 32 additions & 20 deletions std/jule/sema/type2.jule
Original file line number Diff line number Diff line change
Expand Up @@ -188,9 +188,11 @@ impl TypeCompatibilityChecker {
}

fn check_prim(mut self): (ok: bool) {
let prim = self.dest.prim()
if prim != nil && prim.is_any() {
ret true
if !self.dest.variadic {
let prim = self.dest.prim()
if prim != nil && prim.is_any() {
ret true
}
}
ret self.dest.equals(self.src)
}
Expand Down Expand Up @@ -566,14 +568,17 @@ impl FnCallArgChecker {

fn check_arg(mut self, mut &p: &ParamIns, mut &arg: &Data, mut &error_token: Token): (ok: bool) {
if self.dynamic_annotation && parameter_uses_generics(p.decl, self.f.decl.generics) {
let mut dta = DynamicTypeAnnotation{
e: self.e,
f: self.f,
p: p,
a: arg,
error_token: error_token,
ok = !p.decl.variadic // Accept as fail if parameter is variadic.
if ok {
let mut dta = DynamicTypeAnnotation{
e: self.e,
f: self.f,
p: p,
a: arg,
error_token: error_token,
}
ok = unsafe { dta.annotate() }
}
ok = unsafe { dta.annotate() }
if !ok {
self.push_err_token(error_token, LogMsg.DynamicTypeAnnotationFailed)
ret false
Expand Down Expand Up @@ -618,12 +623,26 @@ impl FnCallArgChecker {
}

let mut old = self.e.prefix

// Save variadic status into separate variable.
// Because parameter might be variadic, but type might be not variadic.
// Some built-in functions passes non-variadic types.
let variadic = p.kind.variadic
p.kind.variadic = false
defer {
p.kind.variadic = variadic
}

for i < self.args.len; i++ {
let mut arg = self.args[i]

match type arg.kind {
| &VariadicExpr:
self.e.prefix = &TypeKind{kind: &Slc{elem: p.kind}}
self.e.prefix = &TypeKind{
kind: &Slc{
elem: p.kind,
}
}

|:
self.e.prefix = p.kind
Expand All @@ -642,15 +661,6 @@ impl FnCallArgChecker {
}
variadiced = true

let pold = p.kind.variadic
let dold = d.kind.variadic
p.kind.variadic = false
d.kind.variadic = false
defer {
p.kind.variadic = pold
d.kind.variadic = dold
}

match type d.model {
| &SliceExprModel:
model = (&SliceExprModel)(d.model)
Expand All @@ -661,7 +671,9 @@ impl FnCallArgChecker {
self.arg_models = append(self.arg_models, d)
}

p.kind.variadic = true
ok = ok && self.check_arg(p, d, arg.token)
p.kind.variadic = false
continue
}

Expand Down

0 comments on commit f84f5b2

Please sign in to comment.