diff --git a/BeefLibs/corlib/src/Type.bf b/BeefLibs/corlib/src/Type.bf index 11aeb50c..6b27fea5 100644 --- a/BeefLibs/corlib/src/Type.bf +++ b/BeefLibs/corlib/src/Type.bf @@ -381,7 +381,15 @@ namespace System { get { - return (mTypeFlags & (TypeFlags.SpecializedGeneric | TypeFlags.UnspecializedGeneric)) != 0; + return (mTypeFlags & (.SpecializedGeneric | .UnspecializedGeneric)) != 0; + } + } + + public bool IsGenericParam + { + get + { + return (mTypeFlags & .GenericParam) != 0; } } @@ -641,6 +649,8 @@ namespace System } } + + enum TypeCode : uint8 { None, @@ -1298,6 +1308,7 @@ namespace System.Reflection Delegate = 0x20000, Function = 0x40000, HasDestructor = 0x80000, + GenericParam = 0x100000, } public enum FieldFlags : uint16 diff --git a/IDEHelper/Compiler/BfContext.cpp b/IDEHelper/Compiler/BfContext.cpp index 93f2ac67..367dbd4c 100644 --- a/IDEHelper/Compiler/BfContext.cpp +++ b/IDEHelper/Compiler/BfContext.cpp @@ -1094,13 +1094,25 @@ void BfContext::RebuildType(BfType* type, bool deleteOnDemandTypes, bool rebuild if (typeInst->mTypeDef->mEmitParent != NULL) { - auto emitTypeDef = typeInst->mTypeDef; + auto emitTypeDef = typeInst->mTypeDef; typeInst->mTypeDef = emitTypeDef->mEmitParent; BfLogSysM("Type %p queueing delete of typeDef %p, resetting typeDef to %p\n", typeInst, emitTypeDef, typeInst->mTypeDef); - emitTypeDef->mDefState = BfTypeDef::DefState_Deleted; - AutoCrit autoCrit(mSystem->mDataLock); - BF_ASSERT(!mSystem->mTypeDefDeleteQueue.Contains(emitTypeDef)); - mSystem->mTypeDefDeleteQueue.push_back(emitTypeDef); + if (emitTypeDef->mDefState != BfTypeDef::DefState_Deleted) + { + emitTypeDef->mDefState = BfTypeDef::DefState_Deleted; + AutoCrit autoCrit(mSystem->mDataLock); + BF_ASSERT(!mSystem->mTypeDefDeleteQueue.Contains(emitTypeDef)); + mSystem->mTypeDefDeleteQueue.push_back(emitTypeDef); + + for (auto& dep : typeInst->mDependencyMap) + { + if (auto typeInst = dep.mKey->ToTypeInstance()) + { + if (typeInst->mTypeDef == emitTypeDef) + RebuildType(typeInst); + } + } + } } //typeInst->mTypeDef->ClearEmitted(); diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 14149d72..2334a524 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -2664,7 +2664,7 @@ void BfMethodMatcher::TryDevirtualizeCall(BfTypedValue target, BfTypedValue* ori if ((mModule->mCompiler->IsAutocomplete()) || (mModule->mContext->mResolvingVarField)) return; - if ((mModule->mBfIRBuilder->mIgnoreWrites) && (!mBestMethodDef->mIsConcrete)) + if ((mModule->mBfIRBuilder->mIgnoreWrites) && (!mBestMethodDef->mIsConcrete) && (!mBestMethodTypeInstance->IsInterface())) return; if (mBestMethodTypeInstance->IsInterface()) @@ -3443,7 +3443,7 @@ void BfExprEvaluator::Visit(BfCaseExpression* caseExpr) } - if ((caseValAddr) && (caseValAddr.mType->IsVar())) + if ((caseValAddr) && (IsVar(caseValAddr.mType))) { auto invocationExpr = BfNodeDynCast(caseExpr->mCaseExpression); if (invocationExpr != NULL) @@ -3519,6 +3519,18 @@ static bool IsCharType(BfTypeCode typeCode) } } +bool BfExprEvaluator::IsVar(BfType* type) +{ + if (type->IsVar()) + return true; + if ((type->IsGenericParam()) && (!mModule->mBfIRBuilder->mIgnoreWrites)) + { + BF_ASSERT(mModule->mIsComptimeModule); + return true; + } + return false; +} + void BfExprEvaluator::GetLiteral(BfAstNode* refNode, const BfVariant& variant) { switch (variant.mTypeCode) @@ -4298,7 +4310,7 @@ BfTypedValue BfExprEvaluator::LookupField(BfAstNode* targetSrc, BfTypedValue tar } } - if ((target.mType != NULL) && (target.mType->IsVar())) + if ((target.mType != NULL) && (IsVar(target.mType))) return BfTypedValue(mModule->GetDefaultValue(target.mType), target.mType, true); BfTypeInstance* startCheckType = mModule->mCurTypeInstance; @@ -4496,7 +4508,7 @@ BfTypedValue BfExprEvaluator::LookupField(BfAstNode* targetSrc, BfTypedValue tar mResultFieldInstance = fieldInstance; // Are we accessing a 'var' field that has not yet been resolved? - if (fieldInstance->mResolvedType->IsVar()) + if (IsVar(fieldInstance->mResolvedType)) { // This can happen if we have one var field referencing another var field fieldInstance->mResolvedType = mModule->ResolveVarFieldType(curCheckType, fieldInstance, field); @@ -5779,7 +5791,7 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, BfMethodInstance* { // We're attempting to directly invoke a non-virtual interface method, this will happen during the unspecialized pass // OR if we had an error and didn't find an implementing member in the actual target - if (!mModule->mCurMethodInstance->mIsUnspecialized) + if ((!mModule->mCurMethodInstance->mIsUnspecialized) && (!mModule->mCurTypeInstance->IsInterface())) mModule->AssertErrorState(); if (returnType->IsInterface()) @@ -5814,7 +5826,7 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, BfMethodInstance* return BfTypedValue(); } - if ((mModule->mCurMethodInstance != NULL) && (mModule->mCurMethodInstance->mIsUnspecialized)) + if (((mModule->mCurMethodInstance != NULL) && (mModule->mCurMethodInstance->mIsUnspecialized)) && (mModule->mBfIRBuilder->mIgnoreWrites)) { // Don't actually do the call - our target may be a generic param return _GetDefaultReturnValue(); @@ -6248,7 +6260,7 @@ void BfExprEvaluator::PushArg(BfTypedValue argVal, SizedArrayImpl& ir { MakeBaseConcrete(argVal); - if (argVal.mType->IsVar()) + if (IsVar(argVal.mType)) { argVal = mModule->GetDefaultTypedValue(mModule->mContext->mBfObjectType); } @@ -6774,9 +6786,14 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu } wantType = methodInstance->GetParamType(paramIdx); - if (wantType->IsSelf()) - wantType = methodInstance->GetOwner(); - if (wantType->IsVar()) + if (!mModule->mCurTypeInstance->IsInterface()) + { + // Resolve `Self` types + if (wantType->IsUnspecializedTypeVariation()) + wantType = mModule->ResolveGenericType(wantType, NULL, NULL); + } + + if (IsVar(wantType)) { // Case happens when we can't find the argument type failed = true; @@ -8109,7 +8126,7 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp } } - if ((!target.mType->IsGenericParam()) && (!target.IsSplat()) && (!target.mType->IsVar())) + if ((!target.mType->IsGenericParam()) && (!target.IsSplat()) && (!IsVar(target.mType))) target = MakeCallableTarget(targetSrc, target); } @@ -8181,7 +8198,7 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp } } } - else if (target.mType->IsVar()) + else if (IsVar(target.mType)) isUnboundCall = true; } @@ -8238,12 +8255,13 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp bool wantsExtensionCheck = target; auto targetType = target.mType; BfTypeDef* curTypeDef = NULL; + BfType* selfType = NULL; BfTypeInstance* targetTypeInst = NULL; bool checkNonStatic = true; if (target) { - if (targetType->IsVar()) + if (IsVar(targetType)) return mModule->GetDefaultTypedValue(targetType); targetTypeInst = targetType->ToTypeInstance(); if (targetTypeInst != NULL) @@ -8312,6 +8330,7 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp curTypeDef = targetTypeInst->mTypeDef; checkNonStatic = true; target = mModule->GetThis(); + selfType = mModule->mCurTypeInstance; //target.mType = targetTypeInst; } else @@ -8529,7 +8548,13 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp } BfTypedValue staticResult; - methodMatcher.TryDevirtualizeCall(target, &origTarget, &staticResult); + // + { + auto devirtTarget = target; + if ((devirtTarget.mType == NULL) && (selfType != NULL)) + devirtTarget.mType = selfType; + methodMatcher.TryDevirtualizeCall(devirtTarget, &origTarget, &staticResult); + } if (staticResult) return staticResult; bypassVirtual |= methodMatcher.mBypassVirtual; @@ -8873,7 +8898,7 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp } return MatchMethod(targetSrc, NULL, fieldVal, false, false, "Invoke", argValues, methodGenericArguments, checkedKind); } - if (fieldVal.mType->IsVar()) + if (IsVar(fieldVal.mType)) { FinishDeferredEvals(argValues); return BfTypedValue(mModule->GetDefaultValue(fieldVal.mType), fieldVal.mType); @@ -9456,17 +9481,27 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp if (result) { - if (result.mType->IsSelf()) + if ((result.mType->IsUnspecializedTypeVariation()) && (moduleMethodInstance.mMethodInstance->GetOwner()->IsInterface())) { + BfType* selfType = NULL; + if (methodMatcher.mSelfType != NULL) { BF_ASSERT(mModule->IsInGeneric()); - result = mModule->GetDefaultTypedValue(methodMatcher.mSelfType); + selfType = methodMatcher.mSelfType; } - else + else { // Will be an error - result = mModule->GetDefaultTypedValue(methodMatcher.mBestMethodTypeInstance); + selfType = methodMatcher.mBestMethodTypeInstance; + } + + if ((selfType != NULL) && (!selfType->IsInterface())) + { + SetAndRestoreValue prevCurTypeInst(mModule->mCurTypeInstance, selfType->ToTypeInstance()); + auto resolvedType = mModule->ResolveGenericType(result.mType, NULL, NULL); + if ((resolvedType != NULL) && (resolvedType != result.mType)) + result = mModule->GetDefaultTypedValue(resolvedType); } } } @@ -9537,7 +9572,7 @@ void BfExprEvaluator::LookupQualifiedName(BfQualifiedNameNode* nameNode, bool ig auto origResult = mResult; auto lookupType = BindGenericType(nameNode, mResult.mType); - if (mResult.mType->IsVar()) + if (IsVar(mResult.mType)) { mResult = BfTypedValue(mModule->GetDefaultValue(mResult.mType), mResult.mType, true); return; @@ -9696,9 +9731,10 @@ void BfExprEvaluator::LookupQualifiedName(BfAstNode* nameNode, BfIdentifierNode* mResult.mType = mResult.mType->GetUnderlyingType(); auto origResult = mResult; - if (mResult.mType->IsVar()) + if (IsVar(mResult.mType)) { - mResult = BfTypedValue(mModule->GetDefaultValue(mResult.mType), mResult.mType, true); + auto varType = mModule->GetPrimitiveType(BfTypeCode_Var); + mResult = BfTypedValue(mModule->GetDefaultValue(varType), varType, true); return; } @@ -10404,7 +10440,7 @@ void BfExprEvaluator::Visit(BfTypeOfExpression* typeOfExpr) return; } - if (type->IsGenericParam()) + if ((type->IsGenericParam()) && (!mModule->mIsComptimeModule)) { mResult = BfTypedValue(mModule->mBfIRBuilder->GetUndefConstValue(mModule->mBfIRBuilder->MapType(typeType)), typeType); } @@ -10493,6 +10529,8 @@ bool BfExprEvaluator::LookupTypeProp(BfTypeOfExpression* typeOfExpr, BfIdentifie _BoolResult(type->IsNullable()); else if (memberName == "IsGenericType") _BoolResult(type->IsGenericTypeInstance()); + else if (memberName == "IsGenericParam") + _BoolResult(type->IsGenericParam()); else if (memberName == "IsArray") _BoolResult(type->IsArray()); else if (memberName == "IsSizedArray") @@ -10658,7 +10696,7 @@ bool BfExprEvaluator::LookupTypeProp(BfTypeOfExpression* typeOfExpr, BfIdentifie else return false; - if (type->IsGenericParam()) + if ((type->IsGenericParam()) && (!mModule->mIsComptimeModule)) { if (mResult.mType != NULL) mResult = mModule->GetDefaultTypedValue(mResult.mType, false, Beefy::BfDefaultValueKind_Undef); @@ -11817,7 +11855,7 @@ void BfExprEvaluator::Visit(BfDelegateBindExpression* delegateBindExpr) if (bindResult.mMethodInstance == NULL) { - if ((mResult) && (mResult.mType->IsVar())) + if ((mResult) && (IsVar(mResult.mType))) return; mResult = BfTypedValue(); return; @@ -13563,7 +13601,7 @@ void BfExprEvaluator::Visit(BfLambdaBindExpression* lambdaBindExpr) if (capturedValue) { - if (!capturedTypedVal.mType->IsVar()) + if (!IsVar(capturedTypedVal.mType)) { auto fieldPtr = mModule->mBfIRBuilder->CreateInBoundsGEP(mResult.mValue, 0, fieldInstance->mDataIdx); mModule->mBfIRBuilder->CreateStore(capturedValue, fieldPtr); @@ -13942,7 +13980,7 @@ void BfExprEvaluator::CreateObject(BfObjectCreateExpression* objCreateExpr, BfAs } resolvedTypeRef = unresolvedTypeRef; - if ((resolvedTypeRef != NULL) && (resolvedTypeRef->IsVar())) + if ((resolvedTypeRef != NULL) && (IsVar(resolvedTypeRef))) resolvedTypeRef = unresolvedTypeRef; } @@ -14300,7 +14338,7 @@ void BfExprEvaluator::CreateObject(BfObjectCreateExpression* objCreateExpr, BfAs BfInitContext initContext(mModule, resultType, dimensions, dimLengthVals, arraySize, writeIdx); - if (resultType->IsVar()) + if (IsVar(resultType)) { SetAndRestoreValue prevIgnoreWrites(mModule->mBfIRBuilder->mIgnoreWrites, true); mResult = BfTypedValue(BfTypedValue(mModule->mBfIRBuilder->GetFakeVal(), mModule->GetPrimitiveType(BfTypeCode_Var))); @@ -14613,7 +14651,7 @@ void BfExprEvaluator::CreateObject(BfObjectCreateExpression* objCreateExpr, BfAs appendAllocAlign = BF_MAX(appendAllocAlign, allocAlign); BfIRValue allocValue; - if (resolvedTypeRef->IsVar()) + if (IsVar(resolvedTypeRef)) { mResult = mModule->GetDefaultTypedValue(resultType); return; @@ -14958,7 +14996,7 @@ BfTypedValue BfExprEvaluator::MakeCallableTarget(BfAstNode* targetSrc, BfTypedVa target = mModule->MakeAddressable(target); } - if (target.mType->IsVar()) + if (IsVar(target.mType)) { target.mType = mModule->mContext->mBfObjectType; return target; diff --git a/IDEHelper/Compiler/BfExprEvaluator.h b/IDEHelper/Compiler/BfExprEvaluator.h index e45afd29..c4e6b06c 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.h +++ b/IDEHelper/Compiler/BfExprEvaluator.h @@ -402,6 +402,7 @@ public: BfExprEvaluator(BfModule* module); ~BfExprEvaluator(); + bool IsVar(BfType* type); void GetLiteral(BfAstNode* refNode, const BfVariant& variant); void FinishExpressionResult(); virtual bool CheckAllowValue(const BfTypedValue& typedValue, BfAstNode* refNode); diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 413549cb..7dfa4f56 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -2898,6 +2898,9 @@ bool BfModule::AddErrorContext(StringImpl& errorString, BfAstNode* refNode, bool else methodInstance->mHasFailed = true; + if (!methodInstance->mHasStartedDeclaration) + StartMethodDeclaration(methodInstance, NULL); + bool isSpecializedMethod = ((methodInstance != NULL) && (!methodInstance->mIsUnspecialized) && (methodInstance->mMethodInfoEx != NULL) && (methodInstance->mMethodInfoEx->mMethodGenericArguments.size() != 0)); if (isSpecializedMethod) { @@ -5393,6 +5396,9 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary& usedStrin typeDataSource = ResolveTypeDef(mCompiler->mReflectConstExprType)->ToTypeInstance(); else typeDataSource = mContext->mBfTypeType; + + if (type->IsGenericParam()) + typeFlags |= BfTypeFlags_GenericParam; if ((!mTypeDataRefs.ContainsKey(typeDataSource)) && (typeDataSource != type)) { @@ -11396,10 +11402,12 @@ void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttri customAttributes->mAttributes.push_back(customAttribute); continue; } - + + SetAndRestoreValue prevCurTypeInst(mContext->mUnreifiedModule->mCurTypeInstance, mCurTypeInstance); + SetAndRestoreValue prevCurMethodInst(mContext->mUnreifiedModule->mCurMethodInstance, mCurMethodInstance); if (mContext->mCurTypeState != NULL) { - SetAndRestoreValue prevTypeRef(mContext->mCurTypeState->mCurAttributeTypeRef, attributesDirective->mAttributeTypeRef); + SetAndRestoreValue prevTypeRef(mContext->mCurTypeState->mCurAttributeTypeRef, attributesDirective->mAttributeTypeRef); mContext->mUnreifiedModule->ResolveTypeResult(attributesDirective->mAttributeTypeRef, attrType, BfPopulateType_BaseType, (BfResolveTypeRefFlags)0); } else @@ -13820,11 +13828,7 @@ BfModuleMethodInstance BfModule::GetMethodInstance(BfTypeInstance* typeInst, BfM { methodInstance->mMangleWithIdx = true; } - - BfModule* declareModule = GetOrCreateMethodModule(methodInstance); - if ((doingRedeclare) && (methodInstance->mDeclModule != mContext->mUnreifiedModule)) - declareModule = methodInstance->mDeclModule; - + BF_ASSERT(typeInst == methodInstance->GetOwner()); auto methodDeclaration = methodDef->GetMethodDeclaration(); @@ -13882,6 +13886,15 @@ BfModuleMethodInstance BfModule::GetMethodInstance(BfTypeInstance* typeInst, BfM addToWorkList = false; } + BfModule* declareModule; + // + { + SetAndRestoreValue prevMethodInstance(mCurMethodInstance, methodInstance); + declareModule = GetOrCreateMethodModule(methodInstance); + } + if ((doingRedeclare) && (methodInstance->mDeclModule != mContext->mUnreifiedModule)) + declareModule = methodInstance->mDeclModule; + BF_ASSERT(declareModule != NULL); methodInstance->mDeclModule = declareModule; @@ -18685,7 +18698,7 @@ void BfModule::EmitGCFindTLSMembers() CallChainedMethods(mCurMethodInstance, false); } -void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup) +void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup, bool forceIRWrites) { BP_ZONE_F("BfModule::ProcessMethod %s", BP_DYN_STR(methodInstance->mMethodDef->mName.c_str())); @@ -18714,7 +18727,7 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup) } } - SetAndRestoreValue prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites, mWantsIRIgnoreWrites || methodInstance->mIsUnspecialized); + SetAndRestoreValue prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites, (mWantsIRIgnoreWrites || methodInstance->mIsUnspecialized) && (!forceIRWrites)); if ((HasCompiledOutput()) && (!mBfIRBuilder->mIgnoreWrites)) { @@ -20680,7 +20693,8 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup) mBfIRBuilder->MergeBlockDown(mCurMethodState->mIRInitBlock, mCurMethodState->mIREntryBlock); mBfIRBuilder->MergeBlockDown(mCurMethodState->mIRHeadBlock, mCurMethodState->mIREntryBlock); - if ((mCurMethodInstance->mIsUnspecialized) /*|| (typeDef->mIsFunction)*/ || (mCurTypeInstance->IsUnspecializedType())) + if (((mCurMethodInstance->mIsUnspecialized) /*|| (typeDef->mIsFunction)*/ || (mCurTypeInstance->IsUnspecializedType())) && + (!mIsComptimeModule)) { // Don't keep instructions for unspecialized types mBfIRBuilder->Func_DeleteBody(mCurMethodInstance->mIRFunction); @@ -20712,7 +20726,8 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup) // We don't want to hold on to pointers to LLVMFunctions of unspecialized types. // This allows us to delete the mScratchModule LLVM module without rebuilding all // unspecialized types - if ((mCurTypeInstance->IsUnspecializedType()) || (mCurTypeInstance->IsInterface())) + if (((mCurTypeInstance->IsUnspecializedType()) && (!mIsComptimeModule)) || + (mCurTypeInstance->IsInterface())) { BfLogSysM("ProcessMethod Clearing IRFunction: %p\n", methodInstance); methodInstance->mIRFunction = BfIRFunction(); @@ -21904,7 +21919,8 @@ void BfModule::SetupIRFunction(BfMethodInstance* methodInstance, StringImpl& man if (!methodInstance->mIRFunction) { BfIRFunction func; - bool wantsLLVMFunc = ((!typeInstance->IsUnspecializedType()) && (!methodDef->IsEmptyPartial())) && (funcType); + bool wantsLLVMFunc = ((!typeInstance->IsUnspecializedType() || (mIsComptimeModule)) && + (!methodDef->IsEmptyPartial())) && (funcType); /*if (mCurTypeInstance->mTypeDef->mName->ToString() == "ClassA") { @@ -22042,6 +22058,79 @@ static void StackOverflow() StackOverflow(); } +void BfModule::StartMethodDeclaration(BfMethodInstance* methodInstance, BfMethodState* prevMethodState) +{ + methodInstance->mHasStartedDeclaration = true; + auto methodDef = methodInstance->mMethodDef; + auto typeInstance = methodInstance->GetOwner(); + + bool hasNonGenericParams = false; + bool hasGenericParams = false; + + int dependentGenericStartIdx = 0; + + if (methodDef->mIsLocalMethod) + { + // If we're a local generic method inside an outer generic method, we can still be considered unspecialized + // if our outer method's generic args are specialized but ours are unspecialized. This is because locals get + // instantiated uniquely for each specialized or unspecialized pass through the outer method, but the local + // method still 'inherits' the outer's generic arguments -- but we still need to make an unspecialized pass + // over the local method each time + auto rootMethodInstance = prevMethodState->GetRootMethodState()->mMethodInstance; + dependentGenericStartIdx = 0; + if (rootMethodInstance != NULL) + { + if (rootMethodInstance->mMethodInfoEx != NULL) + dependentGenericStartIdx = (int)rootMethodInstance->mMethodInfoEx->mMethodGenericArguments.size(); + + methodInstance->mIsUnspecialized = rootMethodInstance->mIsUnspecialized; + methodInstance->mIsUnspecializedVariation = rootMethodInstance->mIsUnspecializedVariation; + } + } + + for (int genericArgIdx = dependentGenericStartIdx; genericArgIdx < (int)methodInstance->GetNumGenericArguments(); genericArgIdx++) + { + auto genericArgType = methodInstance->mMethodInfoEx->mMethodGenericArguments[genericArgIdx]; + if (genericArgType->IsGenericParam()) + { + hasGenericParams = true; + auto genericParam = (BfGenericParamType*)genericArgType; + methodInstance->mIsUnspecialized = true; + if ((genericParam->mGenericParamKind != BfGenericParamKind_Method) || (genericParam->mGenericParamIdx != genericArgIdx)) + methodInstance->mIsUnspecializedVariation = true; + } + else + { + hasNonGenericParams = true; + if (genericArgType->IsUnspecializedType()) + { + methodInstance->mIsUnspecialized = true; + methodInstance->mIsUnspecializedVariation = true; + } + } + } + + if ((hasGenericParams) && (hasNonGenericParams)) + { + methodInstance->mIsUnspecializedVariation = true; + } + + if (typeInstance->IsUnspecializedType()) + { + // A specialized method within an unspecialized type is considered an unspecialized variation -- in the sense that we don't + // actually want to do method processing on it + if ((!methodInstance->mIsUnspecialized) && (methodInstance->GetNumGenericArguments() != 0)) + methodInstance->mIsUnspecializedVariation = true; + methodInstance->mIsUnspecialized = true; + } + + if (methodInstance->mIsUnspecializedVariation) + BF_ASSERT(methodInstance->mIsUnspecialized); + + if (methodDef->mMethodType == BfMethodType_Mixin) + methodInstance->mIsUnspecialized = true; +} + // methodDeclaration is NULL for default constructors void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool isTemporaryFunc, bool addToWorkList) { @@ -22064,7 +22153,7 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool BfMethodState methodState; SetAndRestoreValue prevMethodState(mCurMethodState, &methodState); methodState.mTempKind = BfMethodState::TempKind_Static; - + defer({ mCurMethodInstance->mHasBeenDeclared = true; }); // If we are doing this then we may end up creating methods when var types are unknown still, failing on splat/zero-sized info @@ -22101,92 +22190,9 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool if ((methodInstance->IsSpecializedByAutoCompleteMethod()) || (mCurTypeInstance->IsFunction())) addToWorkList = false; - - bool hasNonGenericParams = false; - bool hasGenericParams = false; - - int dependentGenericStartIdx = 0; - if (methodDef->mIsLocalMethod) - { - // If we're a local generic method inside an outer generic method, we can still be considered unspecialized - // if our outer method's generic args are specialized but ours are unspecialized. This is because locals get - // instantiated uniquely for each specialized or unspecialized pass through the outer method, but the local - // method still 'inherits' the outer's generic arguments -- but we still need to make an unspecialized pass - // over the local method each time - auto rootMethodInstance = prevMethodState.mPrevVal->GetRootMethodState()->mMethodInstance; - dependentGenericStartIdx = 0; - if (rootMethodInstance != NULL) - { - if (rootMethodInstance->mMethodInfoEx != NULL) - dependentGenericStartIdx = (int)rootMethodInstance->mMethodInfoEx->mMethodGenericArguments.size(); - - methodInstance->mIsUnspecialized = rootMethodInstance->mIsUnspecialized; - methodInstance->mIsUnspecializedVariation = rootMethodInstance->mIsUnspecializedVariation; - } - } - - for (int genericArgIdx = dependentGenericStartIdx; genericArgIdx < (int) methodInstance->GetNumGenericArguments(); genericArgIdx++) - { - auto genericArgType = methodInstance->mMethodInfoEx->mMethodGenericArguments[genericArgIdx]; - if (genericArgType->IsGenericParam()) - { - hasGenericParams = true; - auto genericParam = (BfGenericParamType*)genericArgType; - methodInstance->mIsUnspecialized = true; - if ((genericParam->mGenericParamKind != BfGenericParamKind_Method) || (genericParam->mGenericParamIdx != genericArgIdx)) - methodInstance->mIsUnspecializedVariation = true; - } - else - { - hasNonGenericParams = true; - if (genericArgType->IsUnspecializedType()) - { - methodInstance->mIsUnspecialized = true; - methodInstance->mIsUnspecializedVariation = true; - } - } - } - - if ((hasGenericParams) && (hasNonGenericParams)) - { - methodInstance->mIsUnspecializedVariation = true; - } - - if (typeInstance->IsUnspecializedType()) - { - // A specialized method within an unspecialized type is considered an unspecialized variation -- in the sense that we don't - // actually want to do method processing on it - if ((!methodInstance->mIsUnspecialized) && (methodInstance->GetNumGenericArguments() != 0)) - methodInstance->mIsUnspecializedVariation = true; - methodInstance->mIsUnspecialized = true; - } - - //methodInstance->mIsUnspecializedVariation |= typeInstance->IsUnspecializedTypeVariation(); - - for (auto genericParamDef : methodDef->mGenericParams) - { - if (mCompiler->IsAutocomplete()) - { - auto autoComplete = mCompiler->mResolvePassData->mAutoComplete; - //autoComplete->CheckTypeRef() - } - } - - if (methodInstance->mIsUnspecializedVariation) - { - } - - if (methodInstance->mIsUnspecializedVariation) - BF_ASSERT(methodInstance->mIsUnspecialized); - - if (methodDef->mMethodType == BfMethodType_Mixin) - methodInstance->mIsUnspecialized = true; - - if (methodInstance->mIsUnspecialized) - { - //BF_ASSERT(methodInstance->mDeclModule == methodInstance->GetOwner()->mModule); - } + if (!methodInstance->mHasStartedDeclaration) + StartMethodDeclaration(methodInstance, prevMethodState.mPrevVal); BfAutoComplete* bfAutocomplete = NULL; if (mCompiler->mResolvePassData != NULL) @@ -23164,7 +23170,7 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool // Don't compare specialized generic methods against normal methods if ((((mCurMethodInstance->mIsUnspecialized) || (mCurMethodInstance->mMethodDef->mGenericParams.size() == 0))) && - (!methodDef->mIsLocalMethod)) + (!methodDef->mIsLocalMethod) && (!mCurTypeInstance->IsUnspecializedTypeVariation())) { if ((!methodInstance->mIsForeignMethodDef) && (methodDef->mMethodType != BfMethodType_Init)) { diff --git a/IDEHelper/Compiler/BfModule.h b/IDEHelper/Compiler/BfModule.h index 6f296daf..99133b62 100644 --- a/IDEHelper/Compiler/BfModule.h +++ b/IDEHelper/Compiler/BfModule.h @@ -1888,6 +1888,7 @@ public: void GetMethodCustomAttributes(BfMethodInstance* methodInstance); void SetupIRFunction(BfMethodInstance* methodInstance, StringImpl& mangledName, bool isTemporaryFunc, bool* outIsIntrinsic); void CheckHotMethod(BfMethodInstance* methodInstance, const StringImpl& mangledName); + void StartMethodDeclaration(BfMethodInstance* methodInstance, BfMethodState* prevMethodState); void DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool isTemporaryFunc, bool addToWorkList = true); void AddMethodToWorkList(BfMethodInstance* methodInstance); bool IsInterestedInMethod(BfTypeInstance* typeInstance, BfMethodDef* methodDef); @@ -1916,7 +1917,7 @@ public: void AddHotDataReferences(BfHotDataReferenceBuilder* builder); void ProcessMethod_SetupParams(BfMethodInstance* methodInstance, BfType* thisType, bool wantsDIData, SizedArrayImpl* diParams); void ProcessMethod_ProcessDeferredLocals(int startIdx = 0); - void ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup = false); + void ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup = false, bool forceIRWrites = false); void CreateDynamicCastMethod(); void CreateValueTypeEqualsMethod(bool strictEquals); BfIRFunction GetIntrinsic(BfMethodInstance* methodInstance, bool reportFailure = false); diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index fe316aba..f8b43582 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -4178,13 +4178,8 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy } } } - - bool tryCE = true; - - if (typeInstance->IsUnspecializedType()) - tryCE = false; - - if ((typeInstance->mDefineState == BfTypeDefineState_CETypeInit) && (tryCE)) + + if (typeInstance->mDefineState == BfTypeDefineState_CETypeInit) { if (populateType <= BfPopulateType_AllowStaticMethods) return; @@ -12296,6 +12291,9 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp } else if (constant->mConstType == BfConstType_Undef) { + if (mIsComptimeModule) + return mBfIRBuilder->GetUndefConstValue(mBfIRBuilder->MapType(toType)); + BF_ASSERT(mBfIRBuilder->mIgnoreWrites); auto undefConst = (BfConstantUndef*)constant; diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.h b/IDEHelper/Compiler/BfResolvedTypeUtils.h index a1fc99e8..5a999d87 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.h +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.h @@ -843,6 +843,7 @@ public: bool mIsUnspecialized:1; bool mIsUnspecializedVariation:1; bool mIsReified:1; + bool mHasStartedDeclaration:1; bool mHasBeenDeclared:1; bool mHasBeenProcessed:1; bool mHasFailed:1; @@ -885,6 +886,7 @@ public: mIsUnspecialized = false; mIsUnspecializedVariation = false; mIsReified = true; + mHasStartedDeclaration = false; mHasBeenDeclared = false; mHasBeenProcessed = false; mHasFailed = false; @@ -2640,7 +2642,7 @@ public: static String TypeToString(BfAstNode* typeRef); static String TypeToString(BfTypeDef* typeDef, BfTypeNameFlags typeNameFlags = BfTypeNameFlags_None); static bool TypeToString(StringImpl& str, BfTypeDef* typeDef, BfTypeNameFlags typeNameFlags = BfTypeNameFlags_None); - static bool TypeEquals(BfType* typeA, BfType* typeB, BfType* selfType); + static bool TypeEquals(BfType* typeA, BfType* typeB, BfTypeInstance* selfType); template static void GetProjectList(BfType* checkType, T* projectList, int immutableLength) diff --git a/IDEHelper/Compiler/BfSystem.h b/IDEHelper/Compiler/BfSystem.h index 31db1ed4..27a8db99 100644 --- a/IDEHelper/Compiler/BfSystem.h +++ b/IDEHelper/Compiler/BfSystem.h @@ -187,6 +187,7 @@ enum BfTypeFlags BfTypeFlags_Delegate = 0x20000, BfTypeFlags_Function = 0x40000, BfTypeFlags_HasDestructor = 0x80000, + BfTypeFlags_GenericParam = 0x100000 }; enum BfMethodFlags diff --git a/IDEHelper/Compiler/CeMachine.cpp b/IDEHelper/Compiler/CeMachine.cpp index b063049a..c945ca4d 100644 --- a/IDEHelper/Compiler/CeMachine.cpp +++ b/IDEHelper/Compiler/CeMachine.cpp @@ -912,6 +912,7 @@ CeOperand CeBuilder::GetOperand(BeValue* value, bool allowAlloca, bool allowImme return result; } break; + case BeUndefConstant::TypeId: case BeConstant::TypeId: { uint64 u64Val = 0; @@ -1181,7 +1182,7 @@ CeOperand CeBuilder::GetOperand(BeValue* value, bool allowAlloca, bool allowImme // if (callInst->mInlineResult != NULL) // return GetOperand(callInst->mInlineResult); } - break; + break; } CeOperand* operandPtr = NULL; @@ -1279,7 +1280,7 @@ void CeBuilder::HandleParams() } } -void CeBuilder::ProcessMethod(BfMethodInstance* methodInstance, BfMethodInstance* dupMethodInstance) +void CeBuilder::ProcessMethod(BfMethodInstance* methodInstance, BfMethodInstance* dupMethodInstance, bool forceIRWrites) { SetAndRestoreValue prevMethodStateInConstEval(mCeMachine->mCeModule->mCurMethodState, NULL); BfAutoComplete* prevAutoComplete = NULL; @@ -1299,7 +1300,7 @@ void CeBuilder::ProcessMethod(BfMethodInstance* methodInstance, BfMethodInstance mCeMachine->mCeModule->mHadBuildError = false; auto irState = irBuilder->GetState(); auto beState = irCodeGen->GetState(); - mCeMachine->mCeModule->ProcessMethod(dupMethodInstance, true); + mCeMachine->mCeModule->ProcessMethod(dupMethodInstance, true, forceIRWrites); irCodeGen->SetState(beState); irBuilder->SetState(irState); @@ -1322,27 +1323,27 @@ void CeBuilder::Build() BfMethodInstance dupMethodInstance; dupMethodInstance.CopyFrom(methodInstance); auto methodDef = methodInstance->mMethodDef; - + bool isGenericVariation = (methodInstance->mIsUnspecializedVariation) || (methodInstance->GetOwner()->IsUnspecializedTypeVariation()); int dependentGenericStartIdx = 0; if ((((methodInstance->mMethodInfoEx != NULL) && ((int)methodInstance->mMethodInfoEx->mMethodGenericArguments.size() > dependentGenericStartIdx)) || - ((methodInstance->GetOwner()->IsGenericTypeInstance()) && (!isGenericVariation) && (!methodInstance->mMethodDef->mIsLocalMethod)))) + ((methodInstance->GetOwner()->IsGenericTypeInstance()) && (!isGenericVariation) && (!methodInstance->mMethodDef->mIsLocalMethod) && (!methodInstance->mIsUnspecialized)))) { auto unspecializedMethodInstance = mCeMachine->mCeModule->GetUnspecializedMethodInstance(methodInstance, !methodInstance->mMethodDef->mIsLocalMethod); if (!unspecializedMethodInstance->mHasBeenProcessed) { BfMethodInstance dupUnspecMethodInstance; dupUnspecMethodInstance.CopyFrom(unspecializedMethodInstance); - ProcessMethod(unspecializedMethodInstance, &dupUnspecMethodInstance); + ProcessMethod(unspecializedMethodInstance, &dupUnspecMethodInstance, false); dupMethodInstance.GetMethodInfoEx()->mGenericTypeBindings = dupUnspecMethodInstance.mMethodInfoEx->mGenericTypeBindings; } } - + // Clear this so we can properly get QueueStaticField calls mCeMachine->mCeModule->mStaticFieldRefs.Clear(); int startFunctionCount = (int)beModule->mFunctions.size(); - ProcessMethod(methodInstance, &dupMethodInstance); + ProcessMethod(methodInstance, &dupMethodInstance, true); if (mCeFunction->mInitializeState == CeFunction::InitializeState_Initialized) return; diff --git a/IDEHelper/Compiler/CeMachine.h b/IDEHelper/Compiler/CeMachine.h index 78a3abae..d8a6d085 100644 --- a/IDEHelper/Compiler/CeMachine.h +++ b/IDEHelper/Compiler/CeMachine.h @@ -730,7 +730,7 @@ public: void EmitBinaryOp(CeOp iOp, CeOp fOp, const CeOperand& lhs, const CeOperand& rhs, CeOperand& result); void EmitUnaryOp(CeOp iOp, CeOp fOp, const CeOperand& val, CeOperand& result); void EmitSizedOp(CeOp op, const CeOperand& operand, CeOperand* result, bool allowNonStdSize); - void ProcessMethod(BfMethodInstance* methodInstance, BfMethodInstance* dupMethodInstance); + void ProcessMethod(BfMethodInstance* methodInstance, BfMethodInstance* dupMethodInstance, bool forceIRWrites); void Build(); }; diff --git a/IDEHelper/DbgExprEvaluator.cpp b/IDEHelper/DbgExprEvaluator.cpp index 51c10fa0..571b2aeb 100644 --- a/IDEHelper/DbgExprEvaluator.cpp +++ b/IDEHelper/DbgExprEvaluator.cpp @@ -8167,8 +8167,8 @@ void DbgExprEvaluator::Visit(BfTypeAttrExpression* typeAttrExpr) case BfToken_StrideOf: mResult.mInt64 = dbgType->GetStride(); break; - case BfToken_TypeOf: - //TODO: + default: + Fail("Invalid attribute expression", typeAttrExpr); break; } } diff --git a/IDEHelper/Tests/src/Interfaces.bf b/IDEHelper/Tests/src/Interfaces.bf index 4f786e0d..ddbb7cd4 100644 --- a/IDEHelper/Tests/src/Interfaces.bf +++ b/IDEHelper/Tests/src/Interfaces.bf @@ -1,4 +1,7 @@ +#pragma warning disable 168 using System; +using System.Diagnostics; +using System.Reflection; namespace Tests { @@ -317,17 +320,75 @@ namespace Tests interface IParsable { + public enum Error + { + case Unknown; + case Syntax(int pos); + case InvalidValue; + case UnexpectedEnd; + } + + static Self GetDefault(Self[] arr); static Result Parse(StringView sv, Self defaultVal); + static Result ParseEx(StringView str) + { + Self[] arr = null; + Self defVal = GetDefault(arr); + switch (Parse(str, default(Self))) + { + case .Ok(let val): return .Ok(val); + case .Err: return .Err(.Unknown); + } + } } class ClassH : IParsable { + static Self IParsable.GetDefault(ClassH[] arr) + { + return default; + } + public static Result Parse(StringView sv, ClassH defaultVal) { return .Err; } } + + [AttributeUsage(.Method)] + struct MethodTestAttribute : Attribute, IComptimeMethodApply + { + public static String gLog = new .() ~ delete _; + + [Comptime] + public void ApplyToMethod(ComptimeMethodInfo method) + { + Compiler.EmitMethodEntry(method, "int b = 2;"); + } + } + + struct Test4 + { + [Comptime, OnCompile(.TypeInit)] + public static void Generator() + { + T val = default; + Compiler.EmitTypeBody(typeof(Self), "int test = 0;"); + } + + [MethodTest] + public void Zank() + { + int c = b; + } + + public void Test() mut + { + test = 1; + } + } + [Test] public static void TestDefaults() { @@ -367,6 +428,8 @@ namespace Tests TestIFaceD(cg); Test.Assert(cg.mA == 999); Test.Assert(TestIFaceD2(cg) == 999); + + ClassH ch = scope .(); } } }