checker: do not allow direct initialization of builtin types (s := string{})

pull/9293/head
Alexander Medvednikov 2021-03-13 18:20:46 +03:00
parent f648e3f10d
commit 2f1810634e
6 changed files with 35 additions and 23 deletions

View File

@ -24,7 +24,7 @@ pub fn decode(data string) []byte {
unsafe {
buffer := malloc(size)
n := decode_in_buffer(data, buffer)
return array{element_size: 1, data: buffer, len: n, cap: size}
return buffer.vbytes(n)
}
}
@ -70,7 +70,8 @@ fn alloc_and_encode(src byteptr, len int) string {
// the a base64 url encoded `string` passed in `data`.
pub fn url_decode(data string) []byte {
mut result := data.replace_each(['-', '+', '_', '/'])
match result.len % 4 { // Pad with trailing '='s
match result.len % 4 {
// Pad with trailing '='s
2 { result += '==' } // 2 pad chars
3 { result += '=' } // 1 pad char
else {} // no padding
@ -81,7 +82,8 @@ pub fn url_decode(data string) []byte {
// url_decode_str is the string variant of url_decode
pub fn url_decode_str(data string) string {
mut result := data.replace_each(['-', '+', '_', '/'])
match result.len % 4 { // Pad with trailing '='s
match result.len % 4 {
// Pad with trailing '='s
2 { result += '==' } // 2 pad chars
3 { result += '=' } // 1 pad char
else {} // no padding
@ -132,19 +134,19 @@ pub fn decode_in_buffer(data &string, buffer byteptr) int {
mut char_c := 0
mut char_d := 0
if i < input_length {
char_a = index[unsafe { d[i] }]
char_a = base64.index[unsafe { d[i] }]
i++
}
if i < input_length {
char_b = index[unsafe { d[i] }]
char_b = base64.index[unsafe { d[i] }]
i++
}
if i < input_length {
char_c = index[unsafe { d[i] }]
char_c = base64.index[unsafe { d[i] }]
i++
}
if i < input_length {
char_d = index[unsafe { d[i] }]
char_d = base64.index[unsafe { d[i] }]
i++
}
@ -180,7 +182,7 @@ fn encode_from_buffer(dest byteptr, src byteptr, src_len int) int {
mut d := src
mut b := dest
mut etable := byteptr(enc_table.str)
mut etable := byteptr(base64.enc_table.str)
for i < input_length {
mut octet_a := 0
mut octet_b := 0
@ -210,7 +212,7 @@ fn encode_from_buffer(dest byteptr, src byteptr, src_len int) int {
j += 4
}
padding_length := ending_table[input_length % 3]
padding_length := base64.ending_table[input_length % 3]
for i = 0; i < padding_length; i++ {
unsafe {
b[output_length - 1 - i] = `=`

View File

@ -483,7 +483,7 @@ pub fn read_file_array<T>(path string) []T {
a := T{}
tsize := int(sizeof(a))
// prepare for reading, get current file size
mut fp := vfopen(path, 'rb') or { return array{} }
mut fp := vfopen(path, 'rb') or { return []T{} }
C.fseek(fp, 0, C.SEEK_END)
fsize := C.ftell(fp)
C.rewind(fp)
@ -492,11 +492,13 @@ pub fn read_file_array<T>(path string) []T {
buf := unsafe { malloc(fsize) }
C.fread(buf, fsize, 1, fp)
C.fclose(fp)
return array{
element_size: tsize
data: buf
len: len
cap: len
return unsafe {
array{
element_size: tsize
data: buf
len: len
cap: len
}
}
}

View File

@ -1248,7 +1248,6 @@ pub fn (expr Expr) is_blank_ident() bool {
pub fn (expr Expr) position() token.Position {
// all uncommented have to be implemented
match expr {
// KEKW2
AnonFn {
return expr.decl.pos
}

View File

@ -463,6 +463,16 @@ pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) table.Type {
utyp := c.unwrap_generic(struct_init.typ)
c.ensure_type_exists(utyp, struct_init.pos) or {}
type_sym := c.table.get_type_symbol(utyp)
// Make sure the first letter is capital, do not allow e.g. `x := string{}`,
// but `x := T{}` is ok.
if !c.is_builtin_mod && !c.inside_unsafe && type_sym.language == .v
&& c.cur_generic_types.len == 0 {
pos := type_sym.name.last_index('.') or { -1 }
first_letter := type_sym.name[pos + 1]
if !first_letter.is_capital() {
c.error('cannot initialize builtin type `$type_sym.name`', struct_init.pos)
}
}
if type_sym.kind == .sum_type && struct_init.fields.len == 1 {
sexpr := struct_init.fields[0].expr.str()
c.error('cast to sum type using `${type_sym.name}($sexpr)` not `$type_sym.name{$sexpr}`',

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/check_generic_int_init.vv:2:9: error: type `int` is private
vlib/v/checker/tests/check_generic_int_init.vv:2:9: error: cannot initialize builtin type `int`
1 | fn test<T>() T {
2 | return T{}
| ~~~

View File

@ -31,7 +31,7 @@ fn test_ct_expressions() {
fn generic_t_is<O>() O {
$if O is string {
return 'It\'s a string!'
return "It's a string!"
} $else {
return O{}
}
@ -41,17 +41,17 @@ fn generic_t_is<O>() O {
struct GenericTIsTest {}
fn test_generic_t_is() {
assert generic_t_is<string>() == 'It\'s a string!'
assert generic_t_is<string>() == "It's a string!"
assert generic_t_is<GenericTIsTest>() == GenericTIsTest{}
}
fn generic_t_is2<T>() ?T {
$if T is string {
return 'It\'s a string!'
return "It's a string!"
} $else {
return T{}
}
}
}
fn test_generic_t_is2() {
res := generic_t_is2<string>() or {
@ -62,7 +62,7 @@ fn test_generic_t_is2() {
assert false
GenericTIsTest{}
}
assert res == 'It\'s a string!'
assert res == "It's a string!"
assert res2 == GenericTIsTest{}
}
@ -123,4 +123,3 @@ fn test_generic_t_is_with_else_if() {
x := generic_t_is_with_else_if<User>()
assert x == ['name', 'age']
}