1
0
Fork 0
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:
Brian Fiete 2022-07-10 07:50:08 -04:00
parent ff229f385d
commit 450d541292
13 changed files with 850 additions and 253 deletions

View file

@ -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()));
}
}

View file

@ -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);
};

View file

@ -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))
{

View file

@ -214,6 +214,7 @@ public:
BfType* mCheckReturnType;
BfMethodType mMethodType;
BfCheckedKind mCheckedKind;
Array<SizedArray<BfUsingFieldData::MemberRef, 1>*>* mUsingLists;
bool mHasArgNames;
bool mHadExplicitGenericArguments;
bool mHadOpenGenericArguments;

View file

@ -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};

View file

@ -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);

View file

@ -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);

View file

@ -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)
{

View file

@ -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)

View file

@ -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;
}
};

View file

@ -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();

View file

@ -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();

View 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);
}
}
}