implement typeof in types

This commit is contained in:
WebFreak001 2023-06-24 20:58:54 +02:00 committed by Jan Jurzitza
parent 25139a8833
commit fe6ce04720
12 changed files with 187 additions and 43 deletions

View File

@ -165,6 +165,20 @@ package istring[24] builtinTypeNames;
* class. DSymbol child of the class type, with the baseClass as its child type.
*/
@("super") istring SUPER_SYMBOL_NAME;
/**
* This symbol name may appear at the start of breadcrumbs meaning the remaining
* breadcrumbs up until the matching $(LREF TYPEOF_END_SYMBOL_NAME) are an
* initializer or typeof expression. Pointer/Array suffixes are parsed
* beforehand, using popBack to remove them from the breadcrumbs.
*
* See_Also: $(LREF TYPEOF_END_SYMBOL_NAME)
*/
@("typeof(") istring TYPEOF_SYMBOL_NAME;
/**
* This symbol always appears in pairs with TYPEOF_SYMBOL_NAME, designates the
* end of the typeof expression in the breadcrumbs.
*/
@(")/*typeof*/") istring TYPEOF_END_SYMBOL_NAME;
/**
* Breadcrumb part in initializer type generation for literal values in the

View File

@ -271,7 +271,7 @@ final class FirstPass : ASTVisitor
part.identifier.text, CompletionKind.variableName,
symbolFile, part.identifier.index);
symbol.parent = currentSymbol;
populateInitializer(symbol, part.initializer);
populateInitializer(symbol.typeLookups, part.initializer);
symbol.acSymbol.protection = protection.current;
symbol.acSymbol.doc = makeDocumentation(dec.comment);
currentSymbol.addChild(symbol, true);
@ -719,7 +719,7 @@ final class FirstPass : ASTVisitor
currentSymbol.addChild(symbol, true);
currentScope.addSymbol(symbol.acSymbol, true);
if (symbol.typeLookups.empty && feExpression !is null)
populateInitializer(symbol, feExpression, true);
populateInitializer(symbol.typeLookups, feExpression, true);
}
}
@ -738,7 +738,7 @@ final class FirstPass : ASTVisitor
currentSymbol.addChild(symbol, true);
currentScope.addSymbol(symbol.acSymbol, true);
if (symbol.typeLookups.empty && ifs.condition !is null && ifs.condition.expression !is null)
populateInitializer(symbol, ifs.condition.expression, false);
populateInitializer(symbol.typeLookups, ifs.condition.expression, false);
}
ifs.accept(this);
}
@ -756,7 +756,7 @@ final class FirstPass : ASTVisitor
currentScope.startLocation, null);
scope(exit) popSymbol();
populateInitializer(currentSymbol, withStatement.expression, false);
populateInitializer(currentSymbol.typeLookups, withStatement.expression, false);
withStatement.accept(this);
}
@ -1127,12 +1127,19 @@ private:
return istring(app.data);
}
void populateInitializer(T)(SemanticSymbol* symbol, const T initializer,
bool appendForeach = false)
void populateInitializer(T)(ref TypeLookups lookups, const T initializer,
bool appendForeach = false, TypeLookup* l = null)
{
auto lookup = TypeLookupsAllocator.instance.make!TypeLookup(TypeLookupKind.initializer);
auto lookup = l ? l : TypeLookupsAllocator.instance.make!TypeLookup(TypeLookupKind.varOrFunType);
lookup.breadcrumbs.insert(TYPEOF_SYMBOL_NAME);
scope (exit)
lookup.breadcrumbs.insert(TYPEOF_END_SYMBOL_NAME);
scope visitor = new InitializerVisitor(lookup, appendForeach, this);
symbol.typeLookups.insert(lookup);
if (l is null)
lookups.insert(lookup);
static if (is(T == typeof(feExpression)))
visitor.dynamicDispatch(initializer);
else
@ -1155,22 +1162,20 @@ private:
auto lookup = l !is null ? l : TypeLookupsAllocator.instance.make!TypeLookup(
TypeLookupKind.varOrFunType);
auto t2 = type.type2;
if (t2.type !is null)
addTypeToLookups(lookups, t2.type, lookup);
if (t2.typeofExpression !is null)
populateInitializer(lookups, t2.typeofExpression, false, lookup);
else if (t2.superOrThis is tok!"this")
lookup.breadcrumbs.insert(internString("this"));
else if (t2.superOrThis is tok!"super")
lookup.breadcrumbs.insert(internString("super"));
if (t2.type !is null)
addTypeToLookups(lookups, t2.type, lookup);
else if (t2.builtinType !is tok!"")
lookup.breadcrumbs.insert(getBuiltinTypeName(t2.builtinType));
else if (t2.typeIdentifierPart !is null)
writeIotcTo(t2.typeIdentifierPart, lookup.breadcrumbs);
else
{
// TODO: Add support for typeof expressions
// TODO: Add support for __vector
// warning("typeof() and __vector are not yet supported");
}
// TODO: support __vector, traits and mixin
foreach (suffix; type.typeSuffixes)
{

View File

@ -237,10 +237,27 @@ do
}
// Follow all the names and try to resolve them
size_t i = 0;
foreach (part; lookup.breadcrumbs[])
bool first = true;
auto breadcrumbs = lookup.breadcrumbs[];
while (!breadcrumbs.empty)
{
if (i == 0)
auto part = breadcrumbs.front;
breadcrumbs.popFront();
scope (exit)
first = false;
if (part == TYPEOF_SYMBOL_NAME)
{
if (currentSymbol !is null)
{
warning("Invalid breadcrumbs, found `Type.typeof(...)`");
return;
}
resolveTypeFromInitializer(symbol, lookup, moduleScope, cache,
breadcrumbs, currentSymbol);
}
else if (first)
{
if (moduleScope is null)
getSymbolFromImports(imports, part);
@ -273,7 +290,6 @@ do
return;
currentSymbol = currentSymbol.getFirstPartNamed(part);
}
++i;
if (currentSymbol is null)
return;
}
@ -311,19 +327,32 @@ do
}
}
void resolveTypeFromInitializer(DSymbol* symbol, TypeLookup* lookup,
Scope* moduleScope, ref ModuleCache cache)
private void resolveTypeFromInitializer(R)(DSymbol* symbol, TypeLookup* lookup,
Scope* moduleScope, ref ModuleCache cache,
ref R breadcrumbs, ref DSymbol* currentSymbol)
{
if (lookup.breadcrumbs.length == 0)
if (breadcrumbs.empty)
return;
DSymbol* currentSymbol = null;
size_t i = 0;
auto crumbs = lookup.breadcrumbs[];
foreach (crumb; crumbs)
bool first = true;
while (!breadcrumbs.empty)
{
if (i == 0)
auto crumb = breadcrumbs.front;
breadcrumbs.popFront();
if (crumb == TYPEOF_SYMBOL_NAME)
{
resolveTypeFromInitializer(symbol, lookup, moduleScope, cache,
breadcrumbs, currentSymbol);
if (currentSymbol is null)
return;
continue;
}
if (crumb == TYPEOF_END_SYMBOL_NAME)
break;
if (first)
{
first = false;
currentSymbol = moduleScope.getFirstSymbolByNameAndCursor(
symbolNameToTypeName(crumb), symbol.location);
@ -348,18 +377,21 @@ void resolveTypeFromInitializer(DSymbol* symbol, TypeLookup* lookup,
|| currentSymbol.qualifier == SymbolQualifier.pointer
|| currentSymbol.kind == CompletionKind.aliasName)
{
if (currentSymbol.type !is null)
currentSymbol = currentSymbol.type;
else
return;
// may become null, returns later
currentSymbol = currentSymbol.type;
}
else
{
auto opIndex = currentSymbol.getFirstPartNamed(internString("opIndex"));
if (opIndex !is null)
{
currentSymbol = opIndex.type;
}
else
{
currentSymbol = null;
return;
}
}
}
else if (crumb == "foreach")
@ -371,19 +403,19 @@ void resolveTypeFromInitializer(DSymbol* symbol, TypeLookup* lookup,
|| currentSymbol.qualifier == SymbolQualifier.assocArray)
{
currentSymbol = currentSymbol.type;
break;
continue;
}
auto front = currentSymbol.getFirstPartNamed(internString("front"));
if (front !is null)
{
currentSymbol = front.type;
break;
continue;
}
auto opApply = currentSymbol.getFirstPartNamed(internString("opApply"));
if (opApply !is null)
{
currentSymbol = opApply.type;
break;
continue;
}
}
else
@ -393,13 +425,10 @@ void resolveTypeFromInitializer(DSymbol* symbol, TypeLookup* lookup,
return;
currentSymbol = currentSymbol.getFirstPartNamed(crumb);
}
++i;
if (currentSymbol is null)
return;
}
typeSwap(currentSymbol);
symbol.type = currentSymbol;
symbol.ownType = false;
}
private:
@ -506,8 +535,6 @@ void resolveType(DSymbol* symbol, ref TypeLookups typeLookups,
foreach(lookup; typeLookups) {
if (lookup.kind == TypeLookupKind.varOrFunType)
resolveTypeFromType(symbol, lookup, moduleScope, cache, null);
else if (lookup.kind == TypeLookupKind.initializer)
resolveTypeFromInitializer(symbol, lookup, moduleScope, cache);
// issue 94
else if (lookup.kind == TypeLookupKind.inherit)
resolveInheritance(symbol, typeLookups, moduleScope, cache);

View File

@ -64,8 +64,6 @@ void checkMissingTypes(SemanticSymbol* currentSymbol, Scope* moduleScope, ref Mo
auto lookup = currentSymbol.typeLookups.front;
if (lookup.kind == TypeLookupKind.varOrFunType)
resolveTypeFromType(currentSymbol.acSymbol, lookup, moduleScope, cache, null);
else if (lookup.kind == TypeLookupKind.initializer)
resolveTypeFromInitializer(currentSymbol.acSymbol, lookup, moduleScope, cache);
}
break;
default:

View File

@ -10,7 +10,6 @@ enum TypeLookupKind : ubyte
{
inherit,
aliasThis,
initializer,
mixinTemplate,
varOrFunType,
selectiveImport,

View File

@ -0,0 +1,20 @@
identifiers
getMember f typeof(member) getMember() stdin 78 Result
identifiers
staticMember f typeof(S.member) staticMember() stdin 133 Result
identifiers
alignof k
expected v int expected stdin 21 int
init k
mangleof k
sizeof k
stringof k
tupleof k
identifiers
alignof k
expected v int expected stdin 21 int
init k
mangleof k
sizeof k
stringof k
tupleof k

View File

@ -0,0 +1,2 @@
identifiers
test v Enum test stdin 121 Enum

View File

@ -0,0 +1,8 @@
identifiers
alignof k
init k
mangleof k
ok v bool ok stdin 16 bool
sizeof k
stringof k
tupleof k

14
tests/tc_typeof/run.sh Executable file
View File

@ -0,0 +1,14 @@
set -e
set -u
../../bin/dcd-client $1 test1.d -x -c213 > actual1.txt
../../bin/dcd-client $1 test1.d -x -c239 >> actual1.txt
../../bin/dcd-client $1 test1.d -x -c254 >> actual1.txt
../../bin/dcd-client $1 test1.d -x -c265 >> actual1.txt
diff actual1.txt expected1.txt --strip-trailing-cr
../../bin/dcd-client $1 test2.d -x -c132 > actual2.txt
diff actual2.txt expected2.txt --strip-trailing-cr
../../bin/dcd-client $1 test3.d -x -c83 > actual3.txt
diff actual3.txt expected3.txt --strip-trailing-cr

32
tests/tc_typeof/test1.d Normal file
View File

@ -0,0 +1,32 @@
struct Result
{
int expected;
}
struct S
{
Result member;
typeof(member) getMember()
{
return member;
}
}
typeof(S.member) staticMember()
{
return S.init.member;
}
void test()
{
S s;
auto a = S.getMember();
auto b = staticMember();
{
a.
}
{
b.
}
}

15
tests/tc_typeof/test2.d Normal file
View File

@ -0,0 +1,15 @@
struct MyTemplate(T)
{
enum Enum { a, b }
T member1;
}
MyTemplate!long global2;
void main()
{
typeof(global2).Enum test;
test
}

10
tests/tc_typeof/test3.d Normal file
View File

@ -0,0 +1,10 @@
struct S { bool ok; }
S global3;
void main()
{
typeof(global3)[] test;
test[0].
}