mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
v.gen.c: support T.typ
- an int for the type index of the generic type T
(#11175)
This commit is contained in:
parent
fb3671107e
commit
900c37aa65
@ -1325,6 +1325,7 @@ fn (t Tree) selector_expr(node ast.SelectorExpr) &Node {
|
||||
obj.add('field_name', t.string_node(node.field_name))
|
||||
obj.add('typ', t.type_node(node.typ))
|
||||
obj.add('name_type', t.type_node(node.name_type))
|
||||
obj.add('gkind_field', t.enum_node(node.gkind_field))
|
||||
obj.add('from_embed_type', t.type_node(node.from_embed_type))
|
||||
obj.add('next_token', t.token_node(node.next_token))
|
||||
obj.add('pos', t.position(node.pos))
|
||||
|
@ -146,3 +146,43 @@ pub fn radians(degrees f64) f64 {
|
||||
pub fn signbit(x f64) bool {
|
||||
return f64_bits(x) & sign_mask != 0
|
||||
}
|
||||
|
||||
pub fn tolerance(a f64, b f64, tol f64) bool {
|
||||
mut ee := tol
|
||||
// Multiplying by ee here can underflow denormal values to zero.
|
||||
// Check a==b so that at least if a and b are small and identical
|
||||
// we say they match.
|
||||
if a == b {
|
||||
return true
|
||||
}
|
||||
mut d := a - b
|
||||
if d < 0 {
|
||||
d = -d
|
||||
}
|
||||
// note: b is correct (expected) value, a is actual value.
|
||||
// make error tolerance a fraction of b, not a.
|
||||
if b != 0 {
|
||||
ee = ee * b
|
||||
if ee < 0 {
|
||||
ee = -ee
|
||||
}
|
||||
}
|
||||
return d < ee
|
||||
}
|
||||
|
||||
pub fn close(a f64, b f64) bool {
|
||||
return tolerance(a, b, 1e-14)
|
||||
}
|
||||
|
||||
pub fn veryclose(a f64, b f64) bool {
|
||||
return tolerance(a, b, 4e-16)
|
||||
}
|
||||
|
||||
pub fn alike(a f64, b f64) bool {
|
||||
if is_nan(a) && is_nan(b) {
|
||||
return true
|
||||
} else if a == b {
|
||||
return signbit(a) == signbit(b)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@ -186,50 +186,10 @@ const (
|
||||
]
|
||||
)
|
||||
|
||||
fn tolerance(a f64, b f64, tol f64) bool {
|
||||
mut ee := tol
|
||||
// Multiplying by ee here can underflow denormal values to zero.
|
||||
// Check a==b so that at least if a and b are small and identical
|
||||
// we say they match.
|
||||
if a == b {
|
||||
return true
|
||||
}
|
||||
mut d := a - b
|
||||
if d < 0 {
|
||||
d = -d
|
||||
}
|
||||
// note: b is correct (expected) value, a is actual value.
|
||||
// make error tolerance a fraction of b, not a.
|
||||
if b != 0 {
|
||||
ee = ee * b
|
||||
if ee < 0 {
|
||||
ee = -ee
|
||||
}
|
||||
}
|
||||
return d < ee
|
||||
}
|
||||
|
||||
fn close(a f64, b f64) bool {
|
||||
return tolerance(a, b, 1e-14)
|
||||
}
|
||||
|
||||
fn veryclose(a f64, b f64) bool {
|
||||
return tolerance(a, b, 4e-16)
|
||||
}
|
||||
|
||||
fn soclose(a f64, b f64, e f64) bool {
|
||||
return tolerance(a, b, e)
|
||||
}
|
||||
|
||||
fn alike(a f64, b f64) bool {
|
||||
if is_nan(a) && is_nan(b) {
|
||||
return true
|
||||
} else if a == b {
|
||||
return signbit(a) == signbit(b)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fn test_nan() {
|
||||
nan_f64 := nan()
|
||||
assert nan_f64 != nan_f64
|
||||
|
@ -129,6 +129,12 @@ pub:
|
||||
pos token.Position
|
||||
}
|
||||
|
||||
pub enum GenericKindField {
|
||||
unknown
|
||||
name
|
||||
typ
|
||||
}
|
||||
|
||||
// `foo.bar`
|
||||
pub struct SelectorExpr {
|
||||
pub:
|
||||
@ -142,6 +148,7 @@ pub mut:
|
||||
expr_type Type // type of `Foo` in `Foo.bar`
|
||||
typ Type // type of the entire thing (`Foo.bar`)
|
||||
name_type Type // T in `T.name` or typeof in `typeof(expr).name`
|
||||
gkind_field GenericKindField // `T.name` => ast.GenericKindField.name, `T.typ` => ast.GenericKindField.typ, or .unknown
|
||||
scope &Scope
|
||||
from_embed_type Type // holds the type of the embed that the method is called from
|
||||
}
|
||||
|
@ -3365,11 +3365,22 @@ pub fn (mut c Checker) selector_expr(mut node ast.SelectorExpr) ast.Type {
|
||||
else {}
|
||||
}
|
||||
if name_type > 0 {
|
||||
if node.field_name != 'name' {
|
||||
c.error('invalid field `.$node.field_name` for type `$node.expr`', node.pos)
|
||||
}
|
||||
node.name_type = name_type
|
||||
return ast.string_type
|
||||
match node.gkind_field {
|
||||
.name {
|
||||
return ast.string_type
|
||||
}
|
||||
.typ {
|
||||
return ast.int_type
|
||||
}
|
||||
else {
|
||||
if node.field_name != 'name' {
|
||||
c.error('invalid field `.$node.field_name` for type `$node.expr`',
|
||||
node.pos)
|
||||
}
|
||||
return ast.string_type
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
old_selector_expr := c.inside_selector_expr
|
||||
|
@ -3649,8 +3649,24 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) {
|
||||
prevent_sum_type_unwrapping_once := g.prevent_sum_type_unwrapping_once
|
||||
g.prevent_sum_type_unwrapping_once = false
|
||||
if node.name_type > 0 {
|
||||
g.type_name(node.name_type)
|
||||
return
|
||||
match node.gkind_field {
|
||||
.name {
|
||||
g.type_name(node.name_type)
|
||||
return
|
||||
}
|
||||
.typ {
|
||||
g.write(int(g.unwrap_generic(node.name_type)).str())
|
||||
return
|
||||
}
|
||||
.unknown {
|
||||
if node.field_name == 'name' {
|
||||
// typeof(expr).name
|
||||
g.type_name(node.name_type)
|
||||
return
|
||||
}
|
||||
g.error('unknown generic field', node.pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
if node.expr_type == 0 {
|
||||
g.checker_bug('unexpected SelectorExpr.expr_type = 0', node.pos)
|
||||
|
@ -2158,6 +2158,11 @@ pub fn (mut p Parser) name_expr() ast.Expr {
|
||||
name := p.check_name()
|
||||
p.check(.dot)
|
||||
field := p.check_name()
|
||||
fkind := match field {
|
||||
'name' { ast.GenericKindField.name }
|
||||
'typ' { ast.GenericKindField.typ }
|
||||
else { ast.GenericKindField.unknown }
|
||||
}
|
||||
pos.extend(p.tok.position())
|
||||
return ast.SelectorExpr{
|
||||
expr: ast.Ident{
|
||||
@ -2165,6 +2170,7 @@ pub fn (mut p Parser) name_expr() ast.Expr {
|
||||
scope: p.scope
|
||||
}
|
||||
field_name: field
|
||||
gkind_field: fkind
|
||||
pos: pos
|
||||
scope: p.scope
|
||||
}
|
||||
|
55
vlib/v/tests/generics_T_typ_test.v
Normal file
55
vlib/v/tests/generics_T_typ_test.v
Normal file
@ -0,0 +1,55 @@
|
||||
import math
|
||||
|
||||
struct Any {
|
||||
mut:
|
||||
data voidptr
|
||||
typ int
|
||||
}
|
||||
|
||||
fn make_any<T>(obj T) Any {
|
||||
tsize := int(sizeof(T))
|
||||
mut a := Any{
|
||||
typ: T.typ
|
||||
data: unsafe { malloc(tsize) }
|
||||
}
|
||||
unsafe {
|
||||
vmemcpy(a.data, &obj, tsize)
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
fn cast<T>(obj Any) ?T {
|
||||
if T.typ == obj.typ {
|
||||
return *&T(obj.data)
|
||||
}
|
||||
return none
|
||||
}
|
||||
|
||||
fn test_any_values() {
|
||||
arr := [make_any(true), make_any(false), make_any(7), make_any('cat'),
|
||||
make_any([3.1415926535]),
|
||||
]
|
||||
for elm in arr {
|
||||
if b := cast<bool>(elm) {
|
||||
println(!b)
|
||||
} else if i := cast<int>(elm) {
|
||||
println(i + 1)
|
||||
} else if s := cast<string>(elm) {
|
||||
println(s + '!')
|
||||
} else if f := cast<[]f64>(elm) {
|
||||
println(f[0])
|
||||
}
|
||||
}
|
||||
if b := cast<bool>(arr[0]) {
|
||||
assert b == true
|
||||
}
|
||||
if b := cast<bool>(arr[1]) {
|
||||
assert b == false
|
||||
}
|
||||
if s := cast<string>(arr[3]) {
|
||||
assert s == 'cat'
|
||||
}
|
||||
if f := cast<[]f64>(arr[4]) {
|
||||
assert math.veryclose(f[0], 3.1415926535)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user