mirror of
https://github.com/vlang/v.git
synced 2025-08-03 09:47:15 -04:00
comptime: support type interpolation in the msg argument of $compile_warn(msg)
and $compile_error(msg)
(#24992)
This commit is contained in:
parent
56b51b69d8
commit
cd94cff219
@ -9,16 +9,17 @@ import v.token
|
||||
import v.util
|
||||
import v.pkgconfig
|
||||
import v.type_resolver
|
||||
import strings
|
||||
|
||||
fn (mut c Checker) comptime_call(mut node ast.ComptimeCall) ast.Type {
|
||||
if node.left !is ast.EmptyExpr {
|
||||
node.left_type = c.expr(mut node.left)
|
||||
}
|
||||
if node.method_name == 'compile_error' {
|
||||
c.error(node.args_var, node.pos)
|
||||
c.error(c.comptime_call_msg(node), node.pos)
|
||||
return ast.void_type
|
||||
} else if node.method_name == 'compile_warn' {
|
||||
c.warn(node.args_var, node.pos)
|
||||
c.warn(c.comptime_call_msg(node), node.pos)
|
||||
return ast.void_type
|
||||
}
|
||||
if node.is_env {
|
||||
@ -203,6 +204,16 @@ fn (mut c Checker) comptime_call(mut node ast.ComptimeCall) ast.Type {
|
||||
return f.return_type
|
||||
}
|
||||
|
||||
fn (mut c Checker) comptime_call_msg(node ast.ComptimeCall) string {
|
||||
return if node.args_var.len > 0 {
|
||||
node.args_var
|
||||
} else if value := c.eval_comptime_const_expr(node.args[0].expr, -1) {
|
||||
value.string() or { '' }
|
||||
} else {
|
||||
''
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut c Checker) comptime_selector(mut node ast.ComptimeSelector) ast.Type {
|
||||
node.left_type = c.expr(mut node.left)
|
||||
mut expr_type := c.unwrap_generic(c.expr(mut node.field_expr))
|
||||
@ -415,6 +426,22 @@ fn (mut c Checker) eval_comptime_const_expr(expr ast.Expr, nlevel int) ?ast.Comp
|
||||
ast.StringLiteral {
|
||||
return util.smart_quote(expr.val, expr.is_raw)
|
||||
}
|
||||
ast.StringInterLiteral {
|
||||
if nlevel < 0 {
|
||||
mut sb := strings.new_builder(20)
|
||||
for i, val in expr.vals {
|
||||
sb.write_string(val)
|
||||
if e := expr.exprs[i] {
|
||||
if value := c.eval_comptime_const_expr(e, nlevel + 1) {
|
||||
sb.write_string(value.string() or { '' })
|
||||
} else {
|
||||
c.error('unsupport expr `${e.str()}`', e.pos())
|
||||
}
|
||||
}
|
||||
}
|
||||
return sb.str()
|
||||
}
|
||||
}
|
||||
ast.CharLiteral {
|
||||
runes := expr.val.runes()
|
||||
if runes.len > 0 {
|
||||
@ -427,6 +454,28 @@ fn (mut c Checker) eval_comptime_const_expr(expr ast.Expr, nlevel int) ?ast.Comp
|
||||
// an existing constant?
|
||||
return c.eval_comptime_const_expr(expr.obj.expr, nlevel + 1)
|
||||
}
|
||||
idx := c.table.cur_fn.generic_names.index(expr.name)
|
||||
if typ := c.table.cur_concrete_types[idx] {
|
||||
sym := c.table.sym(typ)
|
||||
return sym.str()
|
||||
}
|
||||
}
|
||||
ast.SelectorExpr {
|
||||
if expr.expr is ast.Ident {
|
||||
idx := c.table.cur_fn.generic_names.index(expr.expr.name)
|
||||
if typ := c.table.cur_concrete_types[idx] {
|
||||
sym := c.table.sym(typ)
|
||||
match expr.field_name {
|
||||
'name' {
|
||||
return sym.name
|
||||
}
|
||||
'idx' {
|
||||
return i32(sym.idx)
|
||||
}
|
||||
else {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ast.CastExpr {
|
||||
cast_expr_value := c.eval_comptime_const_expr(expr.expr, nlevel + 1) or { return none }
|
||||
|
@ -2285,10 +2285,16 @@ pub fn (mut f Fmt) comptime_call(node ast.ComptimeCall) {
|
||||
f.write("\$pkgconfig('${node.args_var}')")
|
||||
}
|
||||
node.method_name in ['compile_error', 'compile_warn'] {
|
||||
if node.args_var.contains("'") {
|
||||
f.write('\$${node.method_name}("${node.args_var}")')
|
||||
if node.args.len == 0 {
|
||||
if node.args_var.contains("'") {
|
||||
f.write('\$${node.method_name}("${node.args_var}")')
|
||||
} else {
|
||||
f.write("\$${node.method_name}('${node.args_var}')")
|
||||
}
|
||||
} else {
|
||||
f.write("\$${node.method_name}('${node.args_var}')")
|
||||
f.write('\$${node.method_name}(')
|
||||
f.expr(node.args[0].expr)
|
||||
f.write(')')
|
||||
}
|
||||
}
|
||||
node.method_name == 'd' {
|
||||
|
@ -159,7 +159,7 @@ fn (mut p Parser) comptime_call() ast.ComptimeCall {
|
||||
is_html := method_name == 'html'
|
||||
p.check(.lpar)
|
||||
arg_pos := p.tok.pos()
|
||||
if method_name in ['env', 'pkgconfig', 'compile_error', 'compile_warn'] {
|
||||
if method_name in ['env', 'pkgconfig'] {
|
||||
s := p.tok.lit
|
||||
p.check(.string)
|
||||
p.check(.rpar)
|
||||
@ -172,6 +172,28 @@ fn (mut p Parser) comptime_call() ast.ComptimeCall {
|
||||
env_pos: start_pos
|
||||
pos: start_pos.extend(p.prev_tok.pos())
|
||||
}
|
||||
} else if method_name in ['compile_error', 'compile_warn'] {
|
||||
mut s := ''
|
||||
mut args := []ast.CallArg{}
|
||||
if p.tok.kind == .string && p.peek_tok.kind == .rpar {
|
||||
s = p.tok.lit
|
||||
p.check(.string)
|
||||
} else {
|
||||
args << ast.CallArg{
|
||||
expr: p.string_expr()
|
||||
typ: ast.string_type
|
||||
ct_expr: true
|
||||
}
|
||||
}
|
||||
p.check(.rpar)
|
||||
return ast.ComptimeCall{
|
||||
scope: unsafe { nil }
|
||||
method_name: method_name
|
||||
args_var: s
|
||||
env_pos: start_pos
|
||||
pos: start_pos.extend(p.prev_tok.pos())
|
||||
args: args
|
||||
}
|
||||
} else if method_name == 'res' {
|
||||
mut has_args := false
|
||||
mut type_index := ''
|
||||
|
@ -0,0 +1,40 @@
|
||||
const msg = 'invalid type'
|
||||
|
||||
fn t[T]() int {
|
||||
$if T is i8 {
|
||||
assert typeof[T]().name == typeof[i8]().name
|
||||
$compile_warn('invalid type ${T.name} ${T.idx}')
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
fn t2[T, R]() int {
|
||||
$if T is i8 && R is i16 {
|
||||
assert typeof[T]().name == typeof[i8]().name
|
||||
assert typeof[R]().name == typeof[i16]().name
|
||||
$compile_warn('invalid type ${T.name} ${T.idx}, ${R.name} ${R.idx}')
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
fn t3[T, R, E]() int {
|
||||
$if T is i8 && R is i16 && E is i32 {
|
||||
assert typeof[T]().name == typeof[i8]().name
|
||||
assert typeof[R]().name == typeof[i16]().name
|
||||
assert typeof[E]().name == typeof[i32]().name
|
||||
$compile_warn('invalid type ${T.name} ${T.idx}, ${R.name} ${R.idx}, ${E.name} ${E.idx}')
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
fn test_main() {
|
||||
assert t[i8]() == 1
|
||||
assert t2[i8, i16]() == 1
|
||||
assert t3[i8, i16, i32]() == 1
|
||||
assert t[i16]() == 0
|
||||
assert t2[i16, i16]() == 0
|
||||
assert t3[i16, i16, i16]() == 0
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user