v.gen.c: support `T.typ` - an int for the type index of the generic type `T` (#11175)

pull/11178/head
Delyan Angelov 2021-08-14 08:48:25 +03:00 committed by GitHub
parent fb3671107e
commit 900c37aa65
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 142 additions and 46 deletions

View File

@ -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))

View File

@ -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
}

View File

@ -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

View File

@ -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
}

View File

@ -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

View File

@ -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)

View File

@ -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
}

View 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)
}
}