Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.

Commit ab380aa

Browse files
committed
Fix Issue 20178 - Add TypeInfo_Class/TypeInfo_Interface.isBaseOf
Equivalent to C#/Java isAssignableFrom. Naming the method "isAssignableFrom" would be more familiar to people coming from C#/Java but is potentially misleading: "alias this" and overloadable opAssign mean that this would not actually indicate whether values of one type could be assigned to another. Adding qualifiers to rt.cast_ functions.
1 parent a2ee5cc commit ab380aa

File tree

4 files changed

+93
-3
lines changed

4 files changed

+93
-3
lines changed

src/object.d

+52
Original file line numberDiff line numberDiff line change
@@ -959,6 +959,8 @@ class TypeInfo_Delegate : TypeInfo
959959
}
960960

961961
private extern (C) Object _d_newclass(const TypeInfo_Class ci);
962+
private extern (C) int _d_isbaseof(scope TypeInfo_Class child,
963+
scope const TypeInfo_Class parent) @nogc nothrow pure @safe; // rt.cast_
962964

963965
/**
964966
* Runtime type information about a class.
@@ -1102,6 +1104,24 @@ class TypeInfo_Class : TypeInfo
11021104
}
11031105
return o;
11041106
}
1107+
1108+
/**
1109+
* Returns true if the class described by `child` derives from the class
1110+
* described by this `TypeInfo_Class`.
1111+
*
1112+
* Params:
1113+
* child = TypeInfo for some class
1114+
* Returns:
1115+
* true if the class described by `child` derives from the class described
1116+
* by `child`, false otherwise.
1117+
*/
1118+
bool isBaseOf(scope const TypeInfo_Class child) const @nogc nothrow pure @trusted
1119+
{
1120+
for (auto ti = cast() child; ti !is null; ti = ti.base)
1121+
if (ti is this)
1122+
return true;
1123+
return false;
1124+
}
11051125
}
11061126

11071127
alias ClassInfo = TypeInfo_Class;
@@ -1191,6 +1211,38 @@ class TypeInfo_Interface : TypeInfo
11911211
override @property uint flags() nothrow pure const { return 1; }
11921212

11931213
TypeInfo_Class info;
1214+
1215+
/**
1216+
* Returns true if the class described by `child` derives from the interface
1217+
* described by this `TypeInfo_Interface`.
1218+
*
1219+
* Params:
1220+
* child = TypeInfo for some class
1221+
* Returns:
1222+
* true if the class described by `child` derives from the class described
1223+
* by `child`, false otherwise.
1224+
*/
1225+
bool isBaseOf(scope const TypeInfo_Class child) const @nogc nothrow pure @trusted
1226+
{
1227+
auto child_ = cast() child;
1228+
return cast(bool) _d_isbaseof(child_, this.info);
1229+
}
1230+
1231+
/**
1232+
* Returns true if the interface described by `child` derives from the
1233+
* the interface described by this `TypeInfo_Interface`.
1234+
*
1235+
* Params:
1236+
* child = TypeInfo for some interface
1237+
* Returns:
1238+
* true if the interface described by `child` derives from the
1239+
* the interface described by this `TypeInfo_Interface`.
1240+
*/
1241+
bool isBaseOf(scope const TypeInfo_Interface child) const @nogc nothrow pure @trusted
1242+
{
1243+
auto child_ = cast() child;
1244+
return child !is null && cast(bool) _d_isbaseof(child_.info, this.info);
1245+
}
11941246
}
11951247

11961248
class TypeInfo_Struct : TypeInfo

src/rt/cast_.d

+5-2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
module rt.cast_;
1515

1616
extern (C):
17+
@nogc:
18+
nothrow:
19+
pure:
1720

1821
/******************************************
1922
* Given a pointer:
@@ -74,7 +77,7 @@ void* _d_dynamic_cast(Object o, ClassInfo c)
7477
return res;
7578
}
7679

77-
int _d_isbaseof2(ClassInfo oc, ClassInfo c, ref size_t offset)
80+
int _d_isbaseof2(scope ClassInfo oc, scope const ClassInfo c, scope ref size_t offset) @safe
7881
{
7982
if (oc is c)
8083
return true;
@@ -101,7 +104,7 @@ int _d_isbaseof2(ClassInfo oc, ClassInfo c, ref size_t offset)
101104
return false;
102105
}
103106

104-
int _d_isbaseof(ClassInfo oc, ClassInfo c)
107+
int _d_isbaseof(scope ClassInfo oc, scope const ClassInfo c) @safe
105108
{
106109
if (oc is c)
107110
return true;

test/typeinfo/Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
include ../common.mak
22

3-
TESTS:=comparison
3+
TESTS:=comparison isbaseof
44

55
.PHONY: all clean
66
all: $(addprefix $(ROOT)/,$(addsuffix .done,$(TESTS)))

test/typeinfo/src/isbaseof.d

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// https://issues.dlang.org/show_bug.cgi?id=20178
2+
3+
interface I {}
4+
interface J : I {}
5+
class C1 : I {}
6+
class C2 : C1 {}
7+
class C3 : J {}
8+
9+
void main() @nogc nothrow pure @safe
10+
{
11+
assert(typeid(C1).isBaseOf(typeid(C1)));
12+
assert(typeid(C1).isBaseOf(typeid(C2)));
13+
14+
assert(!typeid(C2).isBaseOf(typeid(C1)));
15+
assert(typeid(C2).isBaseOf(typeid(C2)));
16+
17+
assert(!typeid(C1).isBaseOf(typeid(Object)));
18+
assert(!typeid(C2).isBaseOf(typeid(Object)));
19+
assert(typeid(Object).isBaseOf(typeid(C1)));
20+
assert(typeid(Object).isBaseOf(typeid(C2)));
21+
22+
assert(typeid(I).isBaseOf(typeid(I)));
23+
assert(typeid(I).isBaseOf(typeid(J)));
24+
assert(typeid(I).isBaseOf(typeid(C1)));
25+
assert(typeid(I).isBaseOf(typeid(C2)));
26+
assert(typeid(I).isBaseOf(typeid(C3)));
27+
assert(!typeid(I).isBaseOf(typeid(Object)));
28+
29+
assert(!typeid(J).isBaseOf(typeid(I)));
30+
assert(typeid(J).isBaseOf(typeid(J)));
31+
assert(!typeid(J).isBaseOf(typeid(C1)));
32+
assert(!typeid(J).isBaseOf(typeid(C2)));
33+
assert(typeid(J).isBaseOf(typeid(C3)));
34+
assert(!typeid(J).isBaseOf(typeid(Object)));
35+
}

0 commit comments

Comments
 (0)