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

Commit 0a0736b

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 0a0736b

File tree

4 files changed

+78
-3
lines changed

4 files changed

+78
-3
lines changed

changelog/isbaseof.dd

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
Added TypeInfo_Class/TypeInfo_Interface.isBaseOf that works like C#/Java isAssignableFrom.
2+
3+
`TypeInfo_Class.isBaseOf` returns true if the argument and the receiver
4+
are equal or if the class represented by the argument inherits from the
5+
class represented by the receiver. This is called `isBaseOf` instead of
6+
`isAssignableFrom` to avoid confusion for classes that overload
7+
`opAssign` and so may allow assignment from classes outside their
8+
inheritance hierarchy and to match existing terminology in the D
9+
runtime. `TypeInfo_Interface.isBaseOf` is similar with the addition
10+
that the argument may be either `TypeInfo_Class` or
11+
`TypeInfo_Interface`.
12+
-------
13+
class ClassA {}
14+
class ClassB : ClassA {}
15+
16+
auto a = new ClassA(), b = new ClassB(), c = new Object();
17+
18+
assert(typeid(a).isBaseOf(typeid(b)));
19+
assert(!typeid(a).isBaseOf(typeid(c)));
20+
-------

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
1110+
* class 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
1116+
* class described by this `TypeInfo_Class`.
1117+
*/
1118+
final 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
1217+
* interface 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
1223+
* interface described by this `TypeInfo_Interface`.
1224+
*/
1225+
final 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+
* 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+
* interface described by this `TypeInfo_Interface`.
1240+
*/
1241+
final 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)))

0 commit comments

Comments
 (0)