From 450d5412920581b12739149086da7451f42132a4 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Sun, 10 Jul 2022 07:50:08 -0400 Subject: [PATCH] Added 'using' fields --- IDEHelper/Compiler/BfAutoComplete.cpp | 87 +++- IDEHelper/Compiler/BfAutoComplete.h | 1 + IDEHelper/Compiler/BfExprEvaluator.cpp | 480 +++++++++++++-------- IDEHelper/Compiler/BfExprEvaluator.h | 1 + IDEHelper/Compiler/BfModule.cpp | 15 +- IDEHelper/Compiler/BfModule.h | 1 + IDEHelper/Compiler/BfModuleTypeUtils.cpp | 145 +++++++ IDEHelper/Compiler/BfReducer.cpp | 34 +- IDEHelper/Compiler/BfResolvedTypeUtils.cpp | 119 +++++ IDEHelper/Compiler/BfResolvedTypeUtils.h | 72 ++++ IDEHelper/Compiler/BfSystem.cpp | 25 +- IDEHelper/Compiler/BfSystem.h | 36 +- IDEHelper/Tests/src/UsingField.bf | 87 ++++ 13 files changed, 850 insertions(+), 253 deletions(-) create mode 100644 IDEHelper/Tests/src/UsingField.bf diff --git a/IDEHelper/Compiler/BfAutoComplete.cpp b/IDEHelper/Compiler/BfAutoComplete.cpp index 34886f31..0add68bd 100644 --- a/IDEHelper/Compiler/BfAutoComplete.cpp +++ b/IDEHelper/Compiler/BfAutoComplete.cpp @@ -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& 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())); + } +} diff --git a/IDEHelper/Compiler/BfAutoComplete.h b/IDEHelper/Compiler/BfAutoComplete.h index f05139a1..6e7f30f9 100644 --- a/IDEHelper/Compiler/BfAutoComplete.h +++ b/IDEHelper/Compiler/BfAutoComplete.h @@ -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& foundList); void SetResultStringType(BfType* type); }; diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 890fe2f5..f0a71905 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -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*> foundLists; + + auto _CheckUsingData = [&](BfUsingFieldData* usingData) { - HashSet checkedTypeSet; - BfUsingFieldData::FieldRef firstFoundField; + BfUsingFieldData::Entry* entry = NULL; + if (!usingData->mEntries.TryGetValue(findName, &entry)) + return; - std::function _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 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 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*> 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 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 ignoreFixits(autoComplete->mIgnoreFixits, true); VisitChild(targetNode); deferredFixits = true; } - else if (!evaluatedLeft) + else*/ + if (!evaluatedLeft) { if (auto memberReferenceExpr = BfNodeDynCast(targetNode)) { diff --git a/IDEHelper/Compiler/BfExprEvaluator.h b/IDEHelper/Compiler/BfExprEvaluator.h index 035acb0f..76c0308d 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.h +++ b/IDEHelper/Compiler/BfExprEvaluator.h @@ -214,6 +214,7 @@ public: BfType* mCheckReturnType; BfMethodType mMethodType; BfCheckedKind mCheckedKind; + Array*>* mUsingLists; bool mHasArgNames; bool mHadExplicitGenericArguments; bool mHadOpenGenericArguments; diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 91b14958..1ca08404 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -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}; diff --git a/IDEHelper/Compiler/BfModule.h b/IDEHelper/Compiler/BfModule.h index 982e9a0d..c6c2c363 100644 --- a/IDEHelper/Compiler/BfModule.h +++ b/IDEHelper/Compiler/BfModule.h @@ -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); diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index 77e6c732..95168ad1 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -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 checkedTypeSet; + Array memberRefs; + std::function _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 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 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 lookup; + for (auto entry : memberRefs) + lookup.Add(entry); + entry->mLookups.Add(lookup); + } + } + }; + + _CheckType(typeInstance, false); +} + void BfModule::DoPopulateType_SetGenericDependencies(BfTypeInstance* genericTypeInstance) { SetAndRestoreValue prevTypeInstance(mCurTypeInstance, genericTypeInstance); diff --git a/IDEHelper/Compiler/BfReducer.cpp b/IDEHelper/Compiler/BfReducer.cpp index ce8fad0b..b6e85698 100644 --- a/IDEHelper/Compiler/BfReducer.cpp +++ b/IDEHelper/Compiler/BfReducer.cpp @@ -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(); -// 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(); + ReplaceNode(tokenNode, usingSpecifier); + MEMBER_SET(usingSpecifier, mUsingToken, tokenNode); + MEMBER_SET(fieldDecl, mConstSpecifier, usingSpecifier); + handled = true; + } if (token == BfToken_ReadOnly) { diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp index 5dabfdeb..99637081 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp @@ -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) diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.h b/IDEHelper/Compiler/BfResolvedTypeUtils.h index 18c22ee2..f1eef7f5 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.h +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.h @@ -1821,19 +1821,91 @@ public: Array 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, 1> mLookups; + }; + +public: + Dictionary mEntries; + Dictionary mMethods; +}; + class BfTypeInfoEx { public: + BfUsingFieldData* mUsingFieldData; BfType* mUnderlyingType; int64 mMinValue; int64 mMaxValue; BfTypeInfoEx() { + mUsingFieldData = NULL; mUnderlyingType = NULL; mMinValue = 0; mMaxValue = 0; } + + ~BfTypeInfoEx() + { + delete mUsingFieldData; + } }; diff --git a/IDEHelper/Compiler/BfSystem.cpp b/IDEHelper/Compiler/BfSystem.cpp index b0a0d795..a39eb3b8 100644 --- a/IDEHelper/Compiler/BfSystem.cpp +++ b/IDEHelper/Compiler/BfSystem.cpp @@ -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(); diff --git a/IDEHelper/Compiler/BfSystem.h b/IDEHelper/Compiler/BfSystem.h index 4306c478..6ef9c9fd 100644 --- a/IDEHelper/Compiler/BfSystem.h +++ b/IDEHelper/Compiler/BfSystem.h @@ -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 mConflicts; - SizedArray mLookup; - }; - -public: - Array mUsingFields; - Dictionary mEntries; -}; - // For partial classes, the first entry in the map will contain the combined data class BfTypeDef { @@ -1127,7 +1095,6 @@ public: Array mStaticSearch; Array mInternalAccessSet; Array mFields; - BfUsingFieldData* mUsingFieldData; // Created during mFieldSet Array mProperties; Array mMethods; BfTypeDefMemberSet mMethodSet; @@ -1217,8 +1184,7 @@ public: mOuterType = NULL; mTypeDeclaration = NULL; mNextRevision = NULL; - mProtection = BfProtection_Public; - mUsingFieldData = NULL; + mProtection = BfProtection_Public; } BfSource* GetLastSource(); diff --git a/IDEHelper/Tests/src/UsingField.bf b/IDEHelper/Tests/src/UsingField.bf new file mode 100644 index 00000000..6fef581b --- /dev/null +++ b/IDEHelper/Tests/src/UsingField.bf @@ -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); + } + } +} \ No newline at end of file