implement typeof in types

This commit is contained in:
WebFreak001 2023-06-24 20:58:54 +02:00
parent 1c60c5480f
commit 35ab44f83d
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. * class. DSymbol child of the class type, with the baseClass as its child type.
*/ */
@("super") istring SUPER_SYMBOL_NAME; @("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 * Breadcrumb part in initializer type generation for literal values in the

View File

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

View File

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

View File

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

View File

@ -10,7 +10,6 @@ enum TypeLookupKind : ubyte
{ {
inherit, inherit,
aliasThis, aliasThis,
initializer,
mixinTemplate, mixinTemplate,
varOrFunType, varOrFunType,
selectiveImport, 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].
}