diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 4afcb38a..f41aba32 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -13286,6 +13286,31 @@ void BfExprEvaluator::InjectMixin(BfAstNode* targetSrc, BfTypedValue target, boo return; auto methodInstance = moduleMethodInstance.mMethodInstance; + for (int checkGenericIdx = 0; checkGenericIdx < (int)methodMatcher.mBestMethodGenericArguments.size(); checkGenericIdx++) + { + auto& genericParams = methodInstance->mMethodInfoEx->mGenericParams; + auto genericArg = methodMatcher.mBestMethodGenericArguments[checkGenericIdx]; + if (genericArg->IsVar()) + continue; + + BfAstNode* paramSrc; + if (methodMatcher.mBestMethodGenericArgumentSrcs.size() == 0) + paramSrc = targetSrc; + else + paramSrc = methodMatcher.mArguments[methodMatcher.mBestMethodGenericArgumentSrcs[checkGenericIdx]].mExpression; + + // Note: don't pass methodMatcher.mBestMethodGenericArguments into here, this method is already specialized + BfError* error = NULL; + if (!mModule->CheckGenericConstraints(BfGenericParamSource(methodInstance), genericArg, paramSrc, genericParams[checkGenericIdx], NULL, &error)) + { + if (methodInstance->mMethodDef->mMethodDeclaration != NULL) + { + if (error != NULL) + mModule->mCompiler->mPassInstance->MoreInfo(StrFormat("See method declaration"), methodInstance->mMethodDef->GetRefNode()); + } + } + } + // Check circular ref based on methodInstance { bool hasCircularRef = false; diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index e39e30fd..ddb9e9ee 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -6836,6 +6836,52 @@ bool BfModule::CheckGenericConstraints(const BfGenericParamSource& genericParamS return false; } } + + if ((genericParamInst->mGenericParamFlags & BfGenericParamFlag_Delete) != 0) + { + bool canDelete = false; + if (checkArgType->IsPointer()) + canDelete = true; + else if (checkArgType->IsObjectOrInterface()) + canDelete = true; + + if (!canDelete) + { + if (!ignoreErrors) + *errorOut = Fail(StrFormat("The type '%s' must be a deletable type in order to use it as parameter '%s' for '%s'", + _TypeToString(origCheckArgType).c_str(), genericParamInst->GetName().c_str(), GenericParamSourceToString(genericParamSource).c_str()), checkArgTypeRef); + return false; + } + } + + if ((genericParamInst->mGenericParamFlags & BfGenericParamFlag_New) != 0) + { + bool canAlloc = false; + if (auto checkTypeInst = checkArgType->ToTypeInstance()) + { + if (checkTypeInst->IsObjectOrStruct()) + { + auto ctorClear = GetRawMethodByName(checkTypeInst, "__BfCtor", 0); + if (ctorClear->mMethodDef->mProtection == BfProtection_Public) + canAlloc = true; + else if ((ctorClear->mMethodDef->mProtection == BfProtection_Protected) && (mCurTypeInstance != NULL)) + canAlloc = TypeIsSubTypeOf(mCurTypeInstance, checkTypeInst, false); + } + } + else + { + // Any primitive types and stuff can be allocated + canAlloc = true; + } + + if (!canAlloc) + { + if (!ignoreErrors) + *errorOut = Fail(StrFormat("The type '%s' must have an accessible default constructor in order to use it as parameter '%s' for '%s'", + _TypeToString(origCheckArgType).c_str(), genericParamInst->GetName().c_str(), GenericParamSourceToString(genericParamSource).c_str()), checkArgTypeRef); + return false; + } + } if ((genericParamInst->mInterfaceConstraints.IsEmpty()) && (genericParamInst->mOperatorConstraints.IsEmpty()) && (genericParamInst->mTypeConstraint == NULL)) return true; @@ -12101,6 +12147,12 @@ BfModuleMethodInstance BfModule::GetMethodInstance(BfTypeInstance* typeInst, BfM SetAndRestoreValue prevTypeInstance(declareModule->mCurTypeInstance, typeInst); SetAndRestoreValue prevFilePos(declareModule->mCurFilePosition); + if ((methodDef->mMethodType == BfMethodType_Mixin) && (methodDef->mGenericParams.size() != 0) && (!isUnspecializedPass)) + { + // For mixins we only process the unspecialized version + addToWorkList = false; + } + declareModule->DoMethodDeclaration(methodDef->GetMethodDeclaration(), false, addToWorkList); if (processNow)