all: remove `it` smartcast and replace with original variable name (#5764)
parent
9511b7d0a1
commit
c5dc1a33b6
|
@ -98,9 +98,9 @@ fn (app App) gen_api_for_module_in_os(mod_name, os_name string) string {
|
||||||
for f in b.parsed_files {
|
for f in b.parsed_files {
|
||||||
for s in f.stmts {
|
for s in f.stmts {
|
||||||
if s is ast.FnDecl {
|
if s is ast.FnDecl {
|
||||||
if it.is_pub {
|
if s.is_pub {
|
||||||
fn_signature := it.stringify(b.table)
|
fn_signature := s.stringify(b.table)
|
||||||
fn_mod := it.modname()
|
fn_mod := s.modname()
|
||||||
if fn_mod == mod_name {
|
if fn_mod == mod_name {
|
||||||
fline := '${fn_mod}: $fn_signature'
|
fline := '${fn_mod}: $fn_signature'
|
||||||
res << fline
|
res << fline
|
||||||
|
|
26
doc/docs.md
26
doc/docs.md
|
@ -541,6 +541,32 @@ else {
|
||||||
println(s) // "odd"
|
println(s) // "odd"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Is check
|
||||||
|
You can check sum types using `if` like `match`ing them.
|
||||||
|
```v
|
||||||
|
struct Abc {
|
||||||
|
val string
|
||||||
|
}
|
||||||
|
struct Xyz {
|
||||||
|
foo string
|
||||||
|
}
|
||||||
|
type Alphabet = Abc | Xyz
|
||||||
|
|
||||||
|
x := Alphabet(Abc{'test'}) // sum type
|
||||||
|
if x is Abc {
|
||||||
|
// x is automatically castet to Abc and can be used here
|
||||||
|
println(x)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If you have a struct field which should be checked, there is also a way to name a alias.
|
||||||
|
```
|
||||||
|
if x.bar is MyStruct as bar {
|
||||||
|
// x.bar cannot be castet automatically, instead you say "as bar" which creates a variable with the MyStruct typing
|
||||||
|
println(bar)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### In operator
|
### In operator
|
||||||
|
|
||||||
`in` allows to check whether an array or a map contains an element.
|
`in` allows to check whether an array or a map contains an element.
|
||||||
|
|
|
@ -33,7 +33,7 @@ fn wait() {
|
||||||
|
|
||||||
fn (l Lander) land(w World) {
|
fn (l Lander) land(w World) {
|
||||||
if w is Mars {
|
if w is Mars {
|
||||||
for it.dust_storm() {
|
for w.dust_storm() {
|
||||||
wait()
|
wait()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -443,6 +443,7 @@ pub:
|
||||||
comments []Comment
|
comments []Comment
|
||||||
pub mut:
|
pub mut:
|
||||||
smartcast bool // should only be true if cond is `x is sumtype`, it will be set in checker - if_expr
|
smartcast bool // should only be true if cond is `x is sumtype`, it will be set in checker - if_expr
|
||||||
|
left_as_name string // only used in x is SumType check
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct LockExpr {
|
pub struct LockExpr {
|
||||||
|
|
|
@ -279,7 +279,7 @@ pub fn (node Stmt) str() string {
|
||||||
mut out := ''
|
mut out := ''
|
||||||
for i, left in it.left {
|
for i, left in it.left {
|
||||||
if left is Ident {
|
if left is Ident {
|
||||||
var_info := it.var_info()
|
var_info := left.var_info()
|
||||||
if var_info.is_mut {
|
if var_info.is_mut {
|
||||||
out += 'mut '
|
out += 'mut '
|
||||||
}
|
}
|
||||||
|
|
|
@ -288,8 +288,8 @@ fn (b &Builder) print_warnings_and_errors() {
|
||||||
for file in b.parsed_files {
|
for file in b.parsed_files {
|
||||||
for stmt in file.stmts {
|
for stmt in file.stmts {
|
||||||
if stmt is ast.FnDecl {
|
if stmt is ast.FnDecl {
|
||||||
if it.name == fn_name {
|
if stmt.name == fn_name {
|
||||||
fline := it.pos.line_nr
|
fline := stmt.pos.line_nr
|
||||||
println('$file.path:$fline:')
|
println('$file.path:$fline:')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -207,17 +207,17 @@ fn (mut c Checker) check_file_in_main(file ast.File) bool {
|
||||||
}
|
}
|
||||||
ast.TypeDecl {
|
ast.TypeDecl {
|
||||||
if stmt is ast.AliasTypeDecl {
|
if stmt is ast.AliasTypeDecl {
|
||||||
if it.is_pub {
|
if stmt.is_pub {
|
||||||
c.warn('type alias `$it.name` $no_pub_in_main_warning',
|
c.warn('type alias `$stmt.name` $no_pub_in_main_warning',
|
||||||
it.pos)
|
stmt.pos)
|
||||||
}
|
}
|
||||||
} else if stmt is ast.SumTypeDecl {
|
} else if stmt is ast.SumTypeDecl {
|
||||||
if it.is_pub {
|
if stmt.is_pub {
|
||||||
c.warn('sum type `$it.name` $no_pub_in_main_warning', it.pos)
|
c.warn('sum type `$stmt.name` $no_pub_in_main_warning', stmt.pos)
|
||||||
}
|
}
|
||||||
} else if stmt is ast.FnTypeDecl {
|
} else if stmt is ast.FnTypeDecl {
|
||||||
if it.is_pub {
|
if stmt.is_pub {
|
||||||
c.warn('type alias `$it.name` $no_pub_in_main_warning', it.pos)
|
c.warn('type alias `$stmt.name` $no_pub_in_main_warning', stmt.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1266,25 +1266,25 @@ fn (mut c Checker) type_implements(typ, inter_typ table.Type, pos token.Position
|
||||||
// return the actual type of the expression, once the optional is handled
|
// return the actual type of the expression, once the optional is handled
|
||||||
pub fn (mut c Checker) check_expr_opt_call(expr ast.Expr, ret_type table.Type) table.Type {
|
pub fn (mut c Checker) check_expr_opt_call(expr ast.Expr, ret_type table.Type) table.Type {
|
||||||
if expr is ast.CallExpr {
|
if expr is ast.CallExpr {
|
||||||
if it.return_type.has_flag(.optional) {
|
if expr.return_type.has_flag(.optional) {
|
||||||
if it.or_block.kind == .absent {
|
if expr.or_block.kind == .absent {
|
||||||
if ret_type != table.void_type {
|
if ret_type != table.void_type {
|
||||||
c.error('${it.name}() returns an option, but you missed to add an `or {}` block to it',
|
c.error('${expr.name}() returns an option, but you missed to add an `or {}` block to it',
|
||||||
it.pos)
|
expr.pos)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
c.check_or_expr(it.or_block, ret_type)
|
c.check_or_expr(expr.or_block, ret_type)
|
||||||
}
|
}
|
||||||
// remove optional flag
|
// remove optional flag
|
||||||
// return ret_type.clear_flag(.optional)
|
// return ret_type.clear_flag(.optional)
|
||||||
// TODO: currently unwrapped in assign, would need to refactor assign to unwrap here
|
// TODO: currently unwrapped in assign, would need to refactor assign to unwrap here
|
||||||
return ret_type
|
return ret_type
|
||||||
} else if it.or_block.kind == .block {
|
} else if expr.or_block.kind == .block {
|
||||||
c.error('unexpected `or` block, the function `$it.name` does not return an optional',
|
c.error('unexpected `or` block, the function `$expr.name` does not return an optional',
|
||||||
it.pos)
|
expr.pos)
|
||||||
} else if it.or_block.kind == .propagate {
|
} else if expr.or_block.kind == .propagate {
|
||||||
c.error('unexpected `?`, the function `$it.name`, does not return an optional',
|
c.error('unexpected `?`, the function `$expr.name`, does not return an optional',
|
||||||
it.pos)
|
expr.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret_type
|
return ret_type
|
||||||
|
@ -1522,7 +1522,7 @@ pub fn (mut c Checker) assign_stmt(mut assign_stmt ast.AssignStmt) {
|
||||||
}
|
}
|
||||||
if assign_stmt.left.len != right_len {
|
if assign_stmt.left.len != right_len {
|
||||||
if right_first is ast.CallExpr {
|
if right_first is ast.CallExpr {
|
||||||
c.error('assignment mismatch: $assign_stmt.left.len variable(s) but `${it.name}()` returns $right_len value(s)',
|
c.error('assignment mismatch: $assign_stmt.left.len variable(s) but `${right_first.name}()` returns $right_len value(s)',
|
||||||
assign_stmt.pos)
|
assign_stmt.pos)
|
||||||
} else {
|
} else {
|
||||||
c.error('assignment mismatch: $assign_stmt.left.len variable(s) $right_len value(s)',
|
c.error('assignment mismatch: $assign_stmt.left.len variable(s) $right_len value(s)',
|
||||||
|
@ -2620,27 +2620,30 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type {
|
||||||
// smartcast sumtypes when using `is`
|
// smartcast sumtypes when using `is`
|
||||||
if branch.cond is ast.InfixExpr {
|
if branch.cond is ast.InfixExpr {
|
||||||
infix := branch.cond as ast.InfixExpr
|
infix := branch.cond as ast.InfixExpr
|
||||||
if infix.op == .key_is && infix.left is ast.Ident && infix.right is ast.Type {
|
if infix.op == .key_is && (infix.left is ast.Ident || infix.left is ast.SelectorExpr) && infix.right is ast.Type {
|
||||||
left_expr := infix.left as ast.Ident
|
|
||||||
right_expr := infix.right as ast.Type
|
right_expr := infix.right as ast.Type
|
||||||
if left_expr.kind == .variable {
|
is_variable := if infix.left is ast.Ident {
|
||||||
|
(infix.left as ast.Ident).kind == .variable
|
||||||
|
} else { true }
|
||||||
// Register shadow variable or `as` variable with actual type
|
// Register shadow variable or `as` variable with actual type
|
||||||
|
if is_variable {
|
||||||
left_sym := c.table.get_type_symbol(infix.left_type)
|
left_sym := c.table.get_type_symbol(infix.left_type)
|
||||||
if left_sym.kind == .sum_type {
|
if left_sym.kind == .sum_type && branch.left_as_name.len > 0 {
|
||||||
|
mut is_mut := false
|
||||||
|
if infix.left is ast.Ident {
|
||||||
|
is_mut = (infix.left as ast.Ident).is_mut
|
||||||
|
} else if infix.left is ast.SelectorExpr {
|
||||||
|
selector := infix.left as ast.SelectorExpr
|
||||||
|
field := c.table.struct_find_field(left_sym, selector.field_name) or { table.Field{} }
|
||||||
|
is_mut = field.is_mut
|
||||||
|
}
|
||||||
mut scope := c.file.scope.innermost(branch.body_pos.pos)
|
mut scope := c.file.scope.innermost(branch.body_pos.pos)
|
||||||
scope.register('it', ast.Var{
|
scope.register(branch.left_as_name, ast.Var{
|
||||||
name: 'it'
|
name: branch.left_as_name
|
||||||
typ: right_expr.typ.to_ptr()
|
typ: right_expr.typ.to_ptr()
|
||||||
pos: left_expr.pos
|
pos: infix.left.position()
|
||||||
is_used: true
|
is_used: true
|
||||||
is_mut: left_expr.is_mut
|
is_mut: is_mut
|
||||||
})
|
|
||||||
scope.register(left_expr.name, ast.Var{
|
|
||||||
name: left_expr.name
|
|
||||||
typ: right_expr.typ.to_ptr()
|
|
||||||
pos: left_expr.pos
|
|
||||||
is_used: true
|
|
||||||
is_mut: left_expr.is_mut
|
|
||||||
})
|
})
|
||||||
node.branches[i].smartcast = true
|
node.branches[i].smartcast = true
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
fn foo() string {
|
||||||
|
if true {
|
||||||
|
return ''
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -45,7 +45,7 @@ pub fn merge_comments(stmts []ast.Stmt) string {
|
||||||
mut res := []string{}
|
mut res := []string{}
|
||||||
for s in stmts {
|
for s in stmts {
|
||||||
if s is ast.Comment {
|
if s is ast.Comment {
|
||||||
res << it.text.trim_left('|')
|
res << s.text.trim_left('|')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res.join('\n')
|
return res.join('\n')
|
||||||
|
@ -374,11 +374,11 @@ fn (mut d Doc) generate() ?Doc {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if stmt is ast.FnDecl {
|
if stmt is ast.FnDecl {
|
||||||
if it.is_deprecated {
|
if stmt.is_deprecated {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if it.receiver.typ != 0 {
|
if stmt.receiver.typ != 0 {
|
||||||
node.attrs['parent'] = d.fmt.type_to_str(it.receiver.typ).trim_left('&')
|
node.attrs['parent'] = d.fmt.type_to_str(stmt.receiver.typ).trim_left('&')
|
||||||
p_idx := d.contents.index_by_name(node.attrs['parent'])
|
p_idx := d.contents.index_by_name(node.attrs['parent'])
|
||||||
if p_idx == -1 && node.attrs['parent'] != 'void' {
|
if p_idx == -1 && node.attrs['parent'] != 'void' {
|
||||||
d.contents << DocNode{
|
d.contents << DocNode{
|
||||||
|
|
|
@ -246,7 +246,7 @@ pub fn (mut f Fmt) stmt(node ast.Stmt) {
|
||||||
ast.AssignStmt {
|
ast.AssignStmt {
|
||||||
for i, left in node.left {
|
for i, left in node.left {
|
||||||
if left is ast.Ident {
|
if left is ast.Ident {
|
||||||
var_info := it.var_info()
|
var_info := left.var_info()
|
||||||
if var_info.is_mut {
|
if var_info.is_mut {
|
||||||
f.write('mut ')
|
f.write('mut ')
|
||||||
}
|
}
|
||||||
|
@ -660,8 +660,8 @@ pub fn (mut f Fmt) prefix_expr_cast_expr(fexpr ast.Expr) {
|
||||||
mut is_pe_amp_ce := false
|
mut is_pe_amp_ce := false
|
||||||
mut ce := ast.CastExpr{}
|
mut ce := ast.CastExpr{}
|
||||||
if fexpr is ast.PrefixExpr {
|
if fexpr is ast.PrefixExpr {
|
||||||
if it.right is ast.CastExpr && it.op == .amp {
|
if fexpr.right is ast.CastExpr && fexpr.op == .amp {
|
||||||
ce = it.right as ast.CastExpr
|
ce = fexpr.right as ast.CastExpr
|
||||||
ce.typname = f.table.get_type_symbol(ce.typ).name
|
ce.typname = f.table.get_type_symbol(ce.typ).name
|
||||||
is_pe_amp_ce = true
|
is_pe_amp_ce = true
|
||||||
f.expr(ce)
|
f.expr(ce)
|
||||||
|
@ -1248,16 +1248,16 @@ pub fn (mut f Fmt) call_expr(node ast.CallExpr) {
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
if node.left is ast.Ident {
|
if node.left is ast.Ident {
|
||||||
it := node.left as ast.Ident
|
left := node.left as ast.Ident
|
||||||
// `time.now()` without `time imported` is processed as a method call with `time` being
|
// `time.now()` without `time imported` is processed as a method call with `time` being
|
||||||
// a `node.left` expression. Import `time` automatically.
|
// a `node.left` expression. Import `time` automatically.
|
||||||
// TODO fetch all available modules
|
// TODO fetch all available modules
|
||||||
if it.name in ['time', 'os', 'strings', 'math', 'json', 'base64'] {
|
if left.name in ['time', 'os', 'strings', 'math', 'json', 'base64'] {
|
||||||
if it.name !in f.auto_imports {
|
if left.name !in f.auto_imports {
|
||||||
f.auto_imports << it.name
|
f.auto_imports << left.name
|
||||||
f.file.imports << ast.Import{
|
f.file.imports << ast.Import{
|
||||||
mod: it.name
|
mod: left.name
|
||||||
alias: it.name
|
alias: left.name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// for imp in f.file.imports {
|
// for imp in f.file.imports {
|
||||||
|
@ -1321,7 +1321,7 @@ pub fn (mut f Fmt) match_expr(it ast.MatchExpr) {
|
||||||
stmt := branch.stmts[0]
|
stmt := branch.stmts[0]
|
||||||
if stmt is ast.ExprStmt {
|
if stmt is ast.ExprStmt {
|
||||||
// If expressions inside match branches can't be one a single line
|
// If expressions inside match branches can't be one a single line
|
||||||
if !expr_is_single_line(it.expr) {
|
if !expr_is_single_line(stmt.expr) {
|
||||||
single_line = false
|
single_line = false
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
|
@ -1213,12 +1213,12 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
||||||
mut blank_assign := false
|
mut blank_assign := false
|
||||||
mut ident := ast.Ident{}
|
mut ident := ast.Ident{}
|
||||||
if left is ast.Ident {
|
if left is ast.Ident {
|
||||||
ident = it
|
ident = *left
|
||||||
// id_info := ident.var_info()
|
// id_info := ident.var_info()
|
||||||
// var_type = id_info.typ
|
// var_type = id_info.typ
|
||||||
blank_assign = ident.kind == .blank_ident
|
blank_assign = left.kind == .blank_ident
|
||||||
if ident.info is ast.IdentVar {
|
if left.info is ast.IdentVar {
|
||||||
share := (ident.info as ast.IdentVar).share
|
share := (left.info as ast.IdentVar).share
|
||||||
if share == .shared_t {
|
if share == .shared_t {
|
||||||
var_type = var_type.set_flag(.shared_f)
|
var_type = var_type.set_flag(.shared_f)
|
||||||
}
|
}
|
||||||
|
@ -1390,9 +1390,9 @@ fn (mut g Gen) gen_cross_tmp_variable(left []ast.Expr, val ast.Expr) {
|
||||||
mut has_var := false
|
mut has_var := false
|
||||||
for lx in left {
|
for lx in left {
|
||||||
if lx is ast.Ident {
|
if lx is ast.Ident {
|
||||||
if val.name == it.name {
|
if val.name == lx.name {
|
||||||
g.write('_var_')
|
g.write('_var_')
|
||||||
g.write(it.pos.pos.str())
|
g.write(lx.pos.pos.str())
|
||||||
has_var = true
|
has_var = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -2322,9 +2322,8 @@ fn (mut g Gen) if_expr(node ast.IfExpr) {
|
||||||
infix := branch.cond as ast.InfixExpr
|
infix := branch.cond as ast.InfixExpr
|
||||||
right_type := infix.right as ast.Type
|
right_type := infix.right as ast.Type
|
||||||
left_type := infix.left_type
|
left_type := infix.left_type
|
||||||
left_expr := infix.left as ast.Ident
|
|
||||||
it_type := g.typ(right_type.typ)
|
it_type := g.typ(right_type.typ)
|
||||||
g.write('\t$it_type* it = ($it_type*)')
|
g.write('\t$it_type* _sc_tmp_$branch.pos.pos = ($it_type*)')
|
||||||
g.expr(infix.left)
|
g.expr(infix.left)
|
||||||
if left_type.is_ptr() {
|
if left_type.is_ptr() {
|
||||||
g.write('->')
|
g.write('->')
|
||||||
|
@ -2332,7 +2331,7 @@ fn (mut g Gen) if_expr(node ast.IfExpr) {
|
||||||
g.write('.')
|
g.write('.')
|
||||||
}
|
}
|
||||||
g.writeln('obj;')
|
g.writeln('obj;')
|
||||||
g.writeln('\t$it_type* $left_expr.name = it;')
|
g.writeln('\t$it_type* $branch.left_as_name = _sc_tmp_$branch.pos.pos;')
|
||||||
}
|
}
|
||||||
g.stmts(branch.stmts)
|
g.stmts(branch.stmts)
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,9 +12,9 @@ fn (g &Gen) comptime_call(node ast.ComptimeCall) {
|
||||||
for stmt in node.vweb_tmpl.stmts {
|
for stmt in node.vweb_tmpl.stmts {
|
||||||
if stmt is ast.FnDecl {
|
if stmt is ast.FnDecl {
|
||||||
// insert stmts from vweb_tmpl fn
|
// insert stmts from vweb_tmpl fn
|
||||||
if it.name.starts_with('main.vweb_tmpl') {
|
if stmt.name.starts_with('main.vweb_tmpl') {
|
||||||
g.inside_vweb_tmpl = true
|
g.inside_vweb_tmpl = true
|
||||||
g.stmts(it.stmts)
|
g.stmts(stmt.stmts)
|
||||||
g.inside_vweb_tmpl = false
|
g.inside_vweb_tmpl = false
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
|
@ -686,8 +686,8 @@ fn (mut g JsGen) gen_assign_stmt(stmt ast.AssignStmt) {
|
||||||
val := stmt.right[i]
|
val := stmt.right[i]
|
||||||
mut is_mut := false
|
mut is_mut := false
|
||||||
if left is ast.Ident {
|
if left is ast.Ident {
|
||||||
is_mut = it.is_mut
|
is_mut = left.is_mut
|
||||||
if it.kind == .blank_ident || it.name in ['', '_'] {
|
if left.kind == .blank_ident || left.name in ['', '_'] {
|
||||||
tmp_var := g.new_tmp_var()
|
tmp_var := g.new_tmp_var()
|
||||||
// TODO: Can the tmp_var declaration be omitted?
|
// TODO: Can the tmp_var declaration be omitted?
|
||||||
g.write('const $tmp_var = ')
|
g.write('const $tmp_var = ')
|
||||||
|
|
|
@ -15,7 +15,7 @@ fn (mut p Parser) check_undefined_variables(exprs []ast.Expr, val ast.Expr) {
|
||||||
ast.Ident {
|
ast.Ident {
|
||||||
for expr in exprs {
|
for expr in exprs {
|
||||||
if expr is ast.Ident {
|
if expr is ast.Ident {
|
||||||
if it.name == val.name {
|
if expr.name == val.name {
|
||||||
p.error_with_pos('undefined variable: `$val.name`', val.pos)
|
p.error_with_pos('undefined variable: `$val.name`', val.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,7 @@ fn (mut p Parser) check_cross_variables(exprs []ast.Expr, val ast.Expr) bool {
|
||||||
ast.Ident {
|
ast.Ident {
|
||||||
for expr in exprs {
|
for expr in exprs {
|
||||||
if expr is ast.Ident {
|
if expr is ast.Ident {
|
||||||
if it.name == val_.name {
|
if expr.name == val_.name {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -129,13 +129,12 @@ fn (mut p Parser) vweb() ast.ComptimeCall {
|
||||||
// copy vars from current fn scope into vweb_tmpl scope
|
// copy vars from current fn scope into vweb_tmpl scope
|
||||||
for stmt in file.stmts {
|
for stmt in file.stmts {
|
||||||
if stmt is ast.FnDecl {
|
if stmt is ast.FnDecl {
|
||||||
if it.name == 'main.vweb_tmpl_$p.cur_fn_name' {
|
if stmt.name == 'main.vweb_tmpl_$p.cur_fn_name' {
|
||||||
fn_decl := it
|
tmpl_scope := file.scope.innermost(stmt.body_pos.pos)
|
||||||
tmpl_scope := file.scope.innermost(it.body_pos.pos)
|
|
||||||
for _, obj in p.scope.objects {
|
for _, obj in p.scope.objects {
|
||||||
if obj is ast.Var {
|
if obj is ast.Var {
|
||||||
mut v := it
|
mut v := obj
|
||||||
v.pos = fn_decl.body_pos
|
v.pos = stmt.body_pos
|
||||||
tmpl_scope.register(v.name, *v)
|
tmpl_scope.register(v.name, *v)
|
||||||
// set the controller action var to used
|
// set the controller action var to used
|
||||||
// if its unused in the template it will warn
|
// if its unused in the template it will warn
|
||||||
|
|
|
@ -555,7 +555,7 @@ fn (mut p Parser) fn_redefinition_error(name string) {
|
||||||
fn have_fn_main(stmts []ast.Stmt) bool {
|
fn have_fn_main(stmts []ast.Stmt) bool {
|
||||||
for stmt in stmts {
|
for stmt in stmts {
|
||||||
if stmt is ast.FnDecl {
|
if stmt is ast.FnDecl {
|
||||||
if it.name == 'main.main' && it.mod == 'main' {
|
if stmt.name == 'main.main' && stmt.mod == 'main' {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,6 +64,22 @@ fn (mut p Parser) if_expr() ast.IfExpr {
|
||||||
} else {
|
} else {
|
||||||
cond = p.expr(0)
|
cond = p.expr(0)
|
||||||
}
|
}
|
||||||
|
mut left_as_name := ''
|
||||||
|
is_infix := cond is ast.InfixExpr
|
||||||
|
if is_infix {
|
||||||
|
infix := cond as ast.InfixExpr
|
||||||
|
is_is_cast := infix.op == .key_is
|
||||||
|
is_ident := infix.left is ast.Ident
|
||||||
|
left_as_name = if is_is_cast && p.tok.kind == .key_as {
|
||||||
|
p.next()
|
||||||
|
p.check_name()
|
||||||
|
} else if is_ident {
|
||||||
|
ident := infix.left as ast.Ident
|
||||||
|
ident.name
|
||||||
|
} else {
|
||||||
|
''
|
||||||
|
}
|
||||||
|
}
|
||||||
end_pos := p.prev_tok.position()
|
end_pos := p.prev_tok.position()
|
||||||
body_pos := p.tok.position()
|
body_pos := p.tok.position()
|
||||||
p.inside_if = false
|
p.inside_if = false
|
||||||
|
@ -77,6 +93,7 @@ fn (mut p Parser) if_expr() ast.IfExpr {
|
||||||
pos: start_pos.extend(end_pos)
|
pos: start_pos.extend(end_pos)
|
||||||
body_pos: body_pos.extend(p.tok.position())
|
body_pos: body_pos.extend(p.tok.position())
|
||||||
comments: comments
|
comments: comments
|
||||||
|
left_as_name: left_as_name
|
||||||
}
|
}
|
||||||
comments = []
|
comments = []
|
||||||
if p.tok.kind != .key_else {
|
if p.tok.kind != .key_else {
|
||||||
|
|
|
@ -230,6 +230,10 @@ pub fn (mut p Parser) expr(precedence int) ast.Expr {
|
||||||
}
|
}
|
||||||
// continue on infix expr
|
// continue on infix expr
|
||||||
node = p.infix_expr(node)
|
node = p.infix_expr(node)
|
||||||
|
// return early `if bar is SumType as b {`
|
||||||
|
if p.tok.kind == .key_as && p.inside_if {
|
||||||
|
return node
|
||||||
|
}
|
||||||
} else if p.tok.kind in [.inc, .dec] {
|
} else if p.tok.kind in [.inc, .dec] {
|
||||||
// Postfix
|
// Postfix
|
||||||
node = ast.PostfixExpr{
|
node = ast.PostfixExpr{
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
struct Abc {
|
||||||
|
mut:
|
||||||
|
val string
|
||||||
|
}
|
||||||
|
struct Xyz {
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
type Alphabet = Abc | Xyz
|
||||||
|
|
||||||
|
fn test_if_smartcast() {
|
||||||
|
x := Alphabet(Abc{'test'})
|
||||||
|
if x is Abc {
|
||||||
|
assert x.val == 'test'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_mutable() {
|
||||||
|
mut x := Alphabet(Abc{'test'})
|
||||||
|
if x is Abc {
|
||||||
|
y := Abc{}
|
||||||
|
x = &y
|
||||||
|
assert x == &y
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_nested_if_smartcast() {
|
||||||
|
x := Alphabet(Abc{'test'})
|
||||||
|
y := Alphabet(Xyz{'foo'})
|
||||||
|
if x is Abc {
|
||||||
|
if y is Xyz {
|
||||||
|
assert y.name == 'foo'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_as_cast() {
|
||||||
|
x := Alphabet(Abc{'test'})
|
||||||
|
if x is Abc as test {
|
||||||
|
assert test.val == 'test'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Test {
|
||||||
|
abc Alphabet
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_mutable_with_struct() {
|
||||||
|
mut x := Test{Abc{'test'}}
|
||||||
|
if x.abc is Abc as test {
|
||||||
|
test.val = 'test'
|
||||||
|
assert test.val == 'test'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_as_cast_with_struct() {
|
||||||
|
x := Test{Abc{'test'}}
|
||||||
|
if x.abc is Abc as test {
|
||||||
|
assert test.val == 'test'
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue