1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-09 03:52:19 +02:00

Added nameof

This commit is contained in:
Brian Fiete 2022-07-06 12:19:01 -07:00
parent dd0d67cca1
commit 7dd2324fcf
13 changed files with 307 additions and 13 deletions

View file

@ -361,6 +361,11 @@ void BfStructuralVisitor::Visit(BfOffsetOfExpression* offsetOfExpr)
Visit(offsetOfExpr->ToBase());
}
void BfStructuralVisitor::Visit(BfNameOfExpression* nameOfExpr)
{
Visit(nameOfExpr->ToBase());
}
void BfStructuralVisitor::Visit(BfIsConstExpression* isConstExpr)
{
Visit(isConstExpr->ToBase());

View file

@ -381,6 +381,7 @@ class BfTypeAttrExpression;
class BfSizeOfExpression;
class BfAlignOfExpression;
class BfOffsetOfExpression;
class BfNameOfExpression;
class BfStrideOfExpression;
class BfIsConstExpression;
class BfDefaultExpression;
@ -508,6 +509,7 @@ public:
virtual void Visit(BfAlignOfExpression* alignOfExpr);
virtual void Visit(BfStrideOfExpression* strideOfExpr);
virtual void Visit(BfOffsetOfExpression* offsetOfExpr);
virtual void Visit(BfNameOfExpression* nameOfExpr);
virtual void Visit(BfIsConstExpression* isConstExpr);
virtual void Visit(BfDefaultExpression* defaultExpr);
virtual void Visit(BfUninitializedExpression* uninitializedExpr);
@ -2728,6 +2730,16 @@ public:
BfIdentifierNode* mMemberName;
}; BF_AST_DECL(BfOffsetOfExpression, BfTypeAttrExpression);
class BfNameOfExpression : public BfExpression
{
public:
BF_AST_TYPE(BfNameOfExpression, BfExpression);
BfTokenNode* mToken;
BfTokenNode* mOpenParen;
BfAstNode* mTarget;
BfTokenNode* mCloseParen;
}; BF_AST_DECL(BfNameOfExpression, BfExpression);
class BfIsConstExpression : public BfExpression
{
public:

View file

@ -690,6 +690,12 @@ void BfAutoComplete::AddTypeDef(BfTypeDef* typeDef, const StringImpl& filter, bo
bool BfAutoComplete::CheckProtection(BfProtection protection, BfTypeDef* typeDef, bool allowProtected, bool allowPrivate)
{
if (mResolveType == BfResolveType_GetSymbolInfo)
{
// This is needed for nameof on private inner types
return true;
}
if ((protection == BfProtection_Internal) && (typeDef != NULL))
{
return mModule->CheckProtection(protection, typeDef, allowProtected, allowPrivate);

View file

@ -519,6 +519,8 @@ void BfElementVisitor::Visit(BfTypeAttrExpression* typeAttrExpr)
void BfElementVisitor::Visit(BfOffsetOfExpression* offsetOfExpr)
{
Visit(offsetOfExpr->ToBase());
VisitChild(offsetOfExpr->mToken);
VisitChild(offsetOfExpr->mOpenParen);
VisitChild(offsetOfExpr->mTypeRef);
@ -527,6 +529,16 @@ void BfElementVisitor::Visit(BfOffsetOfExpression* offsetOfExpr)
VisitChild(offsetOfExpr->mCloseParen);
}
void BfElementVisitor::Visit(BfNameOfExpression* nameOfExpr)
{
Visit(nameOfExpr->ToBase());
VisitChild(nameOfExpr->mToken);
VisitChild(nameOfExpr->mOpenParen);
VisitChild(nameOfExpr->mTarget);
VisitChild(nameOfExpr->mCloseParen);
}
void BfElementVisitor::Visit(BfDefaultExpression* defaultExpr)
{
Visit(defaultExpr->ToBase());

View file

@ -72,6 +72,7 @@ public:
virtual void Visit(BfParameterDeclaration* paramDecl);
virtual void Visit(BfTypeAttrExpression* typeAttrExpr);
virtual void Visit(BfOffsetOfExpression* offsetOfExpr);
virtual void Visit(BfNameOfExpression* nameOfExpr);
virtual void Visit(BfDefaultExpression* defaultExpr);
virtual void Visit(BfIsConstExpression* isConstExpr);
virtual void Visit(BfUninitializedExpression* uninitializedExpr);

View file

@ -3762,6 +3762,49 @@ static bool IsCharType(BfTypeCode typeCode)
}
}
bool BfExprEvaluator::CheckForMethodName(BfAstNode* refNode, BfTypeInstance* typeInst, const StringImpl& findName)
{
BF_ASSERT((mBfEvalExprFlags & BfEvalExprFlags_NameOf) != 0);
auto autoComplete = GetAutoComplete();
while (typeInst != NULL)
{
auto typeDef = typeInst->mTypeDef;
typeDef->PopulateMemberSets();
BfMemberSetEntry* memberSetEntry;
if (typeDef->mMethodSet.TryGetWith(findName, &memberSetEntry))
{
if (mModule->mCompiler->mResolvePassData != NULL)
mModule->mCompiler->mResolvePassData->HandleMethodReference(refNode, typeDef, (BfMethodDef*)memberSetEntry->mMemberDef);
if ((autoComplete != NULL) && (autoComplete->IsAutocompleteNode(refNode)))
{
autoComplete->SetDefinitionLocation(((BfMethodDef*)memberSetEntry->mMemberDef)->GetRefNode());
if ((autoComplete->mResolveType == BfResolveType_GetSymbolInfo) && (autoComplete->mDefType == NULL))
{
autoComplete->mDefType = typeDef;
autoComplete->mDefMethod = (BfMethodDef*)memberSetEntry->mMemberDef;
}
}
if (mModule->mCompiler->mResolvePassData != NULL)
{
if (auto sourceClassifier = mModule->mCompiler->mResolvePassData->GetSourceClassifier(refNode))
sourceClassifier->SetElementType(refNode, BfSourceElementType_Method);
}
mBfEvalExprFlags = (BfEvalExprFlags)(mBfEvalExprFlags | BfEvalExprFlags_NameOfSuccess);
return true;
}
typeInst = typeInst->mBaseType;
}
return false;
}
bool BfExprEvaluator::IsVar(BfType* type, bool forceIgnoreWrites)
{
if (type->IsVar())
@ -4591,6 +4634,9 @@ void BfExprEvaluator::Visit(BfIdentifierNode* identifierNode)
}
}
if (((mBfEvalExprFlags & BfEvalExprFlags_NameOf) != 0) && (mModule->mCurTypeInstance != NULL) && (CheckForMethodName(identifierNode, mModule->mCurTypeInstance, identifierNode->ToString())))
return;
if ((mBfEvalExprFlags & BfEvalExprFlags_NoLookupError) == 0)
mModule->Fail("Identifier not found", identifierNode);
}
@ -5063,7 +5109,7 @@ BfTypedValue BfExprEvaluator::LoadField(BfAstNode* targetSrc, BfTypedValue targe
}
else if (!target)
{
if (mModule->PreFail())
if (((mBfEvalExprFlags & BfEvalExprFlags_NameOf) == 0) && (mModule->PreFail()))
{
if ((flags & BfLookupFieldFlag_CheckingOuter) != 0)
mModule->Fail(StrFormat("An instance reference is required to reference non-static outer field '%s.%s'", mModule->TypeToString(typeInstance).c_str(), fieldDef->mName.c_str()),
@ -5530,7 +5576,7 @@ BfTypedValue BfExprEvaluator::LookupField(BfAstNode* targetSrc, BfTypedValue tar
auto prop = nextProp;
nextProp = nextProp->mNextWithSameName;
if ((!isFailurePass) && (!mModule->CheckProtection(protectionCheckFlags, curCheckType, prop->mDeclaringType->mProject, prop->mProtection, startCheckType)))
if ((!isFailurePass) && ((mBfEvalExprFlags & BfEvalExprFlags_NameOf) == 0) && (!mModule->CheckProtection(protectionCheckFlags, curCheckType, prop->mDeclaringType->mProject, prop->mProtection, startCheckType)))
{
continue;
}
@ -5543,7 +5589,7 @@ BfTypedValue BfExprEvaluator::LookupField(BfAstNode* targetSrc, BfTypedValue tar
continue;
}
if ((!target.IsStatic()) || (prop->mIsStatic))
if ((!target.IsStatic()) || (prop->mIsStatic) || ((mBfEvalExprFlags & BfEvalExprFlags_NameOf) != 0))
{
if (!mModule->IsInSpecializedSection())
{
@ -10864,6 +10910,10 @@ void BfExprEvaluator::LookupQualifiedName(BfAstNode* nameNode, BfIdentifierNode*
{
FixitAddMember(typeInst, mExpectingType, nameRight->ToString(), false);
}
if (((mBfEvalExprFlags & BfEvalExprFlags_NameOf) != 0) && (typeInst != NULL) && (CheckForMethodName(nameRight, typeInst, fieldName)))
return;
mModule->Fail(StrFormat("Unable to find member '%s' in '%s'", fieldName.c_str(), mModule->TypeToString(lookupType).c_str()), nameRight);
}
@ -11013,6 +11063,13 @@ void BfExprEvaluator::LookupQualifiedStaticField(BfAstNode* nameNode, BfIdentifi
}
}
if ((mBfEvalExprFlags & BfEvalExprFlags_NameOf) != 0)
{
auto typeInst = lookupType.mType->ToTypeInstance();
if ((typeInst != NULL) && (CheckForMethodName(nameRight, typeInst, findName)))
return;
}
if ((mBfEvalExprFlags & BfEvalExprFlags_NoLookupError) == 0)
mModule->Fail("Field not found", nameRight);
return;
@ -11885,6 +11942,135 @@ void BfExprEvaluator::Visit(BfOffsetOfExpression* offsetOfExpr)
DoTypeIntAttr(offsetOfExpr->mTypeRef, offsetOfExpr->mCommaToken, offsetOfExpr->mMemberName, BfToken_OffsetOf);
}
void BfExprEvaluator::Visit(BfNameOfExpression* nameOfExpr)
{
String name;
if (mModule->IsInSpecializedGeneric())
{
if (auto identifierNode = BfNodeDynCastExact<BfIdentifierNode>(nameOfExpr->mTarget))
{
// This is necessary so we don't resolve 'T' to the actual generic argument type
name = identifierNode->ToString();
}
}
if (name.IsEmpty())
{
auto type = mModule->ResolveTypeRef(nameOfExpr->mTarget, {}, BfPopulateType_IdentityNoRemapAlias,
(BfResolveTypeRefFlags)(BfResolveTypeRefFlag_AllowUnboundGeneric | BfResolveTypeRefFlag_IgnoreLookupError | BfResolveTypeRefFlag_IgnoreProtection));
if (type != NULL)
{
auto typeInst = type->ToTypeInstance();
if (typeInst != NULL)
name = typeInst->mTypeDef->mName->ToString();
else
name = mModule->TypeToString(type);
mModule->AddDependency(type, mModule->mCurTypeInstance, BfDependencyMap::DependencyFlag_NameReference);
// Just do this for autocomplete
SetAndRestoreValue<bool> prevIgnoreErrors(mModule->mIgnoreErrors, true);
VisitChild(nameOfExpr->mTarget);
}
}
if (name.IsEmpty())
{
if (auto identifer = BfNodeDynCast<BfIdentifierNode>(nameOfExpr->mTarget))
{
String targetStr = nameOfExpr->mTarget->ToString();
BfAtomComposite targetComposite;
bool isValid = mModule->mSystem->ParseAtomComposite(targetStr, targetComposite);
bool namespaceExists = false;
BfProject* bfProject = NULL;
auto activeTypeDef = mModule->GetActiveTypeDef();
if (activeTypeDef != NULL)
bfProject = activeTypeDef->mProject;
auto _CheckProject = [&](BfProject* project)
{
if ((isValid) && (project->mNamespaces.ContainsKey(targetComposite)))
namespaceExists = true;
};
if (bfProject != NULL)
{
for (int depIdx = -1; depIdx < (int)bfProject->mDependencies.size(); depIdx++)
{
BfProject* depProject = (depIdx == -1) ? bfProject : bfProject->mDependencies[depIdx];
_CheckProject(depProject);
}
}
else
{
for (auto project : mModule->mSystem->mProjects)
_CheckProject(project);
}
if (namespaceExists)
{
if (mModule->mCompiler->mResolvePassData != NULL)
{
if (auto sourceClassifier = mModule->mCompiler->mResolvePassData->GetSourceClassifier(nameOfExpr->mTarget))
{
BfAstNode* checkIdentifier = identifer;
while (true)
{
auto qualifiedIdentifier = BfNodeDynCast<BfQualifiedNameNode>(checkIdentifier);
if (qualifiedIdentifier == NULL)
break;
sourceClassifier->SetElementType(qualifiedIdentifier->mRight, BfSourceElementType_Namespace);
checkIdentifier = qualifiedIdentifier->mLeft;
}
sourceClassifier->SetElementType(checkIdentifier, BfSourceElementType_Namespace);
}
}
name = targetComposite.mParts[targetComposite.mSize - 1]->ToString();
}
}
}
if (name.IsEmpty())
{
SetAndRestoreValue<BfEvalExprFlags> prevFlags(mBfEvalExprFlags, (BfEvalExprFlags)(mBfEvalExprFlags | BfEvalExprFlags_NameOf));
VisitChild(nameOfExpr->mTarget);
if ((mBfEvalExprFlags & BfEvalExprFlags_NameOfSuccess) != 0)
{
BfAstNode* nameNode = nameOfExpr->mTarget;
if (auto attributedIdentifierNode = BfNodeDynCast<BfAttributedIdentifierNode>(nameNode))
nameNode = attributedIdentifierNode->mIdentifier;
if (auto memberReferenceExpr = BfNodeDynCast<BfMemberReferenceExpression>(nameNode))
nameNode = memberReferenceExpr->mMemberName;
if (auto qualifiedNameNode = BfNodeDynCast<BfQualifiedNameNode>(nameNode))
nameNode = qualifiedNameNode->mRight;
name = nameNode->ToString();
}
else if (mResultFieldInstance != NULL)
{
auto fieldDef = mResultFieldInstance->GetFieldDef();
if (fieldDef != NULL)
name = fieldDef->mName;
}
else if (mResultLocalVar != NULL)
{
name = mResultLocalVar->mName;
}
else if (mPropDef != NULL)
{
name = mPropDef->mName;
}
}
if ((name.IsEmpty()) && (nameOfExpr->mTarget != NULL))
mModule->Fail("Expression does not have a name", nameOfExpr->mTarget);
mResult = BfTypedValue(mModule->GetStringObjectValue(name), mModule->ResolveTypeDef(mModule->mCompiler->mStringTypeDef));
}
void BfExprEvaluator::Visit(BfIsConstExpression* isConstExpr)
{
if (isConstExpr->mExpression == NULL)
@ -21142,6 +21328,13 @@ void BfExprEvaluator::DoMemberReference(BfMemberReferenceExpression* memberRefEx
{
if (auto targetIdentifier = BfNodeDynCast<BfIdentifierNode>(memberRefExpr->mMemberName))
{
if ((mBfEvalExprFlags & BfEvalExprFlags_NameOf) != 0)
{
auto typeInst = thisValue.mType->ToTypeInstance();
if ((typeInst != NULL) && (CheckForMethodName(nameRight, typeInst, findName)))
return;
}
mResult.mType = mModule->ResolveInnerType(thisValue.mType, targetIdentifier, BfPopulateType_Declaration);
}
}

View file

@ -273,8 +273,6 @@ public:
bool IsVarCall(BfType*& outReturnType);
};
class BfBaseClassWalker
{
public:
@ -432,6 +430,7 @@ public:
BfExprEvaluator(BfModule* module);
~BfExprEvaluator();
bool CheckForMethodName(BfAstNode* refNode, BfTypeInstance* typeInst, const StringImpl& findName);
bool IsVar(BfType* type, bool forceIgnoreWrites = false);
void GetLiteral(BfAstNode* refNode, const BfVariant& variant);
void FinishExpressionResult();
@ -559,6 +558,7 @@ public:
virtual void Visit(BfAlignOfExpression* alignOfExpr) override;
virtual void Visit(BfStrideOfExpression* strideOfExpr) override;
virtual void Visit(BfOffsetOfExpression* offsetOfExpr) override;
virtual void Visit(BfNameOfExpression* nameOfExpr) override;
virtual void Visit(BfIsConstExpression* isConstExpr) override;
virtual void Visit(BfDefaultExpression* defaultExpr) override;
virtual void Visit(BfUninitializedExpression* uninitialziedExpr) override;

View file

@ -54,7 +54,7 @@ enum BfPopulateType
BfPopulateType_Full_Force
};
enum BfEvalExprFlags
enum BfEvalExprFlags : int64
{
BfEvalExprFlags_None = 0,
BfEvalExprFlags_ExplicitCast = 1,
@ -89,6 +89,8 @@ enum BfEvalExprFlags
BfEvalExprFlags_AllowGenericConstValue = 0x20000000,
BfEvalExprFlags_IsExpressionBody = 0x40000000,
BfEvalExprFlags_AppendFieldInitializer = 0x80000000,
BfEvalExprFlags_NameOf = 0x100000000LL,
BfEvalExprFlags_NameOfSuccess = 0x200000000LL,
BfEvalExprFlags_InheritFlags = BfEvalExprFlags_NoAutoComplete | BfEvalExprFlags_Comptime | BfEvalExprFlags_DeclType
};
@ -1947,7 +1949,7 @@ public:
BfType* ResolveTypeRef(BfAstNode* astNode, const BfSizedArray<BfAstNode*>* genericArgs, BfPopulateType populateType = BfPopulateType_Data, BfResolveTypeRefFlags resolveFlags = (BfResolveTypeRefFlags)0);
BfType* ResolveTypeDef(BfTypeDef* typeDef, BfPopulateType populateType = BfPopulateType_Data, BfResolveTypeRefFlags resolveFlags = BfResolveTypeRefFlag_None);
BfType* ResolveTypeDef(BfTypeDef* typeDef, const BfTypeVector& genericArgs, BfPopulateType populateType = BfPopulateType_Data, BfResolveTypeRefFlags resolveFlags = BfResolveTypeRefFlag_None);
BfType* ResolveInnerType(BfType* outerType, BfAstNode* typeRef, BfPopulateType populateType = BfPopulateType_Data, bool ignoreErrors = false, int numGenericArgs = 0);
BfType* ResolveInnerType(BfType* outerType, BfAstNode* typeRef, BfPopulateType populateType = BfPopulateType_Data, bool ignoreErrors = false, int numGenericArgs = 0, BfResolveTypeRefFlags resolveFlags = BfResolveTypeRefFlag_None);
BfTypeDef* GetCombinedPartialTypeDef(BfTypeDef* type);
BfTypeInstance* GetOuterType(BfType* type);
bool IsInnerType(BfType* checkInnerType, BfType* checkOuterType);

View file

@ -8029,7 +8029,7 @@ void BfModule::HandleMethodGenericParamRef(BfAstNode* refNode, BfTypeDef* typeDe
mCompiler->mResolvePassData->HandleMethodGenericParam(refNode, typeDef, methodDef, methodGenericParamIdx);
}
BfType* BfModule::ResolveInnerType(BfType* outerType, BfAstNode* typeRef, BfPopulateType populateType, bool ignoreErrors, int numGenericArgs)
BfType* BfModule::ResolveInnerType(BfType* outerType, BfAstNode* typeRef, BfPopulateType populateType, bool ignoreErrors, int numGenericArgs, BfResolveTypeRefFlags resolveFlags)
{
BfTypeDef* nestedTypeDef = NULL;
@ -8092,7 +8092,8 @@ BfType* BfModule::ResolveInnerType(BfType* outerType, BfAstNode* typeRef, BfPopu
{
auto latestCheckType = checkType->GetLatest();
if ((!isFailurePass) && (!CheckProtection(latestCheckType->mProtection, latestCheckType, allowProtected, allowPrivate)))
if ((!isFailurePass) && ((resolveFlags & BfResolveTypeRefFlag_IgnoreProtection) == 0) &&
(!CheckProtection(latestCheckType->mProtection, latestCheckType, allowProtected, allowPrivate)))
continue;
if (checkType->mProject != checkOuterType->mTypeDef->mProject)
@ -8135,7 +8136,7 @@ BfType* BfModule::ResolveInnerType(BfType* outerType, BfAstNode* typeRef, BfPopu
if (nestedTypeDef == NULL)
{
if (!mIgnoreErrors && !ignoreErrors)
if ((!mIgnoreErrors) && (!ignoreErrors) && ((resolveFlags & BfResolveTypeRefFlag_IgnoreLookupError) == 0))
{
StringT<64> name;
name.Append(findName);
@ -11020,7 +11021,7 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
}
}
auto resolvedType = ResolveInnerType(leftType, qualifiedTypeRef->mRight, populateType, false, numGenericArgs);
auto resolvedType = ResolveInnerType(leftType, qualifiedTypeRef->mRight, populateType, false, numGenericArgs, resolveFlags);
if ((resolvedType != NULL) && (mCurTypeInstance != NULL))
AddDependency(leftType, mCurTypeInstance, BfDependencyMap::DependencyFlag_NameReference);
return ResolveTypeResult(typeRef, resolvedType, populateType, resolveFlags);

View file

@ -3174,6 +3174,8 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate, bool disablePrepro
case TOKEN_HASH('n', 'a', 'm', 'e'):
if (SrcPtrHasToken("namespace"))
mToken = BfToken_Namespace;
else if (SrcPtrHasToken("nameof"))
mToken = BfToken_NameOf;
break;
case TOKEN_HASH('n', 'e', 'w', 0):
if (SrcPtrHasToken("new"))

View file

@ -2352,6 +2352,41 @@ BfExpression* BfReducer::CreateExpression(BfAstNode* node, CreateExprFlags creat
exprLeft = CreateMemberReferenceExpression(typeRef);
}
}
else if (tokenNode->GetToken() == BfToken_NameOf)
{
BfNameOfExpression* nameOfExpr = mAlloc->Alloc<BfNameOfExpression>();
ReplaceNode(tokenNode, nameOfExpr);
nameOfExpr->mToken = tokenNode;
tokenNode = ExpectTokenAfter(nameOfExpr, BfToken_LParen);
MEMBER_SET_CHECKED(nameOfExpr, mOpenParen, tokenNode);
mVisitorPos.MoveNext();
int outEndNode = -1;
bool isTypeRef = IsTypeReference(mVisitorPos.GetCurrent(), BfToken_RParen, -1, &outEndNode);
mVisitorPos.mReadPos--;
if ((isTypeRef) && (outEndNode > 0))
{
if (auto tokenNode = BfNodeDynCast<BfTokenNode>(mVisitorPos.Get(outEndNode - 1)))
{
if ((tokenNode->mToken == BfToken_RChevron) || (tokenNode->mToken == BfToken_RDblChevron))
{
// Can ONLY be a type reference
auto typeRef = CreateTypeRefAfter(nameOfExpr);
MEMBER_SET_CHECKED(nameOfExpr, mTarget, typeRef);
}
}
}
if (nameOfExpr->mTarget == NULL)
{
auto expr = CreateExpressionAfter(nameOfExpr);
MEMBER_SET_CHECKED(nameOfExpr, mTarget, expr);
}
tokenNode = ExpectTokenAfter(nameOfExpr, BfToken_RParen);
MEMBER_SET_CHECKED(nameOfExpr, mCloseParen, tokenNode);
exprLeft = nameOfExpr;
}
if (exprLeft == NULL)
{

View file

@ -40,7 +40,8 @@ enum BfResolveTypeRefFlags
BfResolveTypeRefFlag_AllowGlobalsSelf = 0x10000,
BfResolveTypeRefFlag_AllowImplicitConstExpr = 0x20000,
BfResolveTypeRefFlag_AllowUnboundGeneric = 0x40000,
BfResolveTypeRefFlag_ForceUnboundGeneric = 0x80000
BfResolveTypeRefFlag_ForceUnboundGeneric = 0x80000,
BfResolveTypeRefFlag_IgnoreProtection = 0x100000
};
enum BfTypeNameFlags : uint16

View file

@ -1,6 +1,8 @@
#pragma warning disable 168
using System;
using System.Interop;
using System.Collections;
namespace Tests
{
@ -24,5 +26,27 @@ namespace Tests
inStr.Length > 1 || 2 == 3
};
}
static void GetName<T>(String str)
{
str.Append(nameof(T));
}
[Test]
public static void TestNameof()
{
var point = (x: 3, y: 4);
Test.Assert(nameof(System) == "System");
Test.Assert(nameof(System.Collections) == "Collections");
Test.Assert(nameof(point) == "point");
Test.Assert(nameof(point.x) == "x");
Test.Assert(nameof(Tests.Expressions) == "Expressions");
Test.Assert(nameof(c_int) == "c_int");
Test.Assert(nameof(List<int>) == "List");
Test.Assert(nameof(List<int>.Add) == "Add");
Test.Assert(nameof(TestBasics) == "TestBasics");
Test.Assert(GetName<String>(.. scope .()) == "T");
}
}
}