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

View File

@ -483,7 +483,7 @@ pub fn read_file_array<T>(path string) []T {
a := T{} a := T{}
tsize := int(sizeof(a)) tsize := int(sizeof(a))
// prepare for reading, get current file size // 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) C.fseek(fp, 0, C.SEEK_END)
fsize := C.ftell(fp) fsize := C.ftell(fp)
C.rewind(fp) C.rewind(fp)
@ -492,13 +492,15 @@ pub fn read_file_array<T>(path string) []T {
buf := unsafe { malloc(fsize) } buf := unsafe { malloc(fsize) }
C.fread(buf, fsize, 1, fp) C.fread(buf, fsize, 1, fp)
C.fclose(fp) C.fclose(fp)
return array{ return unsafe {
array{
element_size: tsize element_size: tsize
data: buf data: buf
len: len len: len
cap: len cap: len
} }
} }
}
pub fn on_segfault(f voidptr) { pub fn on_segfault(f voidptr) {
$if windows { $if windows {

View File

@ -1248,7 +1248,6 @@ pub fn (expr Expr) is_blank_ident() bool {
pub fn (expr Expr) position() token.Position { pub fn (expr Expr) position() token.Position {
// all uncommented have to be implemented // all uncommented have to be implemented
match expr { match expr {
// KEKW2
AnonFn { AnonFn {
return expr.decl.pos 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) utyp := c.unwrap_generic(struct_init.typ)
c.ensure_type_exists(utyp, struct_init.pos) or {} c.ensure_type_exists(utyp, struct_init.pos) or {}
type_sym := c.table.get_type_symbol(utyp) 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 { if type_sym.kind == .sum_type && struct_init.fields.len == 1 {
sexpr := struct_init.fields[0].expr.str() sexpr := struct_init.fields[0].expr.str()
c.error('cast to sum type using `${type_sym.name}($sexpr)` not `$type_sym.name{$sexpr}`', 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 { 1 | fn test<T>() T {
2 | return T{} 2 | return T{}
| ~~~ | ~~~

View File

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