mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-08 11:38:21 +02:00
Added 'using' fields
This commit is contained in:
parent
ff229f385d
commit
450d541292
13 changed files with 850 additions and 253 deletions
|
@ -857,13 +857,13 @@ void BfAutoComplete::AddProp(BfTypeInstance* typeInst, BfPropertyDef* propDef, c
|
|||
if (methodDef->mMethodType == BfMethodType_PropertyGetter)
|
||||
{
|
||||
hasGetter = true;
|
||||
propType = methodInstance->mReturnType;
|
||||
propType = methodInstance->mReturnType;
|
||||
}
|
||||
if (methodDef->mMethodType == BfMethodType_PropertySetter)
|
||||
{
|
||||
hasSetter = true;
|
||||
if (methodInstance->GetParamCount() > 0)
|
||||
propType = methodInstance->GetParamType(0);
|
||||
if (methodInstance->GetParamCount() > 0)
|
||||
propType = methodInstance->GetParamType(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1024,6 +1024,63 @@ void BfAutoComplete::AddTypeMembers(BfTypeInstance* typeInst, bool addStatic, bo
|
|||
AddTypeMembers(outerType, true, false, filter, startType, false, allowImplicitThis, false);
|
||||
}
|
||||
}
|
||||
|
||||
if ((typeInst->mTypeDef->mHasUsingFields) &&
|
||||
((typeInst->mTypeInfoEx == NULL) || (typeInst->mTypeInfoEx->mUsingFieldData == NULL)))
|
||||
mModule->PopulateUsingFieldData(typeInst);
|
||||
|
||||
if ((typeInst->mTypeInfoEx != NULL) && (typeInst->mTypeInfoEx->mUsingFieldData != NULL))
|
||||
{
|
||||
for (int pass = 0; pass < 2; pass++)
|
||||
{
|
||||
auto& dict = (pass == 0) ? typeInst->mTypeInfoEx->mUsingFieldData->mEntries : typeInst->mTypeInfoEx->mUsingFieldData->mMethods;
|
||||
for (auto& entryKV : dict)
|
||||
{
|
||||
for (auto& entryList : entryKV.mValue.mLookups)
|
||||
{
|
||||
auto& endEntry = entryList.back();
|
||||
|
||||
bool isStatic = endEntry.IsStatic();
|
||||
if ((isStatic) && (!addStatic))
|
||||
continue;
|
||||
if ((!isStatic) && (!addNonStatic))
|
||||
continue;
|
||||
|
||||
bool passesProtection = true;
|
||||
for (int entryIdx = 0; entryIdx < entryList.mSize; entryIdx++)
|
||||
{
|
||||
auto& entry = entryList[entryIdx];
|
||||
if (!mModule->CheckProtection(protectionCheckFlags, entry.mTypeInstance, entry.GetDeclaringType(mModule)->mProject,
|
||||
(entryIdx < entryList.mSize - 1) ? entry.GetUsingProtection() : entry.GetProtection(), typeInst))
|
||||
{
|
||||
passesProtection = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!passesProtection)
|
||||
continue;
|
||||
|
||||
switch (endEntry.mKind)
|
||||
{
|
||||
case BfUsingFieldData::MemberRef::Kind_Field:
|
||||
if (endEntry.mTypeInstance->mDefineState < BfTypeDefineState_Defined)
|
||||
mModule->PopulateType(endEntry.mTypeInstance);
|
||||
AddField(endEntry.mTypeInstance, endEntry.mTypeInstance->mTypeDef->mFields[endEntry.mIdx], &endEntry.mTypeInstance->mFieldInstances[endEntry.mIdx], filter);
|
||||
break;
|
||||
case BfUsingFieldData::MemberRef::Kind_Property:
|
||||
AddProp(endEntry.mTypeInstance, endEntry.mTypeInstance->mTypeDef->mProperties[endEntry.mIdx], filter);
|
||||
break;
|
||||
case BfUsingFieldData::MemberRef::Kind_Method:
|
||||
{
|
||||
auto methodDef = endEntry.mTypeInstance->mTypeDef->mMethods[endEntry.mIdx];
|
||||
AddMethod(endEntry.mTypeInstance, methodDef, NULL, methodDef->GetMethodDeclaration(), methodDef->mName, filter);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BfAutoComplete::AddSelfResultTypeMembers(BfTypeInstance* typeInst, BfTypeInstance* selfType, const StringImpl& filter, bool allowPrivate)
|
||||
|
@ -3866,3 +3923,27 @@ void BfAutoComplete::SetResultStringType(BfType * type)
|
|||
else
|
||||
mResultString += "\n:type\tvaluetype";
|
||||
}
|
||||
|
||||
void BfAutoComplete::FixitAddFullyQualify(BfAstNode* refNode, const StringImpl& findName, const SizedArrayImpl<BfUsingFieldData::MemberRef>& foundList)
|
||||
{
|
||||
BfProtectionCheckFlags protectionCheckFlags = BfProtectionCheckFlag_None;
|
||||
String fullName;
|
||||
for (int entryIdx = 0; entryIdx < foundList.mSize - 1; entryIdx++)
|
||||
{
|
||||
auto& entry = foundList[entryIdx];
|
||||
if (entryIdx > 0)
|
||||
fullName += ".";
|
||||
if (!mModule->CheckProtection(protectionCheckFlags, entry.mTypeInstance, entry.GetDeclaringType(mModule)->mProject, entry.GetProtection(), mModule->mCurTypeInstance))
|
||||
fullName += "[Friend]";
|
||||
fullName += entry.GetName(mModule);
|
||||
}
|
||||
|
||||
BfParserData* parser = refNode->GetSourceData()->ToParserData();
|
||||
if (parser != NULL)
|
||||
{
|
||||
AddEntry(AutoCompleteEntry("fixit", StrFormat("Fully qualify 'using' name as '%s.%s'\tqualify|%s|%d|%s.",
|
||||
fullName.c_str(), findName.c_str(),
|
||||
parser->mFileName.c_str(), refNode->mSrcStart,
|
||||
fullName.c_str()).c_str()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -277,6 +277,7 @@ public:
|
|||
void FixitAddNamespace(BfAstNode* refNode, const StringImpl& namespacStr);
|
||||
void FixitCheckNamespace(BfTypeDef* activeTypeDef, BfAstNode* typeRef, BfTokenNode* nextDotToken);
|
||||
void FixitAddConstructor(BfTypeInstance* typeInstance);
|
||||
void FixitAddFullyQualify(BfAstNode* refNode, const StringImpl& findName, const SizedArrayImpl<BfUsingFieldData::MemberRef>& foundList);
|
||||
|
||||
void SetResultStringType(BfType* type);
|
||||
};
|
||||
|
|
|
@ -163,6 +163,7 @@ BfMethodMatcher::BfMethodMatcher(BfAstNode* targetSrc, BfModule* module, BfMetho
|
|||
void BfMethodMatcher::Init(const BfMethodGenericArguments& methodGenericArguments)
|
||||
{
|
||||
//mArguments = arguments;
|
||||
mUsingLists = NULL;
|
||||
mActiveTypeDef = NULL;
|
||||
mBestMethodDef = NULL;
|
||||
mBackupMethodDef = NULL;
|
||||
|
@ -2642,7 +2643,7 @@ bool BfMethodMatcher::IsType(BfTypedValue& typedVal, BfType* type)
|
|||
// This method checks all base classes before checking interfaces. Is that correct?
|
||||
bool BfMethodMatcher::CheckType(BfTypeInstance* typeInstance, BfTypedValue target, bool isFailurePass, bool forceOuterCheck)
|
||||
{
|
||||
BfMethodDef* prevBesstMethodDef = mBestMethodDef;
|
||||
BfMethodDef* prevBestMethodDef = mBestMethodDef;
|
||||
auto curTypeInst = typeInstance;
|
||||
auto curTypeDef = typeInstance->mTypeDef;
|
||||
|
||||
|
@ -2812,12 +2813,96 @@ bool BfMethodMatcher::CheckType(BfTypeInstance* typeInstance, BfTypedValue targe
|
|||
}
|
||||
|
||||
if ((mBestMethodDef != NULL) && (mMethodType != BfMethodType_Extension))
|
||||
{
|
||||
{
|
||||
if ((mUsingLists != NULL) && (mUsingLists->mSize != 0))
|
||||
mUsingLists->Clear();
|
||||
|
||||
if (mAutoFlushAmbiguityErrors)
|
||||
FlushAmbiguityError();
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((mUsingLists != NULL) && (curTypeInst->mTypeDef->mHasUsingFields) &&
|
||||
((curTypeInst->mTypeInfoEx == NULL) || (curTypeInst->mTypeInfoEx->mUsingFieldData == NULL)))
|
||||
mModule->PopulateUsingFieldData(curTypeInst);
|
||||
|
||||
if (mUsingLists != NULL)
|
||||
{
|
||||
auto _CheckUsingData = [&](BfUsingFieldData* usingData)
|
||||
{
|
||||
BfUsingFieldData::Entry* entry = NULL;
|
||||
if (!usingData->mMethods.TryGetValue(mMethodName, &entry))
|
||||
return;
|
||||
|
||||
for (int listIdx = 0; listIdx < entry->mLookups.mSize; listIdx++)
|
||||
{
|
||||
bool passesProtection = true;
|
||||
auto& entryList = entry->mLookups[listIdx];
|
||||
for (int entryIdx = 0; entryIdx < entryList.mSize; entryIdx++)
|
||||
{
|
||||
auto& entry = entryList[entryIdx];
|
||||
if (!mModule->CheckProtection(protectionCheckFlags, entry.mTypeInstance, entry.GetDeclaringType(mModule)->mProject,
|
||||
(entryIdx < entryList.mSize - 1) ? entry.GetUsingProtection() : entry.GetProtection(), curTypeInst))
|
||||
{
|
||||
passesProtection = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!passesProtection)
|
||||
continue;
|
||||
|
||||
auto& entry = entryList.back();
|
||||
BF_ASSERT(entry.mKind == BfUsingFieldData::MemberRef::Kind_Method);
|
||||
auto methodDef = entry.mTypeInstance->mTypeDef->mMethods[entry.mIdx];
|
||||
CheckMethod(curTypeInst, entry.mTypeInstance, methodDef, isFailurePass);
|
||||
if ((mBestMethodDef != methodDef) && (mBackupMethodDef != methodDef))
|
||||
{
|
||||
bool foundAmbiguous = false;
|
||||
for (int checkIdx = 0; checkIdx < mAmbiguousEntries.mSize; checkIdx++)
|
||||
{
|
||||
if (mAmbiguousEntries[checkIdx].mMethodInstance->mMethodDef == methodDef)
|
||||
{
|
||||
mAmbiguousEntries.RemoveAt(checkIdx);
|
||||
foundAmbiguous = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundAmbiguous)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mUsingLists->mSize == 0)
|
||||
{
|
||||
mUsingLists->Add(&entryList);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (entryList.mSize < (*mUsingLists)[0]->mSize)
|
||||
{
|
||||
// New is shorter
|
||||
mUsingLists->Clear();
|
||||
mUsingLists->Add(&entryList);
|
||||
}
|
||||
else if (entryList.mSize > (*mUsingLists)[0]->mSize)
|
||||
{
|
||||
// Ignore longer
|
||||
}
|
||||
else
|
||||
{
|
||||
mUsingLists->Add(&entryList);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if ((curTypeInst->mTypeInfoEx != NULL) && (curTypeInst->mTypeInfoEx->mUsingFieldData != NULL))
|
||||
_CheckUsingData(curTypeInst->mTypeInfoEx->mUsingFieldData);
|
||||
|
||||
if (mBestMethodDef != NULL)
|
||||
break;
|
||||
}
|
||||
|
||||
auto baseType = curTypeInst->mBaseType;
|
||||
if (baseType == NULL)
|
||||
{
|
||||
|
@ -2867,7 +2952,7 @@ bool BfMethodMatcher::CheckType(BfTypeInstance* typeInstance, BfTypedValue targe
|
|||
if (mAutoFlushAmbiguityErrors)
|
||||
FlushAmbiguityError();
|
||||
|
||||
return mBestMethodDef != prevBesstMethodDef;
|
||||
return mBestMethodDef != prevBestMethodDef;
|
||||
}
|
||||
|
||||
void BfMethodMatcher::TryDevirtualizeCall(BfTypedValue target, BfTypedValue* origTarget, BfTypedValue* staticResult)
|
||||
|
@ -4879,7 +4964,7 @@ BfTypedValue BfExprEvaluator::LoadField(BfAstNode* targetSrc, BfTypedValue targe
|
|||
}
|
||||
|
||||
auto resolvePassData = mModule->mCompiler->mResolvePassData;
|
||||
if ((resolvePassData != NULL) && (resolvePassData->mGetSymbolReferenceKind == BfGetSymbolReferenceKind_Field))
|
||||
if ((resolvePassData != NULL) && (resolvePassData->mGetSymbolReferenceKind == BfGetSymbolReferenceKind_Field) && ((flags & BfLookupFieldFlag_IsAnonymous) == 0))
|
||||
{
|
||||
resolvePassData->HandleFieldReference(targetSrc, typeInstance->mTypeDef, fieldDef);
|
||||
}
|
||||
|
@ -5620,187 +5705,140 @@ BfTypedValue BfExprEvaluator::LookupField(BfAstNode* targetSrc, BfTypedValue tar
|
|||
return LoadProperty(targetSrc, target, curCheckType, matchedProp, flags, checkedKind, isInlined);
|
||||
}
|
||||
|
||||
if ((curCheckType->mTypeDef->mHasUsingFields) && ((flags & BfLookupFieldFlag_BindOnly) == 0))
|
||||
if ((curCheckType->mTypeDef->mHasUsingFields) &&
|
||||
((curCheckType->mTypeInfoEx == NULL) || (curCheckType->mTypeInfoEx->mUsingFieldData == NULL)))
|
||||
mModule->PopulateUsingFieldData(curCheckType);
|
||||
|
||||
///
|
||||
{
|
||||
auto usingFieldData = curCheckType->mTypeDef->mUsingFieldData;
|
||||
|
||||
BfUsingFieldData::Entry* usingEntry = NULL;
|
||||
if (usingFieldData->mEntries.TryAdd(findName, NULL, &usingEntry))
|
||||
Array<SizedArray<BfUsingFieldData::MemberRef, 1>*> foundLists;
|
||||
|
||||
auto _CheckUsingData = [&](BfUsingFieldData* usingData)
|
||||
{
|
||||
HashSet<BfTypeInstance*> checkedTypeSet;
|
||||
BfUsingFieldData::FieldRef firstFoundField;
|
||||
BfUsingFieldData::Entry* entry = NULL;
|
||||
if (!usingData->mEntries.TryGetValue(findName, &entry))
|
||||
return;
|
||||
|
||||
std::function<bool(BfTypeInstance*)> _CheckTypeDef = [&](BfTypeInstance* usingType)
|
||||
for (int listIdx = 0; listIdx < entry->mLookups.mSize; listIdx++)
|
||||
{
|
||||
if (!checkedTypeSet.Add(usingType))
|
||||
return false;
|
||||
|
||||
BfFieldDef* matchedField = NULL;
|
||||
BfTypeInstance* matchedTypeInst = NULL;
|
||||
|
||||
if (curCheckType != usingType)
|
||||
bool passesProtection = true;
|
||||
auto& entryList = entry->mLookups[listIdx];
|
||||
for (int entryIdx = 0; entryIdx < entryList.mSize; entryIdx++)
|
||||
{
|
||||
auto curUsingType = usingType;
|
||||
while (curUsingType != NULL)
|
||||
auto& entry = entryList[entryIdx];
|
||||
if (!mModule->CheckProtection(protectionCheckFlags, entry.mTypeInstance, entry.GetDeclaringType(mModule)->mProject,
|
||||
(entryIdx < entryList.mSize - 1) ? entry.GetUsingProtection() : entry.GetProtection(), curCheckType))
|
||||
{
|
||||
curUsingType->mTypeDef->PopulateMemberSets();
|
||||
|
||||
BfFieldDef* nextField = NULL;
|
||||
BfMemberSetEntry* entry;
|
||||
if (curUsingType->mTypeDef->mFieldSet.TryGetWith(findName, &entry))
|
||||
nextField = (BfFieldDef*)entry->mMemberDef;
|
||||
|
||||
while (nextField != NULL)
|
||||
{
|
||||
auto field = nextField;
|
||||
nextField = nextField->mNextWithSameName;
|
||||
|
||||
if (!mModule->CheckProtection(protectionCheckFlags, curUsingType, field->mDeclaringType->mProject, field->mProtection, usingType))
|
||||
continue;
|
||||
|
||||
matchedTypeInst = curUsingType;
|
||||
matchedField = field;
|
||||
break;
|
||||
}
|
||||
|
||||
if (matchedField == NULL)
|
||||
{
|
||||
BfPropertyDef* nextProp = NULL;
|
||||
if (curUsingType->mTypeDef->mPropertySet.TryGetWith(findName, &entry))
|
||||
nextProp = (BfPropertyDef*)entry->mMemberDef;
|
||||
while (nextProp != NULL)
|
||||
{
|
||||
auto propDef = nextProp;
|
||||
nextProp = nextProp->mNextWithSameName;
|
||||
|
||||
if (!mModule->CheckProtection(protectionCheckFlags, curUsingType, propDef->mDeclaringType->mProject, propDef->mProtection, usingType))
|
||||
continue;
|
||||
|
||||
matchedTypeInst = curUsingType;
|
||||
matchedField = propDef;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (matchedField != NULL)
|
||||
{
|
||||
if (firstFoundField.mTypeInstance == NULL)
|
||||
{
|
||||
firstFoundField = BfUsingFieldData::FieldRef(curUsingType, matchedField);
|
||||
}
|
||||
else
|
||||
{
|
||||
usingEntry->mConflicts.Add(firstFoundField);
|
||||
usingEntry->mConflicts.Add(BfUsingFieldData::FieldRef(curUsingType, matchedField));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
curUsingType = curUsingType->mBaseType;
|
||||
}
|
||||
}
|
||||
|
||||
auto curUsingType = usingType;
|
||||
while (curUsingType != NULL)
|
||||
{
|
||||
if (curUsingType->mTypeDef->mUsingFieldData != NULL)
|
||||
{
|
||||
for (auto fieldDef : curUsingType->mTypeDef->mUsingFieldData->mUsingFields)
|
||||
{
|
||||
if (!mModule->CheckProtection(protectionCheckFlags, curUsingType, fieldDef->mDeclaringType->mProject, fieldDef->mUsingProtection, usingType))
|
||||
continue;
|
||||
|
||||
if (fieldDef->mIsProperty)
|
||||
{
|
||||
auto propDef = (BfPropertyDef*)fieldDef;
|
||||
for (auto methodDef : propDef->mMethods)
|
||||
{
|
||||
if (methodDef->mMethodType == BfMethodType_PropertyGetter)
|
||||
{
|
||||
auto methodInstance = mModule->GetRawMethodInstance(curUsingType, methodDef);
|
||||
if (methodInstance == NULL)
|
||||
continue;
|
||||
BfType* returnType = methodInstance->mReturnType;
|
||||
if ((returnType->IsRef()) || (returnType->IsPointer()))
|
||||
returnType = returnType->GetUnderlyingType();
|
||||
auto fieldTypeInst = returnType->ToTypeInstance();
|
||||
if ((fieldTypeInst != NULL) && (_CheckTypeDef(fieldTypeInst)))
|
||||
usingEntry->mLookup.Insert(0, BfUsingFieldData::FieldRef(curUsingType, fieldDef));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (curUsingType->mFieldInstances.IsEmpty())
|
||||
mModule->PopulateType(curCheckType, BfPopulateType_Data);
|
||||
BF_ASSERT(fieldDef->mIdx < (int)curUsingType->mFieldInstances.size());
|
||||
auto fieldInstance = &curUsingType->mFieldInstances[fieldDef->mIdx];
|
||||
if (!fieldInstance->mFieldIncluded)
|
||||
continue;
|
||||
auto fieldType = fieldInstance->mResolvedType;
|
||||
if (fieldType->IsPointer())
|
||||
fieldType = fieldType->GetUnderlyingType();
|
||||
auto fieldTypeInst = fieldType->ToTypeInstance();
|
||||
if ((fieldTypeInst != NULL) && (_CheckTypeDef(fieldTypeInst)))
|
||||
usingEntry->mLookup.Insert(0, BfUsingFieldData::FieldRef(curUsingType, fieldDef));
|
||||
}
|
||||
}
|
||||
passesProtection = false;
|
||||
break;
|
||||
}
|
||||
curUsingType = curUsingType->mBaseType;
|
||||
}
|
||||
|
||||
if ((matchedField != NULL) && (usingEntry->mLookup.IsEmpty()))
|
||||
if (!passesProtection)
|
||||
continue;
|
||||
|
||||
if (foundLists.mSize == 0)
|
||||
{
|
||||
usingEntry->mLookup.Add(BfUsingFieldData::FieldRef(matchedTypeInst, matchedField));
|
||||
return true;
|
||||
foundLists.Add(&entryList);
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
_CheckTypeDef(curCheckType);
|
||||
}
|
||||
|
||||
if ((!usingEntry->mConflicts.IsEmpty()) && (mModule->PreFail()))
|
||||
{
|
||||
BfError* error = mModule->Fail("Ambiguous 'using' field reference", targetSrc);
|
||||
if (error != NULL)
|
||||
{
|
||||
for (auto& conflict : usingEntry->mConflicts)
|
||||
else
|
||||
{
|
||||
mModule->mCompiler->mPassInstance->MoreInfo(StrFormat("'%s.%s' is a candidate", mModule->TypeToString(conflict.mTypeInstance).c_str(), conflict.mFieldDef->mName.c_str()), conflict.mFieldDef->GetRefNode());
|
||||
if (entryList.mSize < foundLists[0]->mSize)
|
||||
{
|
||||
// New is shorter
|
||||
foundLists.Clear();
|
||||
foundLists.Add(&entryList);
|
||||
}
|
||||
else if (entryList.mSize > foundLists[0]->mSize)
|
||||
{
|
||||
// Ignore longer
|
||||
}
|
||||
else
|
||||
{
|
||||
foundLists.Add(&entryList);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (!usingEntry->mLookup.IsEmpty())
|
||||
if ((curCheckType->mTypeInfoEx != NULL) && (curCheckType->mTypeInfoEx->mUsingFieldData != NULL))
|
||||
_CheckUsingData(curCheckType->mTypeInfoEx->mUsingFieldData);
|
||||
|
||||
if (!foundLists.IsEmpty())
|
||||
{
|
||||
auto initialFieldDef = usingEntry->mLookup[0].mFieldDef;
|
||||
if ((initialFieldDef->mIsStatic == target.IsStatic()) &&
|
||||
(mModule->CheckProtection(protectionCheckFlags, curCheckType, initialFieldDef->mDeclaringType->mProject, initialFieldDef->mUsingProtection, startCheckType)))
|
||||
{
|
||||
BfTypeInstance* curTypeInst = curCheckType;
|
||||
BfTypedValue curResult = target;
|
||||
for (int i = 0; i < usingEntry->mLookup.mSize; i++)
|
||||
{
|
||||
auto& fieldRef = usingEntry->mLookup[i];
|
||||
if (mPropDef != NULL)
|
||||
{
|
||||
SetAndRestoreValue<BfTypedValue> prevResult(mResult, BfTypedValue());
|
||||
mPropGetMethodFlags = (BfGetMethodInstanceFlags)(mPropGetMethodFlags | BfGetMethodInstanceFlag_Friend);
|
||||
curResult = GetResult();
|
||||
if (!curResult)
|
||||
return curResult;
|
||||
}
|
||||
auto foundList = foundLists[0];
|
||||
|
||||
auto useFlags = flags;
|
||||
if (i < usingEntry->mLookup.mSize - 1)
|
||||
useFlags = (BfLookupFieldFlags)(flags | BfLookupFieldFlag_IsAnonymous);
|
||||
curResult = LoadField(targetSrc, curResult, fieldRef.mTypeInstance, fieldRef.mFieldDef, useFlags);
|
||||
if ((!curResult) && (mPropDef == NULL))
|
||||
if (foundLists.mSize > 1)
|
||||
{
|
||||
BfError* error = mModule->Fail("Ambiguous 'using' field reference", targetSrc);
|
||||
if (error != NULL)
|
||||
{
|
||||
for (auto checkList : foundLists)
|
||||
{
|
||||
String errorStr = "'";
|
||||
for (int entryIdx = 0; entryIdx < checkList->mSize; entryIdx++)
|
||||
{
|
||||
if (entryIdx == 0)
|
||||
errorStr += (*checkList)[entryIdx].GetFullName(mModule);
|
||||
else
|
||||
{
|
||||
errorStr += ".";
|
||||
errorStr += (*checkList)[entryIdx].GetName(mModule);
|
||||
}
|
||||
}
|
||||
errorStr += "' is a candidate";
|
||||
mModule->mCompiler->mPassInstance->MoreInfo(errorStr, (*checkList)[0].GetRefNode(mModule));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BfTypedValue curResult = target;
|
||||
for (int entryIdx = 0; entryIdx < foundList->mSize; entryIdx++)
|
||||
{
|
||||
if ((entryIdx == 0) && (foundList->back().IsStatic()))
|
||||
entryIdx = (int)foundList->mSize - 1;
|
||||
|
||||
auto& entry = (*foundList)[entryIdx];
|
||||
if (mPropDef != NULL)
|
||||
{
|
||||
SetAndRestoreValue<BfTypedValue> prevResult(mResult, BfTypedValue());
|
||||
mPropGetMethodFlags = (BfGetMethodInstanceFlags)(mPropGetMethodFlags | BfGetMethodInstanceFlag_Friend);
|
||||
curResult = GetResult();
|
||||
if (!curResult)
|
||||
return curResult;
|
||||
}
|
||||
return curResult;
|
||||
|
||||
auto useFlags = flags;
|
||||
if (entryIdx < foundList->mSize - 1)
|
||||
useFlags = (BfLookupFieldFlags)(flags | BfLookupFieldFlag_IsAnonymous);
|
||||
|
||||
if (entry.mKind == BfUsingFieldData::MemberRef::Kind_Field)
|
||||
{
|
||||
curResult = LoadField(targetSrc, curResult, entry.mTypeInstance, entry.mTypeInstance->mTypeDef->mFields[entry.mIdx], useFlags);
|
||||
}
|
||||
else if (entry.mKind == BfUsingFieldData::MemberRef::Kind_Property)
|
||||
{
|
||||
curResult = LoadProperty(targetSrc, curResult, entry.mTypeInstance, entry.mTypeInstance->mTypeDef->mProperties[entry.mIdx], useFlags, BfCheckedKind_NotSet, false);
|
||||
}
|
||||
else if (entry.mKind == BfUsingFieldData::MemberRef::Kind_Local)
|
||||
{
|
||||
auto localDef = mModule->mCurMethodState->mLocals[entry.mIdx];
|
||||
curResult = LoadLocal(localDef);
|
||||
}
|
||||
if ((!curResult) && (mPropDef == NULL))
|
||||
return curResult;
|
||||
|
||||
if (entryIdx == foundList->mSize - 1)
|
||||
{
|
||||
auto autoComplete = GetAutoComplete();
|
||||
if ((autoComplete != NULL) && (autoComplete->IsAutocompleteNode(targetSrc)))
|
||||
autoComplete->SetDefinitionLocation(entry.GetRefNode(mModule));
|
||||
|
||||
if ((autoComplete != NULL) && (autoComplete->CheckFixit(targetSrc)))
|
||||
autoComplete->FixitAddFullyQualify(targetSrc, findName, *foundList);
|
||||
}
|
||||
}
|
||||
|
||||
return curResult;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9412,7 +9450,9 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
|
|||
|
||||
BfTypeInstance* curTypeInst = targetTypeInst;
|
||||
|
||||
Array<SizedArray<BfUsingFieldData::MemberRef, 1>*> methodUsingLists;
|
||||
BfMethodMatcher methodMatcher(targetSrc, mModule, methodName, argValues.mResolvedArgs, methodGenericArgs);
|
||||
methodMatcher.mUsingLists = &methodUsingLists;
|
||||
methodMatcher.mOrigTarget = origTarget;
|
||||
methodMatcher.mTarget = target;
|
||||
methodMatcher.mCheckedKind = checkedKind;
|
||||
|
@ -9581,7 +9621,7 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
|
|||
if (lookupTypeInst != NULL)
|
||||
methodMatcher.CheckType(lookupTypeInst, target, true);
|
||||
}
|
||||
|
||||
|
||||
BfTypedValue staticResult;
|
||||
//
|
||||
{
|
||||
|
@ -9605,6 +9645,96 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
|
|||
target = mModule->GetThis();
|
||||
}
|
||||
|
||||
if (!methodUsingLists.IsEmpty())
|
||||
{
|
||||
auto foundList = methodUsingLists[0];
|
||||
|
||||
if (methodUsingLists.mSize > 1)
|
||||
{
|
||||
BfError* error = mModule->Fail("Ambiguous 'using' method reference", targetSrc);
|
||||
if (error != NULL)
|
||||
{
|
||||
for (auto checkList : methodUsingLists)
|
||||
{
|
||||
String errorStr = "'";
|
||||
for (int entryIdx = 0; entryIdx < checkList->mSize; entryIdx++)
|
||||
{
|
||||
if (entryIdx == 0)
|
||||
errorStr += (*checkList)[entryIdx].GetFullName(mModule);
|
||||
else
|
||||
{
|
||||
errorStr += ".";
|
||||
errorStr += (*checkList)[entryIdx].GetName(mModule);
|
||||
}
|
||||
}
|
||||
errorStr += "' is a candidate";
|
||||
mModule->mCompiler->mPassInstance->MoreInfo(errorStr, (*checkList)[0].GetRefNode(mModule));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BfTypedValue curResult = target;
|
||||
for (int entryIdx = 0; entryIdx < foundList->mSize; entryIdx++)
|
||||
{
|
||||
if ((entryIdx == 0) && (foundList->back().IsStatic()))
|
||||
entryIdx = (int)foundList->mSize - 1;
|
||||
|
||||
auto& entry = (*foundList)[entryIdx];
|
||||
if (mPropDef != NULL)
|
||||
{
|
||||
SetAndRestoreValue<BfTypedValue> prevResult(mResult, BfTypedValue());
|
||||
mPropGetMethodFlags = (BfGetMethodInstanceFlags)(mPropGetMethodFlags | BfGetMethodInstanceFlag_Friend);
|
||||
curResult = GetResult();
|
||||
if (!curResult)
|
||||
break;
|
||||
}
|
||||
|
||||
auto useFlags = BfLookupFieldFlag_None;
|
||||
if (entryIdx < foundList->mSize - 1)
|
||||
useFlags = (BfLookupFieldFlags)(useFlags | BfLookupFieldFlag_IsAnonymous);
|
||||
|
||||
if (entry.mKind == BfUsingFieldData::MemberRef::Kind_Field)
|
||||
{
|
||||
curResult = LoadField(targetSrc, curResult, entry.mTypeInstance, entry.mTypeInstance->mTypeDef->mFields[entry.mIdx], useFlags);
|
||||
}
|
||||
else if (entry.mKind == BfUsingFieldData::MemberRef::Kind_Property)
|
||||
{
|
||||
curResult = LoadProperty(targetSrc, curResult, entry.mTypeInstance, entry.mTypeInstance->mTypeDef->mProperties[entry.mIdx], useFlags, BfCheckedKind_NotSet, false);
|
||||
}
|
||||
else if (entry.mKind == BfUsingFieldData::MemberRef::Kind_Local)
|
||||
{
|
||||
auto localDef = mModule->mCurMethodState->mLocals[entry.mIdx];
|
||||
curResult = LoadLocal(localDef);
|
||||
}
|
||||
else if (entry.mKind == BfUsingFieldData::MemberRef::Kind_Local)
|
||||
{
|
||||
auto checkMethodDef = entry.mTypeInstance->mTypeDef->mMethods[entry.mIdx];
|
||||
BF_ASSERT(methodDef == checkMethodDef);
|
||||
break;
|
||||
}
|
||||
|
||||
if ((!curResult) && (mPropDef == NULL))
|
||||
break;
|
||||
|
||||
if (entryIdx == foundList->mSize - 1)
|
||||
{
|
||||
auto autoComplete = GetAutoComplete();
|
||||
if ((autoComplete != NULL) && (autoComplete->IsAutocompleteNode(targetSrc)))
|
||||
autoComplete->SetDefinitionLocation(entry.GetRefNode(mModule));
|
||||
|
||||
if ((autoComplete != NULL) && (autoComplete->CheckFixit(targetSrc)))
|
||||
autoComplete->FixitAddFullyQualify(targetSrc, methodName, *foundList);
|
||||
}
|
||||
}
|
||||
|
||||
if (methodDef->mIsStatic)
|
||||
target = BfTypedValue(curTypeInst);
|
||||
else if (curResult)
|
||||
target = curResult;
|
||||
else if ((!methodDef->mIsStatic) && (curTypeInst != NULL))
|
||||
target = mModule->GetDefaultTypedValue(curTypeInst);
|
||||
}
|
||||
|
||||
// If we call "GetType" on a value type, statically determine the type rather than boxing and then dispatching
|
||||
if ((methodDef) && (target) && (curTypeInst == mModule->mContext->mBfObjectType) &&
|
||||
(methodDef->mName == "GetType") && (target.mType->IsValueType()) && (argValues.mArguments->IsEmpty()))
|
||||
|
@ -10034,6 +10164,11 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
|
|||
}
|
||||
}
|
||||
|
||||
if (methodDef == NULL)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// This will flush out any new ambiguity errors from extension methods
|
||||
methodMatcher.FlushAmbiguityError();
|
||||
|
||||
|
@ -10041,8 +10176,8 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
|
|||
{
|
||||
FinishDeferredEvals(argValues);
|
||||
auto compiler = mModule->mCompiler;
|
||||
if ((compiler->IsAutocomplete()) && (compiler->mResolvePassData->mAutoComplete->CheckFixit(targetSrc)))
|
||||
{
|
||||
if ((autoComplete != NULL) && (autoComplete->CheckFixit(targetSrc)))
|
||||
{
|
||||
mModule->CheckTypeRefFixit(targetSrc);
|
||||
bool wantStatic = !target.mValue;
|
||||
if ((targetType == NULL) && (allowImplicitThis))
|
||||
|
@ -19934,13 +20069,16 @@ void BfExprEvaluator::PerformAssignment(BfAssignmentExpression* assignExpr, bool
|
|||
|
||||
BfAutoComplete* autoComplete = GetAutoComplete();
|
||||
bool deferredFixits = false;
|
||||
if ((autoComplete != NULL) && (autoComplete->mResolveType == BfResolveType_GetFixits))
|
||||
|
||||
//TODO: Why was this needed? This breaks fixits on target nodes (ie: 'using' field fixit for 'fully quality')
|
||||
/*if ((autoComplete != NULL) && (autoComplete->mResolveType == BfResolveType_GetFixits))
|
||||
{
|
||||
SetAndRestoreValue<bool> ignoreFixits(autoComplete->mIgnoreFixits, true);
|
||||
VisitChild(targetNode);
|
||||
deferredFixits = true;
|
||||
}
|
||||
else if (!evaluatedLeft)
|
||||
else*/
|
||||
if (!evaluatedLeft)
|
||||
{
|
||||
if (auto memberReferenceExpr = BfNodeDynCast<BfMemberReferenceExpression>(targetNode))
|
||||
{
|
||||
|
|
|
@ -214,6 +214,7 @@ public:
|
|||
BfType* mCheckReturnType;
|
||||
BfMethodType mMethodType;
|
||||
BfCheckedKind mCheckedKind;
|
||||
Array<SizedArray<BfUsingFieldData::MemberRef, 1>*>* mUsingLists;
|
||||
bool mHasArgNames;
|
||||
bool mHadExplicitGenericArguments;
|
||||
bool mHadOpenGenericArguments;
|
||||
|
|
|
@ -291,20 +291,27 @@ void BfMethodState::LocalDefined(BfLocalVariable* localVar, int fieldIdx, BfLoca
|
|||
{
|
||||
if (fieldIdx >= 0)
|
||||
{
|
||||
localVar->mUnassignedFieldFlags &= ~((int64)1 << fieldIdx);
|
||||
localVar->mUnassignedFieldFlags &= ~((int64)1 << fieldIdx);
|
||||
|
||||
if (localVar->mResolvedType->IsUnion())
|
||||
{
|
||||
// We need more 'smarts' to determine assignment of unions
|
||||
localVar->mUnassignedFieldFlags = 0;
|
||||
}
|
||||
|
||||
if (localVar->mUnassignedFieldFlags == 0)
|
||||
{
|
||||
if (localVar->mAssignedKind == BfLocalVarAssignKind_None)
|
||||
localVar->mAssignedKind = assignKind;
|
||||
localVar->mAssignedKind = assignKind;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
localVar->mAssignedKind = assignKind;
|
||||
localVar->mAssignedKind = assignKind;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
BF_ASSERT(deferredLocalAssignData->mVarIdBarrier != -1);
|
||||
|
||||
BfAssignedLocal defineVal = {localVar, fieldIdx, assignKind};
|
||||
|
|
|
@ -1838,6 +1838,7 @@ public:
|
|||
void ExecuteCEOnCompile(CeEmitContext* ceEmitContext, BfTypeInstance* typeInst, BfCEOnCompileKind onCompileKind, bool underlyingTypeDeferred);
|
||||
void DoCEEmit(BfTypeInstance* typeInstance, bool& hadNewMembers, bool underlyingTypeDeferred);
|
||||
void DoCEEmit(BfMethodInstance* methodInstance);
|
||||
void PopulateUsingFieldData(BfTypeInstance* typeInstance);
|
||||
void DoPopulateType_TypeAlias(BfTypeAliasType* typeAlias);
|
||||
void DoPopulateType_InitSearches(BfTypeInstance* typeInstance);
|
||||
void DoPopulateType_SetGenericDependencies(BfTypeInstance* genericTypeInstance);
|
||||
|
|
|
@ -3056,6 +3056,151 @@ void BfModule::DoCEEmit(BfMethodInstance* methodInstance)
|
|||
}
|
||||
}
|
||||
|
||||
void BfModule::PopulateUsingFieldData(BfTypeInstance* typeInstance)
|
||||
{
|
||||
if (typeInstance->mTypeInfoEx == NULL)
|
||||
typeInstance->mTypeInfoEx = new BfTypeInfoEx();
|
||||
|
||||
BF_ASSERT(typeInstance->mTypeInfoEx->mUsingFieldData == NULL);
|
||||
|
||||
BfUsingFieldData* usingFieldData = new BfUsingFieldData();
|
||||
typeInstance->mTypeInfoEx->mUsingFieldData = usingFieldData;
|
||||
|
||||
HashSet<BfTypeInstance*> checkedTypeSet;
|
||||
Array<BfUsingFieldData::MemberRef> memberRefs;
|
||||
std::function<void(BfTypeInstance*, bool)> _CheckType = [&](BfTypeInstance* usingType, bool staticOnly)
|
||||
{
|
||||
if (!checkedTypeSet.Add(usingType))
|
||||
return;
|
||||
defer(
|
||||
{
|
||||
checkedTypeSet.Remove(usingType);
|
||||
});
|
||||
|
||||
for (auto fieldDef : usingType->mTypeDef->mFields)
|
||||
{
|
||||
if ((staticOnly) && (!fieldDef->mIsStatic))
|
||||
continue;
|
||||
|
||||
memberRefs.Add(BfUsingFieldData::MemberRef(usingType, fieldDef));
|
||||
defer(
|
||||
{
|
||||
memberRefs.pop_back();
|
||||
});
|
||||
|
||||
if (memberRefs.Count() > 1)
|
||||
{
|
||||
BfUsingFieldData::Entry* entry = NULL;
|
||||
usingFieldData->mEntries.TryAdd(fieldDef->mName, NULL, &entry);
|
||||
SizedArray<BfUsingFieldData::MemberRef, 1> lookup;
|
||||
for (auto entry : memberRefs)
|
||||
lookup.Add(entry);
|
||||
entry->mLookups.Add(lookup);
|
||||
}
|
||||
|
||||
if (fieldDef->mUsingProtection == BfProtection_Hidden)
|
||||
continue;
|
||||
|
||||
if (usingType->mDefineState < BfTypeDefineState_Defined)
|
||||
{
|
||||
// We need to populate this type now
|
||||
PopulateType(usingType);
|
||||
}
|
||||
|
||||
auto fieldInstance = &usingType->mFieldInstances[fieldDef->mIdx];
|
||||
auto fieldTypeInst = fieldInstance->mResolvedType->ToTypeInstance();
|
||||
if (fieldTypeInst != NULL)
|
||||
_CheckType(fieldTypeInst, fieldDef->mIsStatic);
|
||||
}
|
||||
|
||||
for (auto propDef : usingType->mTypeDef->mProperties)
|
||||
{
|
||||
if ((staticOnly) && (!propDef->mIsStatic))
|
||||
continue;
|
||||
|
||||
memberRefs.Add(BfUsingFieldData::MemberRef(usingType, propDef));
|
||||
defer(
|
||||
{
|
||||
memberRefs.pop_back();
|
||||
});
|
||||
|
||||
if (memberRefs.Count() > 1)
|
||||
{
|
||||
BfUsingFieldData::Entry* entry = NULL;
|
||||
usingFieldData->mEntries.TryAdd(propDef->mName, NULL, &entry);
|
||||
SizedArray<BfUsingFieldData::MemberRef, 1> lookup;
|
||||
for (auto entry : memberRefs)
|
||||
lookup.Add(entry);
|
||||
entry->mLookups.Add(lookup);
|
||||
}
|
||||
|
||||
if (propDef->mUsingProtection == BfProtection_Hidden)
|
||||
continue;
|
||||
|
||||
if (usingType->mDefineState < BfTypeDefineState_Defined)
|
||||
{
|
||||
// We need to populate this type now
|
||||
PopulateType(usingType);
|
||||
}
|
||||
|
||||
BfType* propType = NULL;
|
||||
for (auto methodDef : propDef->mMethods)
|
||||
{
|
||||
auto methodInstance = GetRawMethodInstance(usingType, methodDef);
|
||||
if (methodInstance == NULL)
|
||||
continue;
|
||||
if (methodDef->mMethodType == BfMethodType_PropertyGetter)
|
||||
{
|
||||
propType = methodInstance->mReturnType;
|
||||
break;
|
||||
}
|
||||
if (methodDef->mMethodType == BfMethodType_PropertySetter)
|
||||
{
|
||||
if (methodInstance->GetParamCount() > 0)
|
||||
{
|
||||
propType = methodInstance->GetParamType(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((propType != NULL) && (propType->IsTypeInstance()))
|
||||
_CheckType(propType->ToTypeInstance(), propDef->mIsStatic);
|
||||
}
|
||||
|
||||
for (auto methodDef : usingType->mTypeDef->mMethods)
|
||||
{
|
||||
if ((staticOnly) && (!methodDef->mIsStatic))
|
||||
continue;
|
||||
|
||||
//TODO: Support mixins as well
|
||||
if (methodDef->mMethodType != BfMethodType_Normal)
|
||||
continue;
|
||||
|
||||
// No auto methods
|
||||
if (methodDef->mMethodDeclaration == NULL)
|
||||
continue;
|
||||
|
||||
memberRefs.Add(BfUsingFieldData::MemberRef(usingType, methodDef));
|
||||
defer(
|
||||
{
|
||||
memberRefs.pop_back();
|
||||
});
|
||||
|
||||
if (memberRefs.Count() > 1)
|
||||
{
|
||||
BfUsingFieldData::Entry* entry = NULL;
|
||||
usingFieldData->mMethods.TryAdd(methodDef->mName, NULL, &entry);
|
||||
SizedArray<BfUsingFieldData::MemberRef, 1> lookup;
|
||||
for (auto entry : memberRefs)
|
||||
lookup.Add(entry);
|
||||
entry->mLookups.Add(lookup);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
_CheckType(typeInstance, false);
|
||||
}
|
||||
|
||||
void BfModule::DoPopulateType_SetGenericDependencies(BfTypeInstance* genericTypeInstance)
|
||||
{
|
||||
SetAndRestoreValue<BfTypeInstance*> prevTypeInstance(mCurTypeInstance, genericTypeInstance);
|
||||
|
|
|
@ -6570,23 +6570,23 @@ BfAstNode* BfReducer::ReadTypeMember(BfTokenNode* tokenNode, bool declStarted, i
|
|||
handled = true;
|
||||
}
|
||||
|
||||
// if (token == BfToken_Using)
|
||||
// {
|
||||
// if ((fieldDecl->mConstSpecifier != NULL) && (fieldDecl->mConstSpecifier->mToken == BfToken_Const))
|
||||
// {
|
||||
// Fail("Const cannot be used with 'using' specified", tokenNode);
|
||||
// }
|
||||
// else if (fieldDecl->mConstSpecifier != NULL)
|
||||
// {
|
||||
// Fail("Using already specified", tokenNode);
|
||||
// }
|
||||
//
|
||||
// auto usingSpecifier = mAlloc->Alloc<BfUsingSpecifierNode>();
|
||||
// ReplaceNode(tokenNode, usingSpecifier);
|
||||
// MEMBER_SET(usingSpecifier, mUsingToken, tokenNode);
|
||||
// MEMBER_SET(fieldDecl, mConstSpecifier, usingSpecifier);
|
||||
// handled = true;
|
||||
// }
|
||||
if (token == BfToken_Using)
|
||||
{
|
||||
if ((fieldDecl->mConstSpecifier != NULL) && (fieldDecl->mConstSpecifier->mToken == BfToken_Const))
|
||||
{
|
||||
Fail("Const cannot be used with 'using' specified", tokenNode);
|
||||
}
|
||||
else if (fieldDecl->mConstSpecifier != NULL)
|
||||
{
|
||||
Fail("Using already specified", tokenNode);
|
||||
}
|
||||
|
||||
auto usingSpecifier = mAlloc->Alloc<BfUsingSpecifierNode>();
|
||||
ReplaceNode(tokenNode, usingSpecifier);
|
||||
MEMBER_SET(usingSpecifier, mUsingToken, tokenNode);
|
||||
MEMBER_SET(fieldDecl, mConstSpecifier, usingSpecifier);
|
||||
handled = true;
|
||||
}
|
||||
|
||||
if (token == BfToken_ReadOnly)
|
||||
{
|
||||
|
|
|
@ -64,6 +64,125 @@ bool BfTypedValue::CanModify() const
|
|||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
BfProtection BfUsingFieldData::MemberRef::GetProtection() const
|
||||
{
|
||||
switch (mKind)
|
||||
{
|
||||
case Kind_Field:
|
||||
return mTypeInstance->mTypeDef->mFields[mIdx]->mProtection;
|
||||
case Kind_Property:
|
||||
return mTypeInstance->mTypeDef->mProperties[mIdx]->mProtection;
|
||||
case Kind_Method:
|
||||
return mTypeInstance->mTypeDef->mMethods[mIdx]->mProtection;
|
||||
}
|
||||
return BfProtection_Public;
|
||||
}
|
||||
|
||||
BfProtection BfUsingFieldData::MemberRef::GetUsingProtection() const
|
||||
{
|
||||
switch (mKind)
|
||||
{
|
||||
case Kind_Field:
|
||||
return mTypeInstance->mTypeDef->mFields[mIdx]->mUsingProtection;
|
||||
case Kind_Property:
|
||||
return mTypeInstance->mTypeDef->mProperties[mIdx]->mUsingProtection;
|
||||
case Kind_Method:
|
||||
return mTypeInstance->mTypeDef->mMethods[mIdx]->mProtection;
|
||||
}
|
||||
return BfProtection_Public;
|
||||
}
|
||||
|
||||
BfTypeDef* BfUsingFieldData::MemberRef::GetDeclaringType(BfModule* curModule) const
|
||||
{
|
||||
switch (mKind)
|
||||
{
|
||||
case Kind_Field:
|
||||
return mTypeInstance->mTypeDef->mFields[mIdx]->mDeclaringType;
|
||||
case Kind_Property:
|
||||
return mTypeInstance->mTypeDef->mProperties[mIdx]->mDeclaringType;
|
||||
case Kind_Method:
|
||||
return mTypeInstance->mTypeDef->mMethods[mIdx]->mDeclaringType;
|
||||
case Kind_Local:
|
||||
return curModule->GetActiveTypeDef();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
String BfUsingFieldData::MemberRef::GetFullName(BfModule* curModule) const
|
||||
{
|
||||
if (mKind == Kind_Local)
|
||||
return curModule->mCurMethodState->mLocals[mIdx]->mName;
|
||||
|
||||
String result = curModule->TypeToString(mTypeInstance);
|
||||
if (!result.IsEmpty())
|
||||
result += ".";
|
||||
|
||||
switch (mKind)
|
||||
{
|
||||
case Kind_Field:
|
||||
result += mTypeInstance->mTypeDef->mFields[mIdx]->mName;
|
||||
break;
|
||||
case Kind_Property:
|
||||
result += mTypeInstance->mTypeDef->mProperties[mIdx]->mName;
|
||||
break;
|
||||
case Kind_Method:
|
||||
result += mTypeInstance->mTypeDef->mMethods[mIdx]->mName;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
String BfUsingFieldData::MemberRef::GetName(BfModule* curModule) const
|
||||
{
|
||||
switch (mKind)
|
||||
{
|
||||
case Kind_Field:
|
||||
return mTypeInstance->mTypeDef->mFields[mIdx]->mName;
|
||||
case Kind_Property:
|
||||
return mTypeInstance->mTypeDef->mProperties[mIdx]->mName;
|
||||
case Kind_Method:
|
||||
{
|
||||
auto methodInstance = curModule->GetRawMethodInstance(mTypeInstance, mTypeInstance->mTypeDef->mMethods[mIdx]);
|
||||
return curModule->MethodToString(methodInstance, BfMethodNameFlag_OmitTypeName);
|
||||
}
|
||||
case Kind_Local:
|
||||
return curModule->mCurMethodState->mLocals[mIdx]->mName;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
BfAstNode* BfUsingFieldData::MemberRef::GetRefNode(BfModule* curModule) const
|
||||
{
|
||||
switch (mKind)
|
||||
{
|
||||
case Kind_Field:
|
||||
return mTypeInstance->mTypeDef->mFields[mIdx]->GetRefNode();
|
||||
case Kind_Property:
|
||||
return mTypeInstance->mTypeDef->mProperties[mIdx]->GetRefNode();
|
||||
case Kind_Method:
|
||||
return mTypeInstance->mTypeDef->mMethods[mIdx]->GetRefNode();
|
||||
case Kind_Local:
|
||||
return curModule->mCurMethodState->mLocals[mIdx]->mNameNode;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool BfUsingFieldData::MemberRef::IsStatic() const
|
||||
{
|
||||
switch (mKind)
|
||||
{
|
||||
case Kind_Field:
|
||||
return mTypeInstance->mTypeDef->mFields[mIdx]->mIsStatic;
|
||||
case Kind_Property:
|
||||
return mTypeInstance->mTypeDef->mProperties[mIdx]->mIsStatic;
|
||||
case Kind_Method:
|
||||
return mTypeInstance->mTypeDef->mMethods[mIdx]->mIsStatic;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool BfGenericParamInstance::IsEnum()
|
||||
{
|
||||
if ((mGenericParamFlags & BfGenericParamFlag_Enum) != 0)
|
||||
|
|
|
@ -1821,19 +1821,91 @@ public:
|
|||
Array<BfAtomComposite> mNamespaces;
|
||||
};
|
||||
|
||||
class BfUsingFieldData
|
||||
{
|
||||
public:
|
||||
struct MemberRef
|
||||
{
|
||||
enum Kind
|
||||
{
|
||||
Kind_None,
|
||||
Kind_Field,
|
||||
Kind_Property,
|
||||
Kind_Method,
|
||||
Kind_Local
|
||||
};
|
||||
|
||||
BfTypeInstance* mTypeInstance;
|
||||
Kind mKind;
|
||||
int mIdx;
|
||||
|
||||
MemberRef()
|
||||
{
|
||||
mTypeInstance = NULL;
|
||||
mKind = Kind_None;
|
||||
mIdx = -1;
|
||||
}
|
||||
|
||||
MemberRef(BfTypeInstance* typeInst, BfFieldDef* fieldDef)
|
||||
{
|
||||
mTypeInstance = typeInst;
|
||||
mKind = Kind_Field;
|
||||
mIdx = fieldDef->mIdx;
|
||||
}
|
||||
|
||||
MemberRef(BfTypeInstance* typeInst, BfMethodDef* methodDef)
|
||||
{
|
||||
mTypeInstance = typeInst;
|
||||
mKind = Kind_Method;
|
||||
mIdx = methodDef->mIdx;
|
||||
}
|
||||
|
||||
MemberRef(BfTypeInstance* typeInst, BfPropertyDef* propDef)
|
||||
{
|
||||
mTypeInstance = typeInst;
|
||||
mKind = Kind_Property;
|
||||
mIdx = propDef->mIdx;
|
||||
}
|
||||
|
||||
BfProtection GetProtection() const;
|
||||
BfProtection GetUsingProtection() const;
|
||||
BfTypeDef* GetDeclaringType(BfModule* curModule) const;
|
||||
String GetFullName(BfModule* curModule) const;
|
||||
String GetName(BfModule* curModule) const;
|
||||
BfAstNode* GetRefNode(BfModule* curModule) const;
|
||||
bool IsStatic() const;
|
||||
};
|
||||
|
||||
struct Entry
|
||||
{
|
||||
SizedArray<SizedArray<MemberRef, 1>, 1> mLookups;
|
||||
};
|
||||
|
||||
public:
|
||||
Dictionary<String, Entry> mEntries;
|
||||
Dictionary<String, Entry> mMethods;
|
||||
};
|
||||
|
||||
class BfTypeInfoEx
|
||||
{
|
||||
public:
|
||||
BfUsingFieldData* mUsingFieldData;
|
||||
BfType* mUnderlyingType;
|
||||
int64 mMinValue;
|
||||
int64 mMaxValue;
|
||||
|
||||
BfTypeInfoEx()
|
||||
{
|
||||
mUsingFieldData = NULL;
|
||||
mUnderlyingType = NULL;
|
||||
mMinValue = 0;
|
||||
mMaxValue = 0;
|
||||
}
|
||||
|
||||
~BfTypeInfoEx()
|
||||
{
|
||||
delete mUsingFieldData;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -775,13 +775,6 @@ void BfTypeDef::PopulateMemberSets()
|
|||
fieldDef->mNextWithSameName = (BfFieldDef*)entry->mMemberDef;
|
||||
entry->mMemberDef = fieldDef;
|
||||
}
|
||||
|
||||
if (fieldDef->mUsingProtection != BfProtection_Hidden)
|
||||
{
|
||||
if (mUsingFieldData == NULL)
|
||||
mUsingFieldData = new BfUsingFieldData();
|
||||
mUsingFieldData->mUsingFields.Add(fieldDef);
|
||||
}
|
||||
}
|
||||
|
||||
while (mPropertySet.mSourceSize < mProperties.mSize)
|
||||
|
@ -795,13 +788,6 @@ void BfTypeDef::PopulateMemberSets()
|
|||
propDef->mNextWithSameName = (BfPropertyDef*)entry->mMemberDef;
|
||||
entry->mMemberDef = propDef;
|
||||
}
|
||||
|
||||
if (propDef->mUsingProtection != BfProtection_Hidden)
|
||||
{
|
||||
if (mUsingFieldData == NULL)
|
||||
mUsingFieldData = new BfUsingFieldData();
|
||||
mUsingFieldData->mUsingFields.Add(propDef);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -813,9 +799,7 @@ void BfTypeDef::ClearMemberSets()
|
|||
|
||||
for (auto entry : mFieldSet)
|
||||
((BfFieldDef*)entry.mMemberDef)->mNextWithSameName = NULL;
|
||||
mFieldSet.Clear();
|
||||
delete mUsingFieldData;
|
||||
mUsingFieldData = NULL;
|
||||
mFieldSet.Clear();
|
||||
|
||||
for (auto entry : mPropertySet)
|
||||
((BfPropertyDef*)entry.mMemberDef)->mNextWithSameName = NULL;
|
||||
|
@ -834,7 +818,6 @@ BfTypeDef::~BfTypeDef()
|
|||
mSource->mRefCount--;
|
||||
BF_ASSERT(mSource->mRefCount >= 0);
|
||||
}
|
||||
delete mUsingFieldData;
|
||||
}
|
||||
|
||||
BfSource* BfTypeDef::GetLastSource()
|
||||
|
@ -3055,8 +3038,6 @@ void BfSystem::InjectNewRevision(BfTypeDef* typeDef)
|
|||
typeDef->mPartials = nextTypeDef->mPartials;
|
||||
typeDef->mMethodSet.Clear();
|
||||
typeDef->mFieldSet.Clear();
|
||||
delete typeDef->mUsingFieldData;
|
||||
typeDef->mUsingFieldData = NULL;
|
||||
typeDef->mPropertySet.Clear();
|
||||
|
||||
delete nextTypeDef;
|
||||
|
@ -3170,9 +3151,7 @@ void BfSystem::AddToCompositePartial(BfPassInstance* passInstance, BfTypeDef* co
|
|||
newField->mIdx = (int)typeDef->mFields.size();
|
||||
typeDef->mFields.push_back(newField);
|
||||
}
|
||||
typeDef->mFieldSet.Clear();
|
||||
delete typeDef->mUsingFieldData;
|
||||
typeDef->mUsingFieldData = NULL;
|
||||
typeDef->mFieldSet.Clear();
|
||||
|
||||
bool hadNoDeclMethod = false;
|
||||
int startMethodIdx = (int)typeDef->mMethods.size();
|
||||
|
|
|
@ -1052,38 +1052,6 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class BfUsingFieldData
|
||||
{
|
||||
public:
|
||||
struct FieldRef
|
||||
{
|
||||
BfTypeInstance* mTypeInstance;
|
||||
BfFieldDef* mFieldDef;
|
||||
|
||||
FieldRef()
|
||||
{
|
||||
mTypeInstance = NULL;
|
||||
mFieldDef = NULL;
|
||||
}
|
||||
|
||||
FieldRef(BfTypeInstance* typeInst, BfFieldDef* fieldDef)
|
||||
{
|
||||
mTypeInstance = typeInst;
|
||||
mFieldDef = fieldDef;
|
||||
}
|
||||
};
|
||||
|
||||
struct Entry
|
||||
{
|
||||
Array<FieldRef> mConflicts;
|
||||
SizedArray<FieldRef, 1> mLookup;
|
||||
};
|
||||
|
||||
public:
|
||||
Array<BfFieldDef*> mUsingFields;
|
||||
Dictionary<String, Entry> mEntries;
|
||||
};
|
||||
|
||||
// For partial classes, the first entry in the map will contain the combined data
|
||||
class BfTypeDef
|
||||
{
|
||||
|
@ -1127,7 +1095,6 @@ public:
|
|||
Array<BfTypeReference*> mStaticSearch;
|
||||
Array<BfTypeReference*> mInternalAccessSet;
|
||||
Array<BfFieldDef*> mFields;
|
||||
BfUsingFieldData* mUsingFieldData; // Created during mFieldSet
|
||||
Array<BfPropertyDef*> mProperties;
|
||||
Array<BfMethodDef*> mMethods;
|
||||
BfTypeDefMemberSet mMethodSet;
|
||||
|
@ -1217,8 +1184,7 @@ public:
|
|||
mOuterType = NULL;
|
||||
mTypeDeclaration = NULL;
|
||||
mNextRevision = NULL;
|
||||
mProtection = BfProtection_Public;
|
||||
mUsingFieldData = NULL;
|
||||
mProtection = BfProtection_Public;
|
||||
}
|
||||
|
||||
BfSource* GetLastSource();
|
||||
|
|
87
IDEHelper/Tests/src/UsingField.bf
Normal file
87
IDEHelper/Tests/src/UsingField.bf
Normal file
|
@ -0,0 +1,87 @@
|
|||
using System;
|
||||
|
||||
namespace Tests
|
||||
{
|
||||
class UsingField
|
||||
{
|
||||
class ClassA
|
||||
{
|
||||
public int mA0 = 1;
|
||||
public static int sA0 = 2;
|
||||
}
|
||||
|
||||
class ClassB
|
||||
{
|
||||
public int mB0 = 3;
|
||||
public static int sB0 = 4;
|
||||
}
|
||||
|
||||
class ClassC
|
||||
{
|
||||
public int mC0 = 12;
|
||||
public int mC1 = 23;
|
||||
|
||||
public int PropC0 => 123;
|
||||
public int MethodC0() => 234;
|
||||
|
||||
using public static ClassA sA = new .() ~ delete _;
|
||||
ClassB sB = new .() ~ delete _;
|
||||
|
||||
using public ClassB B => sB;
|
||||
}
|
||||
|
||||
class ClassD
|
||||
{
|
||||
public using protected append ClassC mC;
|
||||
private using append ClassC mC2;
|
||||
|
||||
public int mD0 = 34;
|
||||
|
||||
public this()
|
||||
{
|
||||
mC.mC0 += 10000;
|
||||
mC2.mC0 += 20000;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
[Union]
|
||||
struct Vector2
|
||||
{
|
||||
public struct Coords
|
||||
{
|
||||
public float mX;
|
||||
public float mY;
|
||||
}
|
||||
|
||||
public float[2] mValues;
|
||||
public using Coords mCoords;
|
||||
|
||||
public this(float x, float y)
|
||||
{
|
||||
mX = x;
|
||||
mY = y;
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public static void Test()
|
||||
{
|
||||
ClassD cd = scope .();
|
||||
cd.mC0 = 123;
|
||||
Test.Assert(cd.PropC0 == 123);
|
||||
Test.Assert(cd.MethodC0() == 234);
|
||||
Test.Assert(cd.mD0 == 34);
|
||||
|
||||
Test.Assert(ClassD.sA0 == 2);
|
||||
Test.Assert(ClassD.sB0 == 4);
|
||||
|
||||
Vector2 vec = .(1.2f, 2.3f);
|
||||
Test.Assert(sizeof(Vector2) == 8);
|
||||
Test.Assert(vec.mX == 1.2f);
|
||||
Test.Assert(vec.mY == 2.3f);
|
||||
Test.Assert(vec.mValues[0] == 1.2f);
|
||||
Test.Assert(vec.mValues[1] == 2.3f);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue