diff --git a/BeefLibs/corlib/src/Attribute.bf b/BeefLibs/corlib/src/Attribute.bf index d6714c9d..4bd007b0 100644 --- a/BeefLibs/corlib/src/Attribute.bf +++ b/BeefLibs/corlib/src/Attribute.bf @@ -340,6 +340,12 @@ namespace System } } + [AttributeUsage(.Method)] + public struct CommutableAttribute : Attribute + { + + } + [AttributeUsage(.Method | .Constructor)] public struct ErrorAttribute : Attribute { diff --git a/IDEHelper/Compiler/BfAst.cpp b/IDEHelper/Compiler/BfAst.cpp index 67cad91d..c65a8e25 100644 --- a/IDEHelper/Compiler/BfAst.cpp +++ b/IDEHelper/Compiler/BfAst.cpp @@ -96,6 +96,11 @@ void BfStructuralVisitor::Visit(BfGenericParamsDeclaration* genericParams) Visit(genericParams->ToBase()); } +void BfStructuralVisitor::Visit(BfGenericOperatorConstraint* genericConstraints) +{ + Visit(genericConstraints->ToBase()); +} + void BfStructuralVisitor::Visit(BfGenericConstraintsDeclaration* genericConstraints) { Visit(genericConstraints->ToBase()); @@ -1567,6 +1572,165 @@ const char* Beefy::BfGetOpName(BfUnaryOp unaryOp) } } +BfBinaryOp Beefy::BfTokenToBinaryOp(BfToken token) +{ + switch (token) + { + case BfToken_Plus: + return BfBinaryOp_Add; + case BfToken_Minus: + return BfBinaryOp_Subtract; + case BfToken_Star: + return BfBinaryOp_Multiply; + case BfToken_ForwardSlash: + return BfBinaryOp_Divide; + case BfToken_Modulus: + return BfBinaryOp_Modulus; + case BfToken_Ampersand: + return BfBinaryOp_BitwiseAnd; + case BfToken_Bar: + return BfBinaryOp_BitwiseOr; + case BfToken_Carat: + return BfBinaryOp_ExclusiveOr; + case BfToken_LDblChevron: + return BfBinaryOp_LeftShift; + case BfToken_RDblChevron: + return BfBinaryOp_RightShift; + case BfToken_CompareEquals: + return BfBinaryOp_Equality; + case BfToken_CompareNotEquals: + return BfBinaryOp_InEquality; + case BfToken_RChevron: + return BfBinaryOp_GreaterThan; + case BfToken_LChevron: + return BfBinaryOp_LessThan; + case BfToken_GreaterEquals: + return BfBinaryOp_GreaterThanOrEqual; + case BfToken_LessEquals: + return BfBinaryOp_LessThanOrEqual; + case BfToken_Spaceship: + return BfBinaryOp_Compare; + case BfToken_DblAmpersand: + return BfBinaryOp_ConditionalAnd; + case BfToken_DblBar: + return BfBinaryOp_ConditionalOr; + case BfToken_DblQuestion: + return BfBinaryOp_NullCoalesce; + default: + return BfBinaryOp_None; + } +} + +BfUnaryOp Beefy::BfTokenToUnaryOp(BfToken token) +{ + switch (token) + { + case BfToken_Star: + return BfUnaryOp_Dereference; + case BfToken_Ampersand: + return BfUnaryOp_AddressOf; + case BfToken_Minus: + return BfUnaryOp_Negate; + case BfToken_Bang: + return BfUnaryOp_Not; + case BfToken_Plus: + return BfUnaryOp_Positive; + case BfToken_Tilde: + return BfUnaryOp_InvertBits; + case BfToken_DblPlus: + return BfUnaryOp_Increment; + case BfToken_DblMinus: + return BfUnaryOp_Decrement; + case BfToken_Ref: + return BfUnaryOp_Ref; + case BfToken_Mut: + return BfUnaryOp_Mut; + case BfToken_Out: + return BfUnaryOp_Out; + case BfToken_Params: + return BfUnaryOp_Params; + default: + return BfUnaryOp_None; + } +} + + +BfAssignmentOp Beefy::BfTokenToAssignmentOp(BfToken token) +{ + switch (token) + { + case BfToken_AssignEquals: + return BfAssignmentOp_Assign; + case BfToken_PlusEquals: + return BfAssignmentOp_Add; + case BfToken_MinusEquals: + return BfAssignmentOp_Subtract; + case BfToken_MultiplyEquals: + return BfAssignmentOp_Multiply; + case BfToken_DivideEquals: + return BfAssignmentOp_Divide; + case BfToken_ModulusEquals: + return BfAssignmentOp_Modulus; + case BfToken_ShiftLeftEquals: + return BfAssignmentOp_ShiftLeft; + case BfToken_ShiftRightEquals: + return BfAssignmentOp_ShiftRight; + case BfToken_AndEquals: + return BfAssignmentOp_BitwiseAnd; + case BfToken_OrEquals: + return BfAssignmentOp_BitwiseOr; + case BfToken_XorEquals: + return BfAssignmentOp_ExclusiveOr; + default: + return BfAssignmentOp_None; + } +} + +BfBinaryOp Beefy::BfGetOppositeBinaryOp(BfBinaryOp origOp) +{ + switch (origOp) + { + case BfBinaryOp_Equality: + return BfBinaryOp_InEquality; + case BfBinaryOp_InEquality: + return BfBinaryOp_Equality; + case BfBinaryOp_LessThan: + return BfBinaryOp_GreaterThanOrEqual; + case BfBinaryOp_LessThanOrEqual: + return BfBinaryOp_GreaterThan; + case BfBinaryOp_GreaterThan: + return BfBinaryOp_LessThanOrEqual; + case BfBinaryOp_GreaterThanOrEqual: + return BfBinaryOp_LessThan; + default: break; + } + + return BfBinaryOp_None; +} + +BfBinaryOp Beefy::BfGetFlippedBinaryOp(BfBinaryOp origOp) +{ + switch (origOp) + { + case BfBinaryOp_Equality: + return BfBinaryOp_Equality; + case BfBinaryOp_InEquality: + return BfBinaryOp_InEquality; + case BfBinaryOp_LessThan: + return BfBinaryOp_GreaterThan; + case BfBinaryOp_LessThanOrEqual: + return BfBinaryOp_GreaterThanOrEqual; + case BfBinaryOp_GreaterThan: + return BfBinaryOp_LessThan; + case BfBinaryOp_GreaterThanOrEqual: + return BfBinaryOp_LessThanOrEqual; + default: break; + } + + return BfBinaryOp_None; +} + + BfInlineAsmInstruction::AsmArg::AsmArg() : mType(ARGTYPE_Immediate) , mMemFlags(0) diff --git a/IDEHelper/Compiler/BfAst.h b/IDEHelper/Compiler/BfAst.h index 50f592fd..28c618d7 100644 --- a/IDEHelper/Compiler/BfAst.h +++ b/IDEHelper/Compiler/BfAst.h @@ -347,6 +347,7 @@ class BfCollectionInitializerExpression; class BfArraySizeSpecifier; class BfSizedArrayCreateExpression; class BfEmptyStatement; +class BfGenericOperatorConstraint; class BfGenericConstraintsDeclaration; class BfAttributeDirective; class BfNullableTypeRef; @@ -409,6 +410,7 @@ public: virtual void Visit(BfAttributeDirective* attributeDirective); virtual void Visit(BfGenericParamsDeclaration* genericParams); + virtual void Visit(BfGenericOperatorConstraint* genericConstraints); virtual void Visit(BfGenericConstraintsDeclaration* genericConstraints); virtual void Visit(BfGenericArgumentsNode* genericArgumentsNode); @@ -2762,15 +2764,26 @@ public: BfTokenNode* mRight; }; BF_AST_DECL(BfTokenPairNode, BfAstNode); +class BfGenericOperatorConstraint : public BfAstNode +{ +public: + BF_AST_TYPE(BfGenericOperatorConstraint, BfAstNode); + + BfTokenNode* mOperatorToken; + BfTypeReference* mLeftType; + BfTokenNode* mOpToken; + BfTypeReference* mRightType; +}; BF_AST_DECL(BfGenericOperatorConstraint, BfAstNode); + class BfGenericConstraint : public BfAstNode { public: BF_AST_TYPE(BfGenericConstraint, BfAstNode); - BfTokenNode* mWhereToken; - BfIdentifierNode* mGenericParamName; + BfTokenNode* mWhereToken; + BfTypeReference* mTypeRef; BfTokenNode* mColonToken; - BfSizedArray mConstraintTypes; + BfSizedArray mConstraintTypes; BfSizedArray mCommas; }; BF_AST_DECL(BfGenericConstraint, BfAstNode); @@ -2778,7 +2791,7 @@ class BfGenericConstraintsDeclaration : public BfAstNode { public: BF_AST_TYPE(BfGenericConstraintsDeclaration, BfAstNode); - BfSizedArray mGenericConstraints; + BfSizedArray mGenericConstraints; }; BF_AST_DECL(BfGenericConstraintsDeclaration, BfAstNode); class BfMethodDeclaration : public BfMemberDeclaration @@ -3171,8 +3184,13 @@ public: const char* BfTokenToString(BfToken token); bool BfTokenIsKeyword(BfToken token); BfBinaryOp BfAssignOpToBinaryOp(BfAssignmentOp assignmentOp); +BfBinaryOp BfGetOppositeBinaryOp(BfBinaryOp origOp); +BfBinaryOp BfGetFlippedBinaryOp(BfBinaryOp origOp); int BfGetBinaryOpPrecendence(BfBinaryOp binOp); const char* BfGetOpName(BfBinaryOp binOp); const char* BfGetOpName(BfUnaryOp unaryOp); +BfBinaryOp BfTokenToBinaryOp(BfToken token); +BfUnaryOp BfTokenToUnaryOp(BfToken token); +BfAssignmentOp BfTokenToAssignmentOp(BfToken token); NS_BF_END \ No newline at end of file diff --git a/IDEHelper/Compiler/BfAutoComplete.cpp b/IDEHelper/Compiler/BfAutoComplete.cpp index e6168b79..0e439b13 100644 --- a/IDEHelper/Compiler/BfAutoComplete.cpp +++ b/IDEHelper/Compiler/BfAutoComplete.cpp @@ -1512,22 +1512,37 @@ bool BfAutoComplete::CheckMemberReference(BfAstNode* target, BfAstNode* dotToken } // Statics, inner types - //bool isStatic = (targetValue.mValue == NULL) && (!targetValue.mType->IsValuelessType()); auto checkType = targetValue.mType; - + if (checkType->IsGenericParam()) { auto genericParamType = (BfGenericParamType*)checkType; - auto genericParamInst = mModule->GetGenericParamInstance(genericParamType); + auto genericParamInstance = mModule->GetGenericParamInstance(genericParamType); - for (auto interfaceConstraint : genericParamInst->mInterfaceConstraints) - AddTypeMembers(interfaceConstraint, false, true, filter, interfaceConstraint, true, false); + auto _HandleGenericParamInstance = [&](BfGenericParamInstance* genericParamInstance) + { + for (auto interfaceConstraint : genericParamInstance->mInterfaceConstraints) + AddTypeMembers(interfaceConstraint, false, true, filter, interfaceConstraint, true, false); - if (genericParamInst->mTypeConstraint != NULL) - checkType = genericParamInst->mTypeConstraint; - else - checkType = mModule->mContext->mBfObjectType; + if (genericParamInstance->mTypeConstraint != NULL) + checkType = genericParamInstance->mTypeConstraint; + else + checkType = mModule->mContext->mBfObjectType; + }; + _HandleGenericParamInstance(genericParamInstance); + + // Check method generic constraints + if ((mModule->mCurMethodInstance != NULL) && (mModule->mCurMethodInstance->mIsUnspecialized) && (mModule->mCurMethodInstance->mMethodInfoEx != NULL)) + { + for (int genericParamIdx = (int)mModule->mCurMethodInstance->mMethodInfoEx->mMethodGenericArguments.size(); + genericParamIdx < mModule->mCurMethodInstance->mMethodInfoEx->mGenericParams.size(); genericParamIdx++) + { + auto genericParam = mModule->mCurMethodInstance->mMethodInfoEx->mGenericParams[genericParamIdx]; + if (genericParam->mExternType == genericParamType) + _HandleGenericParamInstance(genericParam); + } + } } if (checkType->IsPointer()) diff --git a/IDEHelper/Compiler/BfCompiler.cpp b/IDEHelper/Compiler/BfCompiler.cpp index cacf8ca1..ad916084 100644 --- a/IDEHelper/Compiler/BfCompiler.cpp +++ b/IDEHelper/Compiler/BfCompiler.cpp @@ -2697,7 +2697,8 @@ void BfCompiler::GenerateDynCastData() } void BfCompiler::UpdateRevisedTypes() -{ +{ + BfLogSysM("UpdateRevisedTypes\n"); BP_ZONE("BfCompiler::UpdateRevisedTypes"); // See if we have any name conflicts and remove those @@ -3251,13 +3252,25 @@ void BfCompiler::UpdateRevisedTypes() mContext->ValidateDependencies(); } mContext->RemoveInvalidWorkItems(); + + //for (auto typeDef : mSystem->mTypeDefs) + //{ + // auto latestTypeDef = typeDef->GetLatest(); + // if ((latestTypeDef->mOuterType != NULL) && (latestTypeDef->mOuterType->mIsPartial) && (latestTypeDef->mIsCombinedPartial)) + // //((!latestTypeDef->mIsPartial) || (latestTypeDef->mIsCombinedPartial))) + // latestTypeDef->mOuterType = mSystem->GetOuterTypeNonPartial(latestTypeDef); - for (auto typeDef : mSystem->mTypeDefs) - { - auto latestTypeDef = typeDef->GetLatest(); - if ((latestTypeDef->mOuterType != NULL) && (latestTypeDef->mOuterType->mIsPartial)) - latestTypeDef->mOuterType = mSystem->GetOuterTypeNonPartial(latestTypeDef); - } + // /*String fullName = typeDef->mFullNameEx.ToString(); + // if (fullName == "System.Collections.Generic.List`1.Enumerator`1") + // { + // NOP; + // } + + // if ((typeDef->mOuterType != NULL) && (!typeDef->mIsPartial) && (typeDef->mOuterType->mIsPartial) && (!typeDef->mOuterType->mIsCombinedPartial)) + // { + // NOP; + // }*/ + //} mSystem->mNeedsTypesHandledByCompiler = false; @@ -3767,8 +3780,9 @@ void BfCompiler::ProcessAutocompleteTempType() { auto genericParamDef = tempTypeDef->mGenericParamDefs[genericParamIdx]; - auto genericParamInstance = new BfGenericTypeParamInstance(tempTypeDef, genericParamIdx); - module->ResolveGenericParamConstraints(genericParamInstance, tempTypeDef->mGenericParamDefs, genericParamIdx); + auto genericParamInstance = new BfGenericTypeParamInstance(tempTypeDef, genericParamIdx); + genericParamInstance->mExternType = module->GetGenericParamType(BfGenericParamKind_Type, genericParamIdx); + module->ResolveGenericParamConstraints(genericParamInstance, true); delete genericParamInstance; for (auto nameNode : genericParamDef->mNameNodes) @@ -3937,10 +3951,14 @@ void BfCompiler::ProcessAutocompleteTempType() auto genericParamType = module->GetGenericParamType(BfGenericParamKind_Method, genericParamIdx); methodInstance->GetMethodInfoEx()->mMethodGenericArguments.push_back(genericParamType); - auto genericParamInstance = new BfGenericMethodParamInstance(methodDef, genericParamIdx); + auto genericParamInstance = new BfGenericMethodParamInstance(methodDef, genericParamIdx); methodInstance->GetMethodInfoEx()->mGenericParams.push_back(genericParamInstance); + } - //module->ResolveGenericParamConstraints(genericParamInstance, methodDef->mGenericParams[genericParamIdx]); + for (int externConstraintIdx = 0; externConstraintIdx < (int)methodDef->mExternalConstraints.size(); externConstraintIdx++) + { + auto genericParamInstance = new BfGenericMethodParamInstance(methodDef, externConstraintIdx + (int)methodDef->mGenericParams.size()); + methodInstance->GetMethodInfoEx()->mGenericParams.push_back(genericParamInstance); } SetAndRestoreValue prevFilePos(module->mCurFilePosition); @@ -4187,8 +4205,18 @@ void BfCompiler::GetSymbolReferences() for (auto genericParam : checkTypeDef->mGenericParamDefs) { - for (auto constraint : genericParam->mInterfaceConstraints) - module->ResolveTypeRef(constraint, BfPopulateType_Identity); + for (auto constraint : genericParam->mConstraints) + { + if (auto constraintTypeRef = BfNodeDynCast(constraint)) + { + module->ResolveTypeRef(constraintTypeRef, BfPopulateType_Identity); + } + else if (auto opConstraint = BfNodeDynCast(constraint)) + { + module->ResolveTypeRef(opConstraint->mLeftType, BfPopulateType_Identity); + module->ResolveTypeRef(opConstraint->mRightType, BfPopulateType_Identity); + } + } } } } @@ -4230,8 +4258,6 @@ void BfCompiler::GetSymbolReferences() BfGenericTypeParamInstance genericParamInstance(genericTypeInstance->mTypeDef, genericParamIdx); auto genericParamDef = typeDef->mGenericParamDefs[genericParamIdx]; - //BfGenericMethodParamInstance genericParamInstance(rebuildMethodInstance->mMethodDef, genericParamIdx); - if (mResolvePassData->mGetSymbolReferenceKind == BfGetSymbolReferenceKind_TypeGenericParam) { for (auto nameNode : genericParamDef->mNameNodes) @@ -4239,8 +4265,8 @@ void BfCompiler::GetSymbolReferences() mResolvePassData->HandleTypeGenericParam(nameNode, typeDef, genericParamIdx); } - rebuildModule->ResolveGenericParamConstraints(&genericParamInstance, typeDef->mGenericParamDefs, genericParamIdx); - } + rebuildModule->ResolveGenericParamConstraints(&genericParamInstance, genericTypeInstance->IsGenericTypeInstance()); + } } } @@ -4372,7 +4398,7 @@ void BfCompiler::GetSymbolReferences() } if (rebuildMethodInstance->mIgnoreBody) - { + { auto methodDeclaration = methodDef->GetMethodDeclaration(); if (methodDeclaration != NULL) mResolvePassData->HandleMethodReference(methodDeclaration->mNameNode, typeDef, methodDef); @@ -4436,7 +4462,15 @@ void BfCompiler::GetSymbolReferences() mResolvePassData->HandleMethodGenericParam(nameNode, typeDef, methodDef, genericParamIdx); } - rebuildModule->ResolveGenericParamConstraints(&genericParamInstance, methodDef->mGenericParams, genericParamIdx); + rebuildModule->ResolveGenericParamConstraints(&genericParamInstance, rebuildMethodInstance->mIsUnspecialized); + } + + for (int externConstraintIdx = 0; externConstraintIdx < (int)methodDef->mExternalConstraints.size(); externConstraintIdx++) + { + BfGenericMethodParamInstance genericParamInstance(rebuildMethodInstance->mMethodDef, externConstraintIdx + (int)methodDef->mGenericParams.size()); + auto& externConstraintDef = methodDef->mExternalConstraints[externConstraintIdx]; + CheckSymbolReferenceTypeRef(module, externConstraintDef.mTypeRef); + rebuildModule->ResolveGenericParamConstraints(&genericParamInstance, rebuildMethodInstance->mIsUnspecialized); } rebuildModule->ProcessMethod(rebuildMethodInstance); diff --git a/IDEHelper/Compiler/BfDefBuilder.cpp b/IDEHelper/Compiler/BfDefBuilder.cpp index ef00c03d..4d247279 100644 --- a/IDEHelper/Compiler/BfDefBuilder.cpp +++ b/IDEHelper/Compiler/BfDefBuilder.cpp @@ -181,7 +181,7 @@ bool BfDefBuilder::WantsNode(BfAstNode* wholeNode, BfAstNode* startNode, int add static int sGenericParamIdx = 0; -void BfDefBuilder::ParseGenericParams(BfGenericParamsDeclaration* genericParamsDecl, BfGenericConstraintsDeclaration* genericConstraints, Array& genericParams, int outerGenericSize) +void BfDefBuilder::ParseGenericParams(BfGenericParamsDeclaration* genericParamsDecl, BfGenericConstraintsDeclaration* genericConstraints, Array& genericParams, Array* externConstraintDefs, int outerGenericSize) { if (genericParamsDecl != NULL) { @@ -203,7 +203,7 @@ void BfDefBuilder::ParseGenericParams(BfGenericParamsDeclaration* genericParamsD while (checkTypeDef != NULL) { if (&genericParams != &checkTypeDef->mGenericParamDefs) - { + { for (int checkParamsIdx = 0; checkParamsIdx < (int)checkTypeDef->mGenericParamDefs.size(); checkParamsIdx++) { if (checkTypeDef->mGenericParamDefs[checkParamsIdx]->mName == name) @@ -228,30 +228,53 @@ void BfDefBuilder::ParseGenericParams(BfGenericParamsDeclaration* genericParamsD if (genericConstraints == NULL) return; - for (BfGenericConstraint* genericConstraint : genericConstraints->mGenericConstraints) + for (BfAstNode* genericConstraintNode : genericConstraints->mGenericConstraints) { - if (genericConstraint->mGenericParamName == NULL) + auto genericConstraint = BfNodeDynCast(genericConstraintNode); + if (genericConstraint == NULL) + continue; + if (genericConstraint->mTypeRef == NULL) continue; - String findName = genericConstraint->mGenericParamName->ToString(); + BfIdentifierNode* nameNode = NULL; BfGenericParamDef* genericParamDef = NULL; - for (int genericParamIdx = outerGenericSize; genericParamIdx < (int) genericParams.size(); genericParamIdx++) + if (auto namedTypeRef = BfNodeDynCast(genericConstraint->mTypeRef)) { - auto checkGenericParam = genericParams[genericParamIdx]; - if (checkGenericParam->mName == findName) - genericParamDef = checkGenericParam; + nameNode = namedTypeRef->mNameNode; + String findName = nameNode->ToString(); + for (int genericParamIdx = outerGenericSize; genericParamIdx < (int)genericParams.size(); genericParamIdx++) + { + auto checkGenericParam = genericParams[genericParamIdx]; + if (checkGenericParam->mName == findName) + genericParamDef = checkGenericParam; + } } + + BfConstraintDef* constraintDef = genericParamDef; + if (genericParamDef == NULL) { - mPassInstance->Fail("Cannot find generic parameter in constraint", genericConstraint->mGenericParamName); + if (externConstraintDefs == NULL) + { + mPassInstance->Fail("Cannot find generic parameter in constraint", genericConstraint->mTypeRef); - if (genericParams.IsEmpty()) - continue; + if (genericParams.IsEmpty()) + continue; - genericParamDef = genericParams[0]; + genericParamDef = genericParams[0]; + constraintDef = genericParamDef; + } + else + { + externConstraintDefs->Add(BfExternalConstraintDef()); + BfExternalConstraintDef* externConstraintDef = &externConstraintDefs->back(); + externConstraintDef->mTypeRef = genericConstraint->mTypeRef; + constraintDef = externConstraintDef; + } } - else - genericParamDef->mNameNodes.Add(genericConstraint->mGenericParamName); + + if (genericParamDef != NULL) + genericParamDef->mNameNodes.Add(nameNode); for (BfAstNode* constraintNode : genericConstraint->mConstraintTypes) { @@ -266,11 +289,13 @@ void BfDefBuilder::ParseGenericParams(BfGenericParamsDeclaration* genericParamsD name = tokenPairNode->mLeft->ToString() + tokenPairNode->mRight->ToString(); } + bool hasEquals = (genericConstraint->mColonToken != NULL) && (genericConstraint->mColonToken->mToken == BfToken_AssignEquals); + if (!name.empty()) { if ((name == "class") || (name == "struct") || (name == "struct*") || (name == "const") || (name == "var")) { - int prevFlags = genericParamDef->mGenericParamFlags & (BfGenericParamFlag_Class | BfGenericParamFlag_Struct | BfGenericParamFlag_StructPtr); + int prevFlags = constraintDef->mGenericParamFlags & (BfGenericParamFlag_Class | BfGenericParamFlag_Struct | BfGenericParamFlag_StructPtr); if (prevFlags != 0) { String prevFlagName; @@ -289,38 +314,57 @@ void BfDefBuilder::ParseGenericParams(BfGenericParamsDeclaration* genericParamsD } if (name == "class") - genericParamDef->mGenericParamFlags = (BfGenericParamFlags)(genericParamDef->mGenericParamFlags | BfGenericParamFlag_Class); + constraintDef->mGenericParamFlags = (BfGenericParamFlags)(constraintDef->mGenericParamFlags | BfGenericParamFlag_Class); else if (name == "struct") - genericParamDef->mGenericParamFlags = (BfGenericParamFlags)(genericParamDef->mGenericParamFlags | BfGenericParamFlag_Struct); + constraintDef->mGenericParamFlags = (BfGenericParamFlags)(constraintDef->mGenericParamFlags | BfGenericParamFlag_Struct); else if (name == "struct*") - genericParamDef->mGenericParamFlags = (BfGenericParamFlags)(genericParamDef->mGenericParamFlags | BfGenericParamFlag_StructPtr); + constraintDef->mGenericParamFlags = (BfGenericParamFlags)(constraintDef->mGenericParamFlags | BfGenericParamFlag_StructPtr); else if (name == "const") - genericParamDef->mGenericParamFlags = (BfGenericParamFlags)(genericParamDef->mGenericParamFlags | BfGenericParamFlag_Const); + constraintDef->mGenericParamFlags = (BfGenericParamFlags)(constraintDef->mGenericParamFlags | BfGenericParamFlag_Const); else //if (name == "var") - genericParamDef->mGenericParamFlags = (BfGenericParamFlags)(genericParamDef->mGenericParamFlags | BfGenericParamFlag_Var); + constraintDef->mGenericParamFlags = (BfGenericParamFlags)(constraintDef->mGenericParamFlags | BfGenericParamFlag_Var); continue; } else if (name == "new") { - genericParamDef->mGenericParamFlags = (BfGenericParamFlags)(genericParamDef->mGenericParamFlags | BfGenericParamFlag_New); + constraintDef->mGenericParamFlags = (BfGenericParamFlags)(constraintDef->mGenericParamFlags | BfGenericParamFlag_New); continue; } else if (name == "delete") { - genericParamDef->mGenericParamFlags = (BfGenericParamFlags)(genericParamDef->mGenericParamFlags | BfGenericParamFlag_Delete); + constraintDef->mGenericParamFlags = (BfGenericParamFlags)(constraintDef->mGenericParamFlags | BfGenericParamFlag_Delete); continue; } } - auto constraintType = BfNodeDynCast(constraintNode); - if (constraintType == NULL) + if (auto genericOpConstraint = BfNodeDynCast(constraintNode)) { - mPassInstance->Fail("Invalid constraint", constraintNode); - return; + // Ok } + else + { + auto constraintType = BfNodeDynCast(constraintNode); + if (constraintType == NULL) + { + mPassInstance->Fail("Invalid constraint", constraintNode); + return; + } + } + + if (hasEquals) + { + if (constraintDef->mConstraints.IsEmpty()) + { + constraintDef->mGenericParamFlags = (BfGenericParamFlags)(constraintDef->mGenericParamFlags | BfGenericParamFlag_Equals); + } + else + { + mPassInstance->Fail("Type assignment must be the first constraint", genericConstraint->mColonToken); + } + } - genericParamDef->mInterfaceConstraints.push_back(constraintType); + constraintDef->mConstraints.Add(constraintNode); } } } @@ -538,7 +582,7 @@ BfMethodDef* BfDefBuilder::CreateMethodDef(BfMethodDeclaration* methodDeclaratio int outerGenericSize = 0; if (outerMethodDef != NULL) outerGenericSize = (int)outerMethodDef->mGenericParams.size(); - ParseGenericParams(methodDeclaration->mGenericParams, methodDeclaration->mGenericConstraintsDeclaration, methodDef->mGenericParams, outerGenericSize); + ParseGenericParams(methodDeclaration->mGenericParams, methodDeclaration->mGenericConstraintsDeclaration, methodDef->mGenericParams, &methodDef->mExternalConstraints, outerGenericSize); bool didDefaultsError = false; bool hadParams = false; @@ -623,13 +667,25 @@ void BfDefBuilder::Visit(BfMethodDeclaration* methodDeclaration) } auto methodDef = CreateMethodDef(methodDeclaration); - if (methodDef->mMethodType == BfMethodType_Operator) - { - mCurTypeDef->mOperators.push_back((BfOperatorDef*)methodDef); - } + methodDef->mWantsBody = wantsBody; + if (methodDef->mMethodType == BfMethodType_Operator) + mCurTypeDef->mOperators.push_back((BfOperatorDef*)methodDef); mCurTypeDef->mMethods.push_back(methodDef); - methodDef->mWantsBody = wantsBody; + if (methodDef->mCommutableKind == BfCommutableKind_Forward) + { + auto revMethodDef = CreateMethodDef(methodDeclaration); + revMethodDef->mWantsBody = wantsBody; + if (revMethodDef->mMethodType == BfMethodType_Operator) + mCurTypeDef->mOperators.push_back((BfOperatorDef*)revMethodDef); + + if (revMethodDef->mParams.size() >= 2) + { + BF_SWAP(revMethodDef->mParams[0], revMethodDef->mParams[1]); + } + revMethodDef->mCommutableKind = BfCommutableKind_Reverse; + mCurTypeDef->mMethods.push_back(revMethodDef); + } } void BfDefBuilder::ParseAttributes(BfAttributeDirective* attributes, BfMethodDef* methodDef) @@ -647,7 +703,7 @@ void BfDefBuilder::ParseAttributes(BfAttributeDirective* attributes, BfMethodDef else if (typeRefName == "CVarArgs") methodDef->mCallingConvention = BfCallingConvention_CVarArgs; else if (typeRefName == "Inline") - methodDef->mAlwaysInline = true; + methodDef->mAlwaysInline = true; else if (typeRefName == "AllowAppend") methodDef->mHasAppend = true; else if (typeRefName == "Checked") @@ -655,12 +711,12 @@ void BfDefBuilder::ParseAttributes(BfAttributeDirective* attributes, BfMethodDef else if (typeRefName == "Unchecked") methodDef->mCheckedKind = BfCheckedKind_Unchecked; else if (typeRefName == "Export") - { + { mCurTypeDef->mIsAlwaysInclude = true; - methodDef->mImportKind = BfImportKind_Export; + methodDef->mImportKind = BfImportKind_Export; } else if (typeRefName == "Import") - { + { methodDef->mImportKind = BfImportKind_Static; if (!attributes->mArguments.IsEmpty()) { @@ -677,7 +733,7 @@ void BfDefBuilder::ParseAttributes(BfAttributeDirective* attributes, BfMethodDef } } } - } + } } else if (typeRefName == "NoReturn") methodDef->mNoReturn = true; @@ -687,6 +743,17 @@ void BfDefBuilder::ParseAttributes(BfAttributeDirective* attributes, BfMethodDef methodDef->mIsNoShow = true; else if (typeRefName == "NoDiscard") methodDef->mIsNoDiscard = true; + else if (typeRefName == "Commutable") + { + if (methodDef->mParams.size() != 2) + { + mPassInstance->Fail("Commutable attributes can only be applied to methods with two arguments", attributes->mAttributeTypeRef); + } + else + { + methodDef->mCommutableKind = BfCommutableKind_Forward; + } + } } attributes = attributes->mNextAttribute; @@ -1304,7 +1371,7 @@ void BfDefBuilder::Visit(BfTypeDeclaration* typeDeclaration) BfGenericParamDef* copiedGenericParamDef = new BfGenericParamDef(); *copiedGenericParamDef = *outerGenericParamDef; mCurTypeDef->mGenericParamDefs.Add(copiedGenericParamDef); - } + } BfTypeDef* parentType = outerTypeDef; while (parentType != NULL) @@ -1521,7 +1588,7 @@ void BfDefBuilder::Visit(BfTypeDeclaration* typeDeclaration) int outerGenericSize = 0; if (mCurTypeDef->mOuterType != NULL) outerGenericSize = (int)mCurTypeDef->mOuterType->mGenericParamDefs.size(); - ParseGenericParams(typeDeclaration->mGenericParams, typeDeclaration->mGenericConstraintsDeclaration, mCurTypeDef->mGenericParamDefs, outerGenericSize); + ParseGenericParams(typeDeclaration->mGenericParams, typeDeclaration->mGenericConstraintsDeclaration, mCurTypeDef->mGenericParamDefs, NULL, outerGenericSize); BF_ASSERT(mCurTypeDef->mNameEx == NULL); diff --git a/IDEHelper/Compiler/BfDefBuilder.h b/IDEHelper/Compiler/BfDefBuilder.h index 573304cb..f9756c89 100644 --- a/IDEHelper/Compiler/BfDefBuilder.h +++ b/IDEHelper/Compiler/BfDefBuilder.h @@ -27,7 +27,7 @@ public: HashContext* mSignatureHashCtx; public: - void ParseGenericParams(BfGenericParamsDeclaration* genericParamsDecl, BfGenericConstraintsDeclaration* genericConstraints, Array& genericParams, int outerGenericSize); + void ParseGenericParams(BfGenericParamsDeclaration* genericParamsDecl, BfGenericConstraintsDeclaration* genericConstraints, Array& genericParams, Array* externConstraintDefs, int outerGenericSize); BfProtection GetProtection(BfTokenNode* protectionToken); bool WantsNode(BfAstNode* wholeNode, BfAstNode* startNode = NULL, int addLen = 0); //static BfNamedTypeReference* AllocTypeReference(BfSource* bfSource, const StringImpl& typeName); diff --git a/IDEHelper/Compiler/BfElementVisitor.cpp b/IDEHelper/Compiler/BfElementVisitor.cpp index c1e17bbc..647ed0fb 100644 --- a/IDEHelper/Compiler/BfElementVisitor.cpp +++ b/IDEHelper/Compiler/BfElementVisitor.cpp @@ -69,19 +69,29 @@ void BfElementVisitor::Visit(BfGenericParamsDeclaration* genericParams) VisitChild(genericParams->mCloseChevron); } +void BfElementVisitor::Visit(BfGenericOperatorConstraint* genericConstraints) +{ + Visit(genericConstraints->ToBase()); + + VisitChild(genericConstraints->mOperatorToken); + VisitChild(genericConstraints->mLeftType); + VisitChild(genericConstraints->mOpToken); + VisitChild(genericConstraints->mRightType); +} + void BfElementVisitor::Visit(BfGenericConstraintsDeclaration* genericConstraints) { Visit(genericConstraints->ToBase()); for (auto genericConstraint : genericConstraints->mGenericConstraints) - { + { VisitChild(genericConstraint->mWhereToken); - VisitChild(genericConstraint->mGenericParamName); + VisitChild(genericConstraint->mTypeRef); VisitChild(genericConstraint->mColonToken); for (auto val : genericConstraint->mConstraintTypes) VisitChild(val); for (auto val : genericConstraint->mCommas) - VisitChild(val); + VisitChild(val); } } diff --git a/IDEHelper/Compiler/BfElementVisitor.h b/IDEHelper/Compiler/BfElementVisitor.h index d037bb48..d14d81d8 100644 --- a/IDEHelper/Compiler/BfElementVisitor.h +++ b/IDEHelper/Compiler/BfElementVisitor.h @@ -28,6 +28,7 @@ public: virtual void Visit(BfAttributeDirective* attributeDirective); virtual void Visit(BfGenericParamsDeclaration* genericParams); + virtual void Visit(BfGenericOperatorConstraint* genericConstraints); virtual void Visit(BfGenericConstraintsDeclaration* genericConstraints); virtual void Visit(BfGenericArgumentsNode* genericArgumentsNode); diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 2af61df8..c6910bc9 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -26,50 +26,6 @@ USING_NS_BF; using namespace llvm; -static BfBinaryOp GetOppositeBinaryOp(BfBinaryOp origOp) -{ - switch (origOp) - { - case BfBinaryOp_Equality: - return BfBinaryOp_InEquality; - case BfBinaryOp_InEquality: - return BfBinaryOp_Equality; - case BfBinaryOp_LessThan: - return BfBinaryOp_GreaterThanOrEqual; - case BfBinaryOp_LessThanOrEqual: - return BfBinaryOp_GreaterThan; - case BfBinaryOp_GreaterThan: - return BfBinaryOp_LessThanOrEqual; - case BfBinaryOp_GreaterThanOrEqual: - return BfBinaryOp_LessThan; - default: break; - } - - return BfBinaryOp_None; -} - -static BfBinaryOp GetFlippedBinaryOp(BfBinaryOp origOp) -{ - switch (origOp) - { - case BfBinaryOp_Equality: - return BfBinaryOp_Equality; - case BfBinaryOp_InEquality: - return BfBinaryOp_InEquality; - case BfBinaryOp_LessThan: - return BfBinaryOp_GreaterThan; - case BfBinaryOp_LessThanOrEqual: - return BfBinaryOp_GreaterThanOrEqual; - case BfBinaryOp_GreaterThan: - return BfBinaryOp_LessThan; - case BfBinaryOp_GreaterThanOrEqual: - return BfBinaryOp_LessThanOrEqual; - default: break; - } - - return BfBinaryOp_None; -} - ////////////////////////////////////////////////////////////////////////// DeferredTupleAssignData::~DeferredTupleAssignData() @@ -197,6 +153,7 @@ BfMethodMatcher::BfMethodMatcher(BfAstNode* targetSrc, BfModule* module, BfMetho void BfMethodMatcher::Init(/*SizedArrayImpl& arguments, */BfSizedArray* methodGenericArguments) { //mArguments = arguments; + mActiveTypeDef = NULL; mBestMethodDef = NULL; mBackupMethodDef = NULL; mBestMethodTypeInstance = NULL; @@ -237,6 +194,22 @@ void BfMethodMatcher::Init(/*SizedArrayImpl& arguments, */BfSized } } +bool BfMethodMatcher::IsMemberAccessible(BfTypeInstance* typeInst, BfTypeDef* declaringType) +{ + if (mActiveTypeDef == NULL) + mActiveTypeDef = mModule->GetActiveTypeDef(); + if (!typeInst->IsTypeMemberIncluded(declaringType, mActiveTypeDef, mModule)) + return false; + + // This may not be completely correct - BUT if we don't have this then even Dictionary TKey's operator == won't be considered accessible + if (!mModule->IsInSpecializedSection()) + { + if (!typeInst->IsTypeMemberAccessible(declaringType, mActiveTypeDef)) + return false; + } + return true; +} + bool BfMethodMatcher::InferGenericArgument(BfMethodInstance* methodInstance, BfType* argType, BfType* wantType, BfIRValue argValue) { if (argType == NULL) @@ -828,7 +801,8 @@ void BfMethodMatcher::CompareMethods(BfMethodInstance* prevMethodInstance, BfTyp } } - RETURN_BETTER_OR_WORSE(newMethodDef->mCheckedKind == mCheckedKind, prevMethodDef->mCheckedKind == mCheckedKind); + RETURN_BETTER_OR_WORSE(newMethodDef->mCheckedKind == mCheckedKind, prevMethodDef->mCheckedKind == mCheckedKind); + RETURN_BETTER_OR_WORSE(newMethodDef->mCommutableKind != BfCommutableKind_Reverse, prevMethodDef->mCommutableKind != BfCommutableKind_Reverse); RETURN_RESULTS; } @@ -1030,6 +1004,11 @@ bool BfMethodMatcher::CheckMethod(BfTypeInstance* typeInstance, BfMethodDef* che mMethodCheckCount++; BfMethodInstance* methodInstance = mModule->GetRawMethodInstance(typeInstance, checkMethod); + if (methodInstance == NULL) + { + BF_FATAL("Failed to get raw method in BfMethodMatcher::CheckMethod"); + return false; + } if ((mInterfaceMethodInstance != NULL) && (methodInstance->GetExplicitInterface() != NULL)) { @@ -1203,6 +1182,24 @@ bool BfMethodMatcher::CheckMethod(BfTypeInstance* typeInstance, BfMethodDef* che auto& genericArg = mCheckMethodGenericArguments[genericArgIdx]; if (genericArg == NULL) { + auto genericParam = methodInstance->mMethodInfoEx->mGenericParams[genericArgIdx]; + //mModule->CheckGenericConstraints(BfGenericParamSource(), NULL, NULL, genericParam, &mCheckMethodGenericArguments, NULL); + if (genericArg != NULL) + continue; + +// if ((genericParam->mGenericParamFlags & BfGenericParamFlag_Equals) != 0) +// { +// if ((genericParam->mGenericParamFlags & BfGenericParamFlag_Equals_Op) != 0) +// { +// +// } +// +// else if ((genericParam->mGenericParamFlags & BfGenericParamFlag_Equals_Type) != 0) +// { +// +// } +// } + if (!allowEmptyGenericSet.Contains(genericArgIdx)) goto NoMatch; } @@ -1944,7 +1941,7 @@ void BfResolvedArgs::HandleFixits(BfModule* module) BfExprEvaluator::BfExprEvaluator(BfModule* module) { mBfEvalExprFlags = BfEvalExprFlags_None; - mModule = module; + mModule = module; mPropDef = NULL; mPropSrc = NULL; mPropGetMethodFlags = BfGetMethodInstanceFlag_None; @@ -6009,22 +6006,39 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp else if (lookupType->IsGenericParam()) { auto genericParamTarget = (BfGenericParamType*)lookupType; - auto genericParamInstance = mModule->GetGenericParamInstance(genericParamTarget); - if (genericParamInstance->mTypeConstraint != NULL) - lookupTypeInst = genericParamInstance->mTypeConstraint->ToTypeInstance(); - else - lookupTypeInst = mModule->mContext->mBfObjectType; - - for (BfType* ifaceInst : genericParamInstance->mInterfaceConstraints) + auto _HandleGenericParamInstance = [&](BfGenericParamInstance* genericParamInstance) { - if (ifaceInst->IsUnspecializedType()) - ifaceInst = mModule->ResolveType(ifaceInst); + if (genericParamInstance->mTypeConstraint != NULL) + lookupTypeInst = genericParamInstance->mTypeConstraint->ToTypeInstance(); + else + lookupTypeInst = mModule->mContext->mBfObjectType; - BfTypeInstance* typeInst = ifaceInst->ToTypeInstance(); - BF_ASSERT(typeInst != NULL); - if (methodMatcher.CheckType(typeInst, target, false)) - methodMatcher.mSelfType = lookupType; + for (BfType* ifaceInst : genericParamInstance->mInterfaceConstraints) + { + if (ifaceInst->IsUnspecializedType()) + ifaceInst = mModule->ResolveType(ifaceInst); + + BfTypeInstance* typeInst = ifaceInst->ToTypeInstance(); + BF_ASSERT(typeInst != NULL); + if (methodMatcher.CheckType(typeInst, target, false)) + methodMatcher.mSelfType = lookupType; + } + }; + + auto genericParamInstance = mModule->GetGenericParamInstance(genericParamTarget); + _HandleGenericParamInstance(genericParamInstance); + + // Check method generic constraints + if ((mModule->mCurMethodInstance != NULL) && (mModule->mCurMethodInstance->mIsUnspecialized) && (mModule->mCurMethodInstance->mMethodInfoEx != NULL)) + { + for (int genericParamIdx = (int)mModule->mCurMethodInstance->mMethodInfoEx->mMethodGenericArguments.size(); + genericParamIdx < mModule->mCurMethodInstance->mMethodInfoEx->mGenericParams.size(); genericParamIdx++) + { + auto genericParam = mModule->mCurMethodInstance->mMethodInfoEx->mGenericParams[genericParamIdx]; + if (genericParam->mExternType == lookupType) + _HandleGenericParamInstance(genericParam); + } } } } @@ -11736,11 +11750,11 @@ BfModuleMethodInstance BfExprEvaluator::GetSelectedMethod(BfAstNode* targetSrc, auto genericArg = methodMatcher.mBestMethodGenericArguments[checkGenericIdx]; if (genericArg->IsVar()) continue; - if (genericArg->IsPrimitiveType()) + /*if (genericArg->IsPrimitiveType()) { auto primType = (BfPrimitiveType*)genericArg; genericArg = mModule->GetPrimitiveStructType(primType->mTypeDef->mTypeCode); - } + }*/ BfAstNode* paramSrc; if (methodMatcher.mBestMethodGenericArgumentSrcs.size() == 0) @@ -15506,6 +15520,9 @@ void BfExprEvaluator::Visit(BfIndexerExpression* indexerExpr) if ((!isFailurePass) && (!methodMatcher.WantsCheckMethod(protectionCheckFlags, startCheckTypeInst, curCheckType, checkMethod))) continue; + if (!methodMatcher.IsMemberAccessible(curCheckType, checkMethod->mDeclaringType)) + continue; + methodMatcher.mCheckedKind = checkedKind; methodMatcher.CheckMethod(curCheckType, checkMethod, false); @@ -15794,10 +15811,17 @@ void BfExprEvaluator::PerformUnaryOperation(BfExpression* unaryOpExpr, BfUnaryOp break; default: mExpectingType = NULL; - } - VisitChild(unaryOpExpr); + } + VisitChild(unaryOpExpr); mExpectingType = prevExpedcting; } + + + BfExprEvaluator::PerformUnaryOperation_OnResult(unaryOpExpr, unaryOp, opToken); +} + +void BfExprEvaluator::PerformUnaryOperation_OnResult(BfExpression* unaryOpExpr, BfUnaryOp unaryOp, BfTokenNode* opToken) +{ BfAstNode* propSrc = mPropSrc; BfTypedValue propTarget = mPropTarget; BfPropertyDef* propDef = mPropDef; @@ -15806,7 +15830,7 @@ void BfExprEvaluator::PerformUnaryOperation(BfExpression* unaryOpExpr, BfUnaryOp GetResult(); if (!mResult) - return; + return; if (mResult.mType->IsRef()) mResult.mType = mResult.mType->GetUnderlyingType(); @@ -15851,12 +15875,17 @@ void BfExprEvaluator::PerformUnaryOperation(BfExpression* unaryOpExpr, BfUnaryOp for (auto operatorDef : checkType->mTypeDef->mOperators) { if (operatorDef->mOperatorDeclaration->mUnaryOp == findOp) + { + if (!methodMatcher.IsMemberAccessible(checkType, operatorDef->mDeclaringType)) + continue; if (methodMatcher.CheckMethod(checkType, operatorDef, false)) methodMatcher.mSelfType = entry.mSrcType; + } } } + if (methodMatcher.mBestMethodDef != NULL) - { + { if (!baseClassWalker.mMayBeFromInterface) mModule->SetElementType(opToken, BfSourceElementType_Method); @@ -15883,6 +15912,47 @@ void BfExprEvaluator::PerformUnaryOperation(BfExpression* unaryOpExpr, BfUnaryOp mResult = args[0].mTypedValue; return; } + + // Check method generic constraints + if ((mModule->mCurMethodInstance != NULL) && (mModule->mCurMethodInstance->mIsUnspecialized) && (mModule->mCurMethodInstance->mMethodInfoEx != NULL)) + { + for (int genericParamIdx = 0; genericParamIdx < mModule->mCurMethodInstance->mMethodInfoEx->mGenericParams.size(); genericParamIdx++) + { + auto genericParam = mModule->mCurMethodInstance->mMethodInfoEx->mGenericParams[genericParamIdx]; + for (auto& opConstraint : genericParam->mOperatorConstraints) + { + if (opConstraint.mUnaryOp == findOp) + { + if (mModule->CanImplicitlyCast(args[0].mTypedValue, opConstraint.mRightType)) + { + mResult = BfTypedValue(mModule->mBfIRBuilder->GetFakeVal(), genericParam->mExternType); + return; + } + } + } + } + } + + // Check type generic constraints + if ((mModule->mCurTypeInstance->IsGenericTypeInstance()) && (mModule->mCurTypeInstance->IsUnspecializedType())) + { + auto genericTypeInst = (BfGenericTypeInstance*)mModule->mCurTypeInstance; + for (int genericParamIdx = 0; genericParamIdx < genericTypeInst->mGenericParams.size(); genericParamIdx++) + { + auto genericParam = mModule->GetGenericTypeParamInstance(genericParamIdx); + for (auto& opConstraint : genericParam->mOperatorConstraints) + { + if (opConstraint.mUnaryOp == findOp) + { + if (mModule->CanImplicitlyCast(args[0].mTypedValue, opConstraint.mRightType)) + { + mResult = BfTypedValue(mModule->mBfIRBuilder->GetFakeVal(), genericParam->mExternType); + return; + } + } + } + } + } } bool numericFail = false; @@ -16612,7 +16682,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod } else if ((leftValue.mValue.IsConst()) && (!rightValue.mValue.IsConst())) { - if (CheckConstCompare(GetOppositeBinaryOp(binaryOp), opToken, rightValue, leftValue)) + if (CheckConstCompare(BfGetOppositeBinaryOp(binaryOp), opToken, rightValue, leftValue)) return; } @@ -16914,7 +16984,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod bool invertResult = false; - BfBinaryOp oppositeBinaryOp = GetOppositeBinaryOp(findBinaryOp); + BfBinaryOp oppositeBinaryOp = BfGetOppositeBinaryOp(findBinaryOp); while (true) { @@ -16935,6 +17005,10 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod if (allowOp) { foundOp = true; + + if (!methodMatcher.IsMemberAccessible(checkType, operatorDef->mDeclaringType)) + continue; + if (methodMatcher.CheckMethod(checkType, operatorDef, false)) { methodMatcher.mSelfType = entry.mSrcType; @@ -17006,7 +17080,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod auto useBinaryOp = binaryOp; if (pass == 1) - useBinaryOp = GetFlippedBinaryOp(useBinaryOp); + useBinaryOp = BfGetFlippedBinaryOp(useBinaryOp); auto boolType = mModule->GetPrimitiveType(BfTypeCode_Boolean); switch (useBinaryOp) @@ -17036,19 +17110,57 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod return; } + // Check method generic constraints + if ((mModule->mCurMethodInstance != NULL) && (mModule->mCurMethodInstance->mIsUnspecialized) && (mModule->mCurMethodInstance->mMethodInfoEx != NULL)) + { + for (int genericParamIdx = 0; genericParamIdx < mModule->mCurMethodInstance->mMethodInfoEx->mGenericParams.size(); genericParamIdx++) + { + auto genericParam = mModule->mCurMethodInstance->mMethodInfoEx->mGenericParams[genericParamIdx]; + for (auto& opConstraint : genericParam->mOperatorConstraints) + { + if (opConstraint.mBinaryOp == findBinaryOp) + { + if ((mModule->CanImplicitlyCast(args[0].mTypedValue, opConstraint.mLeftType)) && + (mModule->CanImplicitlyCast(args[1].mTypedValue, opConstraint.mRightType))) + { + BF_ASSERT(genericParam->mExternType != NULL); + mResult = BfTypedValue(mModule->mBfIRBuilder->GetFakeVal(), genericParam->mExternType); + return; + } + } + } + } + } + + // Check type generic constraints + if ((mModule->mCurTypeInstance->IsGenericTypeInstance()) && (mModule->mCurTypeInstance->IsUnspecializedType())) + { + auto genericTypeInst = (BfGenericTypeInstance*)mModule->mCurTypeInstance; + for (int genericParamIdx = 0; genericParamIdx < genericTypeInst->mGenericParams.size(); genericParamIdx++) + { + auto genericParam = mModule->GetGenericTypeParamInstance(genericParamIdx); + for (auto& opConstraint : genericParam->mOperatorConstraints) + { + if (opConstraint.mBinaryOp == findBinaryOp) + { + if ((mModule->CanImplicitlyCast(args[0].mTypedValue, opConstraint.mLeftType)) && + (mModule->CanImplicitlyCast(args[1].mTypedValue, opConstraint.mRightType))) + { + mResult = BfTypedValue(mModule->mBfIRBuilder->GetFakeVal(), genericParam->mExternType); + return; + } + } + } + } + } + if ((!foundOp) || (pass == 1)) break; switch (findBinaryOp) { - case BfBinaryOp_Add: - case BfBinaryOp_Multiply: case BfBinaryOp_Equality: - case BfBinaryOp_InEquality: - case BfBinaryOp_BitwiseAnd: - case BfBinaryOp_BitwiseOr: - case BfBinaryOp_ConditionalAnd: - case BfBinaryOp_ConditionalOr: + case BfBinaryOp_InEquality: case BfBinaryOp_Compare: // Still works break; @@ -17071,7 +17183,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfAstNode* leftExpression, BfAstNod if (findBinaryOp == BfBinaryOp_None) break; - } + } } } diff --git a/IDEHelper/Compiler/BfExprEvaluator.h b/IDEHelper/Compiler/BfExprEvaluator.h index 38167728..a3210dac 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.h +++ b/IDEHelper/Compiler/BfExprEvaluator.h @@ -120,6 +120,7 @@ public: public: BfAstNode* mTargetSrc; BfModule* mModule; + BfTypeDef* mActiveTypeDef; String mMethodName; BfMethodInstance* mInterfaceMethodInstance; SizedArrayImpl& mArguments; @@ -164,6 +165,7 @@ public: BfMethodMatcher(BfAstNode* targetSrc, BfModule* module, const StringImpl& methodName, SizedArrayImpl& arguments, BfSizedArray* methodGenericArguments); BfMethodMatcher(BfAstNode* targetSrc, BfModule* module, BfMethodInstance* interfaceMethodInstance, SizedArrayImpl& arguments, BfSizedArray* methodGenericArguments = NULL); void Init(/*SizedArrayImpl& arguments, */BfSizedArray* methodGenericArguments); + bool IsMemberAccessible(BfTypeInstance* typeInst, BfTypeDef* declaringType); bool CheckType(BfTypeInstance* typeInstance, BfTypedValue target, bool isFailurePass); void CheckOuterTypeStaticMethods(BfTypeInstance* typeInstance, bool isFailurePass); bool WantsCheckMethod(BfProtectionCheckFlags& flags, BfTypeInstance* startTypeInstance, BfTypeInstance* checkTypeInstance, BfMethodDef* methodDef); @@ -379,6 +381,7 @@ public: void VisitLambdaBodies(BfAstNode* body, BfFieldDtorDeclaration* fieldDtor); void FixitAddMember(BfTypeInstance* typeInst, BfType* fieldType, const StringImpl& fieldName, bool isStatic); void PerformUnaryOperation(BfExpression* unaryOpExpr, BfUnaryOp unaryOp, BfTokenNode* opToken); + void PerformUnaryOperation_OnResult(BfExpression* unaryOpExpr, BfUnaryOp unaryOp, BfTokenNode* opToken); void PerformAssignment(BfAssignmentExpression* assignExpr, bool evaluatedLeft, BfTypedValue rightValue, BfTypedValue* outCascadeValue = NULL); void PopulateDeferrredTupleAssignData(BfTupleExpression* tupleExr, DeferredTupleAssignData& deferredTupleAssignData); void AssignDeferrredTupleAssignData(BfAssignmentExpression* assignExpr, DeferredTupleAssignData& deferredTupleAssignData, BfTypedValue rightValue); diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index a9db30ca..0f166d3c 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -2471,7 +2471,7 @@ BfError* BfModule::Fail(const StringImpl& error, BfAstNode* refNode, bool isPers if ((mCurMethodInstance != NULL) && (mCurMethodInstance->mIsUnspecializedVariation)) return NULL; // Ignore errors on unspecialized variations, they are always dups - if (!mHadBuildError) + if (!mHadBuildError) mHadBuildError = true; if (mParentModule != NULL) mParentModule->mHadBuildError = true; @@ -6150,17 +6150,19 @@ BfIRFunction BfModule::GetBuiltInFunc(BfBuiltInFuncType funcTypeId) return mBuiltInFuncs[(int)funcTypeId]; } -void BfModule::ResolveGenericParamConstraints(BfGenericParamInstance* genericParamInstance, const Array& genericParamDefs, int genericParamIdx) -{ - BfGenericParamDef* genericParamDef = genericParamDefs[genericParamIdx]; +void BfModule::ResolveGenericParamConstraints(BfGenericParamInstance* genericParamInstance, bool isUnspecialized) +{ + BfGenericParamDef* genericParamDef = genericParamInstance->GetGenericParamDef(); + BfExternalConstraintDef* externConstraintDef = genericParamInstance->GetExternConstraintDef(); + BfConstraintDef* constraintDef = genericParamInstance->GetConstraintDef(); BfType* startingTypeConstraint = genericParamInstance->mTypeConstraint; BfAutoComplete* bfAutocomplete = NULL; - if (mCompiler->mResolvePassData != NULL) + if ((mCompiler->mResolvePassData != NULL) && (isUnspecialized)) bfAutocomplete = mCompiler->mResolvePassData->mAutoComplete; - if (bfAutocomplete != NULL) + if ((bfAutocomplete != NULL) && (genericParamDef != NULL)) { for (int nameIdx = 0; nameIdx < (int)genericParamDef->mNameNodes.size(); nameIdx++) { @@ -6172,16 +6174,87 @@ void BfModule::ResolveGenericParamConstraints(BfGenericParamInstance* genericPar bfAutocomplete->mInsertEndIdx = nameNode->GetSrcEnd(); if (nameIdx != 0) - { - for (auto checkGenericParam : genericParamDefs) - bfAutocomplete->AddEntry(AutoCompleteEntry("generic", checkGenericParam->mName.c_str()), filter); + { + bfAutocomplete->AddEntry(AutoCompleteEntry("generic", nameNode->ToString().c_str()), filter); } } } } - for (auto constraintTypeRef : genericParamDef->mInterfaceConstraints) + for (auto constraint : constraintDef->mConstraints) { + if (auto opConstraint = BfNodeDynCast(constraint)) + { + BfGenericOperatorConstraintInstance opConstraintInstance; + + if (opConstraint->mLeftType != NULL) + { + if (bfAutocomplete != NULL) + bfAutocomplete->CheckTypeRef(opConstraint->mLeftType, false); + opConstraintInstance.mLeftType = ResolveTypeRef(opConstraint->mLeftType); + if (opConstraintInstance.mLeftType == NULL) + continue; + } + + if (opConstraint->mRightType == NULL) + { + // We had a failure in parsing + continue; + } + + if (opConstraint->mRightType != NULL) + { + if (bfAutocomplete != NULL) + bfAutocomplete->CheckTypeRef(opConstraint->mRightType, false); + opConstraintInstance.mRightType = ResolveTypeRef(opConstraint->mRightType); + if (opConstraintInstance.mRightType == NULL) + continue; + } + + if (opConstraint->mOpToken == NULL) + { + FailAfter("Missing operator", (opConstraint->mLeftType != NULL) ? (BfAstNode*)opConstraint->mLeftType : (BfAstNode*)opConstraint->mOperatorToken); + continue; + } + + if (opConstraint->mLeftType != NULL) + { + if (opConstraint->mRightType == NULL) + { + // Parse should have failed + continue; + } + + opConstraintInstance.mBinaryOp = BfTokenToBinaryOp(opConstraint->mOpToken->mToken); + if (opConstraintInstance.mBinaryOp == BfBinaryOp_None) + { + Fail("Invalid binary operator", opConstraint->mOpToken); + continue; + } + } + else if ((opConstraint->mOpToken->mToken == BfToken_Implicit) || (opConstraint->mOpToken->mToken == BfToken_Explicit)) + { + opConstraintInstance.mCastToken = opConstraint->mOpToken->mToken; + } + else + { + opConstraintInstance.mUnaryOp = BfTokenToUnaryOp(opConstraint->mOpToken->mToken); + if (opConstraintInstance.mUnaryOp == BfBinaryOp_None) + { + Fail("Invalid unary operator", opConstraint->mOpToken); + continue; + } + } + + if ((constraintDef->mGenericParamFlags & BfGenericParamFlag_Equals) != 0) + genericParamInstance->mGenericParamFlags = (BfGenericParamFlags)(genericParamInstance->mGenericParamFlags | BfGenericParamFlag_Equals_Op); + genericParamInstance->mOperatorConstraints.Add(opConstraintInstance); + + continue; + } + + auto constraintTypeRef = BfNodeDynCast(constraint); + if (bfAutocomplete != NULL) bfAutocomplete->CheckTypeRef(constraintTypeRef, true); //TODO: Constraints may refer to other generic params (of either type or method) @@ -6189,7 +6262,7 @@ void BfModule::ResolveGenericParamConstraints(BfGenericParamInstance* genericPar auto constraintType = ResolveTypeRef(constraintTypeRef, BfPopulateType_Declaration, BfResolveTypeRefFlag_AllowGenericMethodParamConstValue); if (constraintType != NULL) { - if ((genericParamDef->mGenericParamFlags & BfGenericParamFlag_Const) != 0) + if ((constraintDef->mGenericParamFlags & BfGenericParamFlag_Const) != 0) { bool isValidTypeCode = false; BfTypeCode typeCode = BfTypeCode_None; @@ -6238,26 +6311,57 @@ void BfModule::ResolveGenericParamConstraints(BfGenericParamInstance* genericPar } else { + bool checkEquality = false; + if (constraintType->IsPrimitiveType()) { - Fail("Primitive constraints are not allowed unless preceded with 'const'", constraintTypeRef); - continue; + if (isUnspecialized) + { + Fail("Primitive constraints are not allowed unless preceded with 'const'", constraintTypeRef); + continue; + } + checkEquality = true; } if (constraintType->IsArray()) { - Fail("Array constraints are not allowed. If a constant-sized array was intended, an type parameterized by a const generic param can be used (ie: where T : int[T2] where T2 : const int)", constraintTypeRef); + if (isUnspecialized) + { + Fail("Array constraints are not allowed. If a constant-sized array was intended, an type parameterized by a const generic param can be used (ie: where T : int[T2] where T2 : const int)", constraintTypeRef); + continue; + } + checkEquality = true; + } + + if (constraintType->IsGenericParam()) + { continue; } if ((!constraintType->IsTypeInstance()) && (!constraintType->IsSizedArray())) { - Fail(StrFormat("Type '%s' is not allowed as a generic constraint", TypeToString(constraintType).c_str()), constraintTypeRef); - continue; + if (isUnspecialized) + { + Fail(StrFormat("Type '%s' is not allowed as a generic constraint", TypeToString(constraintType).c_str()), constraintTypeRef); + continue; + } + checkEquality = true; } - if (constraintType->IsInterface()) + if ((constraintDef->mGenericParamFlags & BfGenericParamFlag_Equals) != 0) { + genericParamInstance->mGenericParamFlags = (BfGenericParamFlags)(genericParamInstance->mGenericParamFlags | BfGenericParamFlag_Equals_Type); + checkEquality = true; + } + + if (checkEquality) + { + genericParamInstance->mTypeConstraint = constraintType; + } + else if (constraintType->IsInterface()) + { + if ((constraintDef->mGenericParamFlags & BfGenericParamFlag_Equals) != 0) + genericParamInstance->mGenericParamFlags = (BfGenericParamFlags)(genericParamInstance->mGenericParamFlags | BfGenericParamFlag_Equals_IFace); genericParamInstance->mInterfaceConstraints.push_back(constraintType->ToTypeInstance()); } else @@ -6292,7 +6396,7 @@ void BfModule::ResolveGenericParamConstraints(BfGenericParamInstance* genericPar } } - if (((genericParamDef->mGenericParamFlags & BfGenericParamFlag_Const) != 0) && + if (((constraintDef->mGenericParamFlags & BfGenericParamFlag_Const) != 0) && (genericParamInstance->mTypeConstraint == NULL)) genericParamInstance->mTypeConstraint = GetPrimitiveType(BfTypeCode_IntPtr); } @@ -6342,7 +6446,7 @@ bool BfModule::CheckGenericConstraints(const BfGenericParamSource& genericParamS { argMayBeReferenceType = true; } - } + } if (checkArgType->IsObjectOrInterface()) argMayBeReferenceType = true; @@ -6356,7 +6460,7 @@ bool BfModule::CheckGenericConstraints(const BfGenericParamSource& genericParamS { if (!ignoreErrors) *errorOut = Fail(StrFormat("The type '%s' must be a value type in order to use it as parameter '%s' for '%s'", - TypeToString(origCheckArgType).c_str(), genericParamInst->GetGenericParamDef()->mName.c_str(), GenericParamSourceToString(genericParamSource).c_str()), checkArgTypeRef); + TypeToString(origCheckArgType).c_str(), genericParamInst->GetName().c_str(), GenericParamSourceToString(genericParamSource).c_str()), checkArgTypeRef); return false; } @@ -6365,7 +6469,7 @@ bool BfModule::CheckGenericConstraints(const BfGenericParamSource& genericParamS { if (!ignoreErrors) *errorOut = Fail(StrFormat("The type '%s' must be a pointer type in order to use it as parameter '%s' for '%s'", - TypeToString(origCheckArgType).c_str(), genericParamInst->GetGenericParamDef()->mName.c_str(), GenericParamSourceToString(genericParamSource).c_str()), checkArgTypeRef); + TypeToString(origCheckArgType).c_str(), genericParamInst->GetName().c_str(), GenericParamSourceToString(genericParamSource).c_str()), checkArgTypeRef); return false; } @@ -6374,7 +6478,7 @@ bool BfModule::CheckGenericConstraints(const BfGenericParamSource& genericParamS { if (!ignoreErrors) *errorOut = Fail(StrFormat("The type '%s' must be a reference type in order to use it as parameter '%s' for '%s'", - TypeToString(origCheckArgType).c_str(), genericParamInst->GetGenericParamDef()->mName.c_str(), GenericParamSourceToString(genericParamSource).c_str()), checkArgTypeRef); + TypeToString(origCheckArgType).c_str(), genericParamInst->GetName().c_str(), GenericParamSourceToString(genericParamSource).c_str()), checkArgTypeRef); return false; } @@ -6384,7 +6488,7 @@ bool BfModule::CheckGenericConstraints(const BfGenericParamSource& genericParamS { if (!ignoreErrors) *errorOut = Fail(StrFormat("The type '%s' must be a const value in order to use it as parameter '%s' for '%s'", - TypeToString(origCheckArgType).c_str(), genericParamInst->GetGenericParamDef()->mName.c_str(), GenericParamSourceToString(genericParamSource).c_str()), checkArgTypeRef); + TypeToString(origCheckArgType).c_str(), genericParamInst->GetName().c_str(), GenericParamSourceToString(genericParamSource).c_str()), checkArgTypeRef); return false; } } @@ -6394,12 +6498,12 @@ bool BfModule::CheckGenericConstraints(const BfGenericParamSource& genericParamS { if (!ignoreErrors) *errorOut = Fail(StrFormat("The value '%s' cannot be used for generic type parameter '%s' for '%s'", - TypeToString(origCheckArgType).c_str(), genericParamInst->GetGenericParamDef()->mName.c_str(), GenericParamSourceToString(genericParamSource).c_str()), checkArgTypeRef); + TypeToString(origCheckArgType).c_str(), genericParamInst->GetName().c_str(), GenericParamSourceToString(genericParamSource).c_str()), checkArgTypeRef); return false; } } - if ((genericParamInst->mInterfaceConstraints.size() == 0) && (genericParamInst->mTypeConstraint == NULL)) + if ((genericParamInst->mInterfaceConstraints.IsEmpty()) && (genericParamInst->mOperatorConstraints.IsEmpty()) && (genericParamInst->mTypeConstraint == NULL)) return true; if (checkArgType->IsPointer()) @@ -6435,7 +6539,7 @@ bool BfModule::CheckGenericConstraints(const BfGenericParamSource& genericParamS if (!mCompiler->mSystem->DoesLiteralFit(primType->mTypeDef->mTypeCode, constExprValueType->mValue.mInt64)) { if (!ignoreErrors) - *errorOut = Fail(StrFormat("Const generic argument '%s', declared with const '%lld', does not fit into const constraint '%s' for '%s'", genericParamInst->GetGenericParamDef()->mName.c_str(), + *errorOut = Fail(StrFormat("Const generic argument '%s', declared with const '%lld', does not fit into const constraint '%s' for '%s'", genericParamInst->GetName().c_str(), constExprValueType->mValue.mInt64, TypeToString(genericParamInst->mTypeConstraint).c_str(), GenericParamSourceToString(genericParamSource).c_str()), checkArgTypeRef); return false; } @@ -6443,7 +6547,7 @@ bool BfModule::CheckGenericConstraints(const BfGenericParamSource& genericParamS else { if (!ignoreErrors) - *errorOut = Fail(StrFormat("Const generic argument '%s', declared with integer const '%lld', is not compatible with const constraint '%s' for '%s'", genericParamInst->GetGenericParamDef()->mName.c_str(), + *errorOut = Fail(StrFormat("Const generic argument '%s', declared with integer const '%lld', is not compatible with const constraint '%s' for '%s'", genericParamInst->GetName().c_str(), constExprValueType->mValue.mInt64, TypeToString(genericParamInst->mTypeConstraint).c_str(), GenericParamSourceToString(genericParamSource).c_str()), checkArgTypeRef); return false; } @@ -6455,7 +6559,7 @@ bool BfModule::CheckGenericConstraints(const BfGenericParamSource& genericParamS char valStr[64]; ExactMinimalDoubleToStr(constExprValueType->mValue.mDouble, valStr); if (!ignoreErrors) - *errorOut = Fail(StrFormat("Const generic argument '%s', declared with floating point const '%s', is not compatible with const constraint '%s' for '%s'", genericParamInst->GetGenericParamDef()->mName.c_str(), + *errorOut = Fail(StrFormat("Const generic argument '%s', declared with floating point const '%s', is not compatible with const constraint '%s' for '%s'", genericParamInst->GetName().c_str(), valStr, TypeToString(genericParamInst->mTypeConstraint).c_str(), GenericParamSourceToString(genericParamSource).c_str()), checkArgTypeRef); return false; } @@ -6514,7 +6618,7 @@ bool BfModule::CheckGenericConstraints(const BfGenericParamSource& genericParamS if (!constraintMatched) { if (!ignoreErrors) - *errorOut = Fail(StrFormat("Generic argument '%s', declared to be '%s' for '%s', must derive from '%s'", genericParamInst->GetGenericParamDef()->mName.c_str(), + *errorOut = Fail(StrFormat("Generic argument '%s', declared to be '%s' for '%s', must derive from '%s'", genericParamInst->GetName().c_str(), TypeToString(origCheckArgType).c_str(), GenericParamSourceToString(genericParamSource).c_str(), TypeToString(convCheckConstraint).c_str(), TypeToString(genericParamInst->mTypeConstraint).c_str()), checkArgTypeRef); return false; @@ -6529,7 +6633,7 @@ bool BfModule::CheckGenericConstraints(const BfGenericParamSource& genericParamS if (checkTypeInst->mTypeDef->mIsConcrete) { if (!ignoreErrors) - *errorOut = Fail(StrFormat("Generic argument '%s', declared to be concrete interface '%s' for '%s', must be a concrete type", genericParamInst->GetGenericParamDef()->mName.c_str(), + *errorOut = Fail(StrFormat("Generic argument '%s', declared to be concrete interface '%s' for '%s', must be a concrete type", genericParamInst->GetName().c_str(), TypeToString(origCheckArgType).c_str(), GenericParamSourceToString(genericParamSource).c_str()), checkArgTypeRef); return false; } @@ -6570,11 +6674,100 @@ bool BfModule::CheckGenericConstraints(const BfGenericParamSource& genericParamS if (!implementsInterface) { if (!ignoreErrors) - *errorOut = Fail(StrFormat("Generic argument '%s', declared to be '%s' for '%s', must implement '%s'", genericParamInst->GetGenericParamDef()->mName.c_str(), + *errorOut = Fail(StrFormat("Generic argument '%s', declared to be '%s' for '%s', must implement '%s'", genericParamInst->GetName().c_str(), TypeToString(origCheckArgType).c_str(), GenericParamSourceToString(genericParamSource).c_str(), TypeToString(checkConstraint).c_str()), checkArgTypeRef); return false; } } + + for (auto& checkOpConstraint : genericParamInst->mOperatorConstraints) + { + auto leftType = checkOpConstraint.mLeftType; + if ((leftType != NULL) && (leftType->IsUnspecializedType())) + leftType = ResolveGenericType(leftType, *methodGenericArgs); + if (leftType != NULL) + leftType = FixIntUnknown(leftType); + + auto rightType = checkOpConstraint.mRightType; + if ((rightType != NULL) && (rightType->IsUnspecializedType())) + rightType = ResolveGenericType(rightType, *methodGenericArgs); + if (rightType != NULL) + rightType = FixIntUnknown(rightType); + + if (checkOpConstraint.mBinaryOp != BfBinaryOp_None) + { + BfExprEvaluator exprEvaluator(this); + + BfTypedValue leftValue(mBfIRBuilder->GetFakeVal(), leftType); + BfTypedValue rightValue(mBfIRBuilder->GetFakeVal(), rightType); + + // + { + SetAndRestoreValue prevIgnoreErrors(mIgnoreErrors, true); + SetAndRestoreValue prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites, true); + exprEvaluator.PerformBinaryOperation(NULL, NULL, checkOpConstraint.mBinaryOp, NULL, BfBinOpFlag_NoClassify, leftValue, rightValue); + } + + if ((exprEvaluator.mResult == NULL) || + (!CanImplicitlyCast(exprEvaluator.mResult, origCheckArgType))) + { + if (!ignoreErrors) + *errorOut = Fail(StrFormat("Generic argument '%s', declared to be '%s' for '%s', must result from binary operation '%s %s %s'", genericParamInst->GetName().c_str(), + TypeToString(origCheckArgType).c_str(), GenericParamSourceToString(genericParamSource).c_str(), + TypeToString(leftType).c_str(), BfGetOpName(checkOpConstraint.mBinaryOp), TypeToString(rightType).c_str() + ), checkArgTypeRef); + return false; + } + + } + else + { + BfTypedValue rightValue(mBfIRBuilder->GetFakeVal(), rightType); + + StringT<128> failedOpName; + + if (checkOpConstraint.mCastToken == BfToken_Implicit) + { + if (!CanImplicitlyCast(rightValue, origCheckArgType, BfCastFlags_SilentFail)) + failedOpName = "implicit conversion from '"; + } + else + { + SetAndRestoreValue prevIgnoreErrors(mIgnoreErrors, true); + SetAndRestoreValue prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites, true); + + if (checkOpConstraint.mCastToken == BfToken_Explicit) + { + if (!CastToValue(NULL, rightValue, origCheckArgType, (BfCastFlags)(BfCastFlags_Explicit | BfCastFlags_SilentFail))) + failedOpName = "explicit conversion from '"; + } + else + { + BfExprEvaluator exprEvaluator(this); + exprEvaluator.mResult = rightValue; + exprEvaluator.PerformUnaryOperation(NULL, checkOpConstraint.mUnaryOp, NULL); + + if ((exprEvaluator.mResult == NULL) || + (!CanImplicitlyCast(exprEvaluator.mResult, origCheckArgType))) + { + failedOpName += "unary operation '"; + failedOpName += BfGetOpName(checkOpConstraint.mUnaryOp); + } + } + } + + if (!failedOpName.IsEmpty()) + { + if (!ignoreErrors) + *errorOut = Fail(StrFormat("Generic argument '%s', declared to be '%s' for '%s', must result from %s%s'", genericParamInst->GetName().c_str(), + TypeToString(origCheckArgType).c_str(), GenericParamSourceToString(genericParamSource).c_str(), + failedOpName.c_str(), TypeToString(rightType).c_str() + ), checkArgTypeRef); + return false; + } + } + } + return true; } @@ -10389,6 +10582,9 @@ bool BfModule::CheckModifyValue(BfTypedValue& typedValue, BfAstNode* refNode, co bool BfModule::CompareMethodSignatures(BfMethodInstance* methodA, BfMethodInstance* methodB) { + // If one is an interface and the other is an impl, B is the impl + auto implOwner = methodB->GetOwner(); + if (methodA->mMethodDef->mIsLocalMethod) { int sepPosA = (int)BF_MIN(methodA->mMethodDef->mName.IndexOf('@'), methodA->mMethodDef->mName.length()); @@ -10421,7 +10617,7 @@ bool BfModule::CompareMethodSignatures(BfMethodInstance* methodA, BfMethodInstan return false; if (operatorA->mOperatorDeclaration->mIsConvOperator) { - if (methodA->mReturnType != methodB->mReturnType) + if (!BfTypeUtils::TypeEquals(methodA->mReturnType, methodB->mReturnType, implOwner)) return false; } } @@ -10437,13 +10633,11 @@ bool BfModule::CompareMethodSignatures(BfMethodInstance* methodA, BfMethodInstan for (int paramIdx = 0; paramIdx < (int)methodA->GetParamCount() - implicitParamCountA; paramIdx++) { - if ((methodA->GetParamType(paramIdx + implicitParamCountA) != methodB->GetParamType(paramIdx + implicitParamCountB)) || + if ((!BfTypeUtils::TypeEquals(methodA->GetParamType(paramIdx + implicitParamCountA), methodB->GetParamType(paramIdx + implicitParamCountB), implOwner)) || (methodA->GetParamKind(paramIdx + implicitParamCountA) != methodB->GetParamKind(paramIdx + implicitParamCountB))) return false; } - - // Compare generic params. Generic params are part of the method signature here if (methodA->GetNumGenericParams() != methodB->GetNumGenericParams()) return false; @@ -11403,6 +11597,12 @@ BfModuleMethodInstance BfModule::GetMethodInstance(BfTypeInstance* typeInst, BfM auto genericParamInstance = new BfGenericMethodParamInstance(methodDef, genericParamIdx); methodInstance->GetMethodInfoEx()->mGenericParams.push_back(genericParamInstance); } + + for (int externConstraintIdx = 0; externConstraintIdx < (int)methodDef->mExternalConstraints.size(); externConstraintIdx++) + { + auto genericParamInstance = new BfGenericMethodParamInstance(methodDef, externConstraintIdx + (int)methodDef->mGenericParams.size()); + methodInstance->GetMethodInfoEx()->mGenericParams.push_back(genericParamInstance); + } bool addToWorkList = !processNow; if (mCompiler->GetAutoComplete() != NULL) @@ -18578,23 +18778,48 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool BfAutoComplete* bfAutocomplete = NULL; if (mCompiler->mResolvePassData != NULL) bfAutocomplete = mCompiler->mResolvePassData->mAutoComplete; - - for (int genericParamIdx = 0; genericParamIdx < (int)methodInstance->GetNumGenericArguments(); genericParamIdx++) - { - auto genericParamDef = methodDef->mGenericParams[genericParamIdx]; - ResolveGenericParamConstraints(methodInstance->mMethodInfoEx->mGenericParams[genericParamIdx], methodDef->mGenericParams, genericParamIdx); - - if (bfAutocomplete != NULL) - { - for (auto nameNode : genericParamDef->mNameNodes) - { - HandleMethodGenericParamRef(nameNode, typeDef, methodDef, genericParamIdx); - } - } - } - + if (methodInstance->mMethodInfoEx != NULL) { + for (int genericParamIdx = 0; genericParamIdx < (int)methodInstance->mMethodInfoEx->mGenericParams.size(); genericParamIdx++) + { + auto genericParam = methodInstance->mMethodInfoEx->mGenericParams[genericParamIdx]; + if (genericParamIdx < (int)methodDef->mGenericParams.size()) + { + genericParam->mExternType = GetGenericParamType(BfGenericParamKind_Method, genericParamIdx); + } + else + { + auto externConstraintDef = genericParam->GetExternConstraintDef(); + genericParam->mExternType = ResolveTypeRef(externConstraintDef->mTypeRef); + + auto autoComplete = mCompiler->GetAutoComplete(); + if (autoComplete != NULL) + autoComplete->CheckTypeRef(externConstraintDef->mTypeRef, false); + + if (genericParam->mExternType != NULL) + { + // + } + else + genericParam->mExternType = GetPrimitiveType(BfTypeCode_Var); + } + + ResolveGenericParamConstraints(genericParam, methodInstance->mIsUnspecialized); + + if (genericParamIdx < (int)methodDef->mGenericParams.size()) + { + auto genericParamDef = methodDef->mGenericParams[genericParamIdx]; + if (bfAutocomplete != NULL) + { + for (auto nameNode : genericParamDef->mNameNodes) + { + HandleMethodGenericParamRef(nameNode, typeDef, methodDef, genericParamIdx); + } + } + } + } + for (auto genericParam : methodInstance->mMethodInfoEx->mGenericParams) { for (auto constraintTypeInst : genericParam->mInterfaceConstraints) @@ -19412,7 +19637,7 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool { if (!typeInstance->IsTypeMemberAccessible(checkMethod->mDeclaringType, methodDef->mDeclaringType)) continue; - + bool silentlyAllow = false; if (checkMethod->mDeclaringType != methodDef->mDeclaringType) { @@ -19424,10 +19649,13 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool else silentlyAllow = true; } + + if ((checkMethod->mCommutableKind == BfCommutableKind_Reverse) || (methodDef->mCommutableKind == BfCommutableKind_Reverse)) + silentlyAllow = true; if (!silentlyAllow) - { - if (!methodDef->mName.IsEmpty()) + { + if ((!methodDef->mName.IsEmpty()) || (checkMethodInstance->mMethodDef->mIsOperator)) { auto refNode = methodDef->GetRefNode(); auto bfError = Fail("Method already declared with the same parameter types", refNode, true); diff --git a/IDEHelper/Compiler/BfModule.h b/IDEHelper/Compiler/BfModule.h index 99f07380..479b9bca 100644 --- a/IDEHelper/Compiler/BfModule.h +++ b/IDEHelper/Compiler/BfModule.h @@ -1537,6 +1537,7 @@ public: bool ValidateGenericConstraints(BfTypeReference* typeRef, BfGenericTypeInstance* genericTypeInstance, bool ignoreErrors); bool AreConstraintsSubset(BfGenericParamInstance* checkInner, BfGenericParamInstance* checkOuter); bool ShouldAllowMultipleDefinitions(BfTypeInstance* typeInst, BfTypeDef* firstDeclaringTypeDef, BfTypeDef* secondDeclaringTypeDef); + void CheckInjectNewRevision(BfTypeInstance* typeInstance); bool InitType(BfType* resolvedTypeRef, BfPopulateType populateType); bool CheckAccessMemberProtection(BfProtection protection, BfType* memberType); bool CheckDefineMemberProtection(BfProtection protection, BfType* memberType); @@ -1589,7 +1590,7 @@ public: void FixIntUnknown(BfTypedValue& lhs, BfTypedValue& rhs); BfTypeDef* ResolveGenericInstanceDef(BfGenericInstanceTypeRef* genericTypeRef); BfType* ResolveType(BfType* lookupType, BfPopulateType populateType = BfPopulateType_Data); - void ResolveGenericParamConstraints(BfGenericParamInstance* genericParamInstance, const Array& genericParamDefs, int genericParamIdx); + void ResolveGenericParamConstraints(BfGenericParamInstance* genericParamInstance, bool isUnspecialized); String GenericParamSourceToString(const BfGenericParamSource& genericParamSource); bool CheckGenericConstraints(const BfGenericParamSource& genericParamSource, BfType* checkArgType, BfAstNode* checkArgTypeRef, BfGenericParamInstance* genericParamInst, BfTypeVector* methodGenericArgs = NULL, BfError** errorOut = NULL); BfIRValue AllocLocalVariable(BfType* type, const StringImpl& name, bool doLifetimeEnd = true); @@ -1619,6 +1620,7 @@ public: BfGenericParamType* GetGenericParamType(BfGenericParamKind paramKind, int paramIdx); BfType* ResolveGenericType(BfType* unspecializedType, const BfTypeVector& methodGenericArguments, bool allowFail = false); bool IsUnboundGeneric(BfType* type); + BfGenericParamInstance* GetGenericTypeParamInstance(int paramIdx); BfGenericParamInstance* GetGenericParamInstance(BfGenericParamType* type); BfTypeInstance* GetBaseType(BfTypeInstance* typeInst); void HandleTypeGenericParamRef(BfAstNode* refNode, BfTypeDef* typeDef, int typeGenericParamIdx); diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index 33d037e2..8daa9172 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -57,6 +57,7 @@ BfGenericExtensionEntry* BfModule::BuildGenericExtensionInfo(BfGenericTypeInstan } BfTypeState typeState; + typeState.mTypeInstance = genericTypeInst; typeState.mCurTypeDef = partialTypeDef; SetAndRestoreValue prevTypeState(mContext->mCurTypeState, &typeState); @@ -71,6 +72,7 @@ BfGenericExtensionEntry* BfModule::BuildGenericExtensionInfo(BfGenericTypeInstan for (int paramIdx = startDefGenericParamIdx; paramIdx < (int)genericTypeInst->mTypeGenericArguments.size(); paramIdx++) { auto genericParamInstance = new BfGenericTypeParamInstance(partialTypeDef, paramIdx); + genericParamInstance->mExternType = GetGenericParamType(BfGenericParamKind_Type, paramIdx); genericExEntry->mGenericParams.push_back(genericParamInstance); } @@ -83,7 +85,7 @@ BfGenericExtensionEntry* BfModule::BuildGenericExtensionInfo(BfGenericTypeInstan genericParamInstance->mInterfaceConstraints = rootGenericParamInstance->mInterfaceConstraints; genericParamInstance->mGenericParamFlags |= rootGenericParamInstance->mGenericParamFlags; - ResolveGenericParamConstraints(genericParamInstance, partialTypeDef->mGenericParamDefs, paramIdx); + ResolveGenericParamConstraints(genericParamInstance, genericTypeInst->IsUnspecializedType()); } for (auto genericParam : genericExEntry->mGenericParams) @@ -116,8 +118,9 @@ bool BfModule::BuildGenericParams(BfType* resolvedTypeRef) for (int paramIdx = startDefGenericParamIdx; paramIdx < (int)genericTypeInst->mTypeGenericArguments.size(); paramIdx++) { auto genericParamInstance = new BfGenericTypeParamInstance(typeDef, paramIdx); + genericParamInstance->mExternType = GetGenericParamType(BfGenericParamKind_Type, paramIdx); genericTypeInst->mGenericParams.push_back(genericParamInstance); - } + } if (!typeDef->mPartials.empty()) { @@ -130,7 +133,7 @@ bool BfModule::BuildGenericParams(BfType* resolvedTypeRef) { auto genericParamDef = typeDef->mGenericParamDefs[paramIdx]; auto genericParamInstance = genericTypeInst->mGenericParams[paramIdx]; - ResolveGenericParamConstraints(genericParamInstance, typeDef->mGenericParamDefs, paramIdx); + ResolveGenericParamConstraints(genericParamInstance, genericTypeInst->IsUnspecializedType()); for (auto nameNode : genericParamDef->mNameNodes) { @@ -164,15 +167,17 @@ bool BfModule::BuildGenericParams(BfType* resolvedTypeRef) } else { - for (int paramIdx = startDefGenericParamIdx; paramIdx < (int)genericTypeInst->mTypeGenericArguments.size(); paramIdx++) + for (int paramIdx = startDefGenericParamIdx; paramIdx < (int)genericTypeInst->mGenericParams.size(); paramIdx++) { auto genericParamInstance = genericTypeInst->mGenericParams[paramIdx]; - ResolveGenericParamConstraints(genericParamInstance, typeDef->mGenericParamDefs, paramIdx); - auto genericParamDef = typeDef->mGenericParamDefs[paramIdx]; - - for (auto nameNode : genericParamDef->mNameNodes) + ResolveGenericParamConstraints(genericParamInstance, genericTypeInst->IsUnspecializedType()); + auto genericParamDef = genericParamInstance->GetGenericParamDef(); + if (genericParamDef != NULL) { - HandleTypeGenericParamRef(nameNode, typeDef, paramIdx); + for (auto nameNode : genericParamDef->mNameNodes) + { + HandleTypeGenericParamRef(nameNode, typeDef, paramIdx); + } } } } @@ -261,6 +266,12 @@ bool BfModule::AreConstraintsSubset(BfGenericParamInstance* checkInner, BfGeneri return false; } + for (auto& innerOp : checkInner->mOperatorConstraints) + { + if (!checkOuter->mOperatorConstraints.Contains(innerOp)) + return false; + } + return true; } @@ -305,6 +316,37 @@ bool BfModule::ShouldAllowMultipleDefinitions(BfTypeInstance* typeInst, BfTypeDe return false; } +void BfModule::CheckInjectNewRevision(BfTypeInstance* typeInstance) +{ + if ((typeInstance != NULL) && (typeInstance->mTypeDef != NULL)) + { + if (typeInstance->mTypeDef->mNextRevision != NULL) + { + // It's possible that our main compiler thread is generating a new typedef while we're autocompleting. This handles that case... + if (typeInstance->mDefineState == BfTypeDefineState_Undefined) + { + if (typeInstance->IsBoxed()) + { + BfBoxedType* boxedType = (BfBoxedType*)typeInstance; + BfTypeInstance* innerType = boxedType->mElementType->ToTypeInstance(); + PopulateType(innerType, BfPopulateType_Data); + } + else + { + mContext->HandleChangedTypeDef(typeInstance->mTypeDef); + mSystem->InjectNewRevision(typeInstance->mTypeDef); + } + } + else + { + BF_ASSERT(mCompiler->IsAutocomplete()); + } + } + if ((!typeInstance->IsDeleting()) && (!mCompiler->IsAutocomplete())) + BF_ASSERT((typeInstance->mTypeDef->mDefState == BfTypeDef::DefState_Defined) || (typeInstance->mTypeDef->mDefState == BfTypeDef::DefState_New)); + } +} + bool BfModule::InitType(BfType* resolvedTypeRef, BfPopulateType populateType) { BP_ZONE("BfModule::InitType"); @@ -318,6 +360,8 @@ bool BfModule::InitType(BfType* resolvedTypeRef, BfPopulateType populateType) auto typeInst = resolvedTypeRef->ToTypeInstance(); if (typeInst != NULL) { + CheckInjectNewRevision(typeInst); + if (typeInst->mBaseType != NULL) BF_ASSERT((typeInst->mBaseType->mRebuildFlags & BfTypeRebuildFlag_Deleted) == 0); @@ -606,22 +650,6 @@ bool BfModule::CheckCircularDataError() { bool hadError = false; - { - int count = 0; - auto checkTypeState = mContext->mCurTypeState; - while (checkTypeState != NULL) - { - checkTypeState = checkTypeState->mPrevState; - count++; - } - - if (count > 20) - { - NOP; - } - } - - int checkIdx = 0; auto checkTypeState = mContext->mCurTypeState; bool isPreBaseCheck = checkTypeState->mPopulateType == BfPopulateType_Declaration; @@ -748,33 +776,7 @@ bool BfModule::PopulateType(BfType* resolvedTypeRef, BfPopulateType populateType return true; auto typeInstance = resolvedTypeRef->ToTypeInstance(); - if ((typeInstance != NULL) && (typeInstance->mTypeDef != NULL)) - { - if (typeInstance->mTypeDef->mNextRevision != NULL) - { - // It's possible that our main compiler thread is generating a new typedef while we're autocompleting. This handles that case... - if (typeInstance->mDefineState == BfTypeDefineState_Undefined) - { - if (typeInstance->IsBoxed()) - { - BfBoxedType* boxedType = (BfBoxedType*)typeInstance; - BfTypeInstance* innerType = boxedType->mElementType->ToTypeInstance(); - PopulateType(innerType, BfPopulateType_Data); - } - else - { - mContext->HandleChangedTypeDef(typeInstance->mTypeDef); - mSystem->InjectNewRevision(typeInstance->mTypeDef); - } - } - else - { - BF_ASSERT(mCompiler->IsAutocomplete()); - } - } - if ((!typeInstance->IsDeleting()) && (!mCompiler->IsAutocomplete())) - BF_ASSERT(typeInstance->mTypeDef->mDefState == BfTypeDef::DefState_Defined); - } + CheckInjectNewRevision(typeInstance); BF_ASSERT((resolvedTypeRef->mRebuildFlags & (BfTypeRebuildFlag_Deleted | BfTypeRebuildFlag_DeleteQueued)) == 0); @@ -2167,6 +2169,10 @@ bool BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy if (propDef->mFieldDeclaration != NULL) { + BfTypeState typeState; + typeState.mCurTypeDef = propDef->mDeclaringType; + SetAndRestoreValue prevTypeState(mContext->mCurTypeState, &typeState); + if (propDef->mFieldDeclaration->mAttributes != NULL) { auto customAttrs = GetCustomAttributes(propDef->mFieldDeclaration->mAttributes, BfAttributeTargets_Property); @@ -2181,11 +2187,7 @@ bool BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy auto propDecl = (BfPropertyDeclaration*)propDef->mFieldDeclaration; if (propDecl->mExplicitInterface != NULL) - { - BfTypeState typeState; - typeState.mCurTypeDef = propDef->mDeclaringType; - SetAndRestoreValue prevTypeState(mContext->mCurTypeState, &typeState); - + { if ((mCompiler->mResolvePassData != NULL) && (mCompiler->mResolvePassData->mAutoComplete != NULL)) mCompiler->mResolvePassData->mAutoComplete->CheckTypeRef(propDecl->mExplicitInterface, false); auto explicitInterface = ResolveTypeRef(propDecl->mExplicitInterface, BfPopulateType_Declaration); @@ -4841,9 +4843,15 @@ BfType* BfModule::ResolveTypeDef(BfTypeDef* typeDef, BfPopulateType populateType return resolvedtypeDefType; } -// Get BaseClass even when we haven't populated the type yet +// Get BaseClass even when we haven't populated the type yet2 BfTypeInstance* BfModule::GetBaseType(BfTypeInstance* typeInst) { + if ((mContext->mCurTypeState != NULL) && (mContext->mCurTypeState->mTypeInstance == typeInst)) + { + if (typeInst->mBaseType == NULL) + return NULL; + } + if ((typeInst->mBaseType == NULL) && (typeInst != mContext->mBfObjectType)) PopulateType(typeInst, BfPopulateType_BaseType); return typeInst->mBaseType; @@ -5093,6 +5101,7 @@ bool BfModule::IsInnerType(BfType* checkInnerType, BfType* checkOuterType) bool BfModule::IsInnerType(BfTypeDef* checkInnerType, BfTypeDef* checkOuterType) { + BF_ASSERT(!checkOuterType->mIsPartial); if (checkInnerType->mNestDepth <= checkOuterType->mNestDepth) return false; while (true) @@ -5100,6 +5109,8 @@ bool BfModule::IsInnerType(BfTypeDef* checkInnerType, BfTypeDef* checkOuterType) BfTypeDef* outerType = checkInnerType->mOuterType; if (outerType == NULL) return false; + if (outerType->mIsPartial) + outerType = mSystem->GetCombinedPartial(outerType); if (outerType == checkOuterType) return true; checkInnerType = checkInnerType->mOuterType; @@ -5482,11 +5493,8 @@ bool BfModule::IsUnboundGeneric(BfType* type) return (genericParamInst->mGenericParamFlags & BfGenericParamFlag_Var) != 0; } -BfGenericParamInstance* BfModule::GetGenericParamInstance(BfGenericParamType* type) +BfGenericParamInstance* BfModule::GetGenericTypeParamInstance(int genericParamIdx) { - if (type->mGenericParamKind == BfGenericParamKind_Method) - return mCurMethodInstance->mMethodInfoEx->mGenericParams[type->mGenericParamIdx]; - // When we're evaluating a method, make sure the params refer back to that method context auto curTypeInstance = mCurTypeInstance; if (mCurMethodInstance != NULL) @@ -5505,23 +5513,35 @@ BfGenericParamInstance* BfModule::GetGenericParamInstance(BfGenericParamType* ty auto activeTypeDef = GetActiveTypeDef(NULL, true); if ((activeTypeDef->mTypeDeclaration != genericTypeInst->mTypeDef->mTypeDeclaration) && (activeTypeDef->IsExtension())) { + BfTypeDef* lookupTypeDef = activeTypeDef; + while (lookupTypeDef->mNestDepth > genericTypeInst->mTypeDef->mNestDepth) + lookupTypeDef = lookupTypeDef->mOuterType; + BfGenericExtensionEntry* genericExEntry; - if (genericTypeInst->mGenericExtensionInfo->mExtensionMap.TryGetValue(activeTypeDef, &genericExEntry)) + if (genericTypeInst->mGenericExtensionInfo->mExtensionMap.TryGetValue(lookupTypeDef, &genericExEntry)) { - return genericExEntry->mGenericParams[type->mGenericParamIdx]; + return genericExEntry->mGenericParams[genericParamIdx]; } else { if ((mCompiler->mResolvePassData == NULL) || (mCompiler->mResolvePassData->mAutoComplete == NULL)) { - BF_FATAL("Invalid GetGenericParamInstance with extention"); + BF_FATAL("Invalid GetGenericParamInstance with extension"); } } } } BF_ASSERT(genericTypeInst != NULL); - return genericTypeInst->mGenericParams[type->mGenericParamIdx]; + return genericTypeInst->mGenericParams[genericParamIdx]; +} + +BfGenericParamInstance* BfModule::GetGenericParamInstance(BfGenericParamType* type) +{ + if (type->mGenericParamKind == BfGenericParamKind_Method) + return mCurMethodInstance->mMethodInfoEx->mGenericParams[type->mGenericParamIdx]; + + return GetGenericTypeParamInstance(type->mGenericParamIdx); } BfType* BfModule::ResolveTypeResult(BfTypeReference* typeRef, BfType* resolvedTypeRef, BfPopulateType populateType, BfResolveTypeRefFlags resolveFlags) @@ -5717,7 +5737,7 @@ BfType* BfModule::ResolveTypeResult(BfTypeReference* typeRef, BfType* resolvedTy bool hadError = false; hadError = !PopulateType(resolvedTypeRef, populateType); - if ((genericTypeInstance != NULL) && (populateType > BfPopulateType_Identity)) + if ((genericTypeInstance != NULL) && (genericTypeInstance != mCurTypeInstance) && (populateType > BfPopulateType_Identity)) { if (((genericTypeInstance->mHadValidateErrors) || (!genericTypeInstance->mValidatedGenericConstraints) || (genericTypeInstance->mIsUnspecializedVariation)) && ((mCurMethodInstance == NULL) || (!mCurMethodInstance->mIsUnspecializedVariation)) && @@ -5852,6 +5872,12 @@ BfTypeDef* BfModule::FindTypeDefRaw(const BfAtomComposite& findName, int numGene } if (checkTypeInst == skipCheckBaseType) break; + + if (checkTypeInst->mTypeDef == mCompiler->mNullableTypeDef) + { + NOP; + } + checkTypeInst = GetBaseType(checkTypeInst); allowPrivate = false; } @@ -5868,6 +5894,7 @@ BfTypeDef* BfModule::FindTypeDefRaw(const BfAtomComposite& findName, int numGene } if (checkTypeInst == skipCheckBaseType) break; + checkTypeInst = GetBaseType(checkTypeInst); allowPrivate = false; } @@ -6931,8 +6958,8 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula if ((mCurTypeInstance != NULL) && (typeDef->mGenericParamDefs.size() != 0)) { // Try to inherit generic params from current parent - - auto outerType = typeDef->mOuterType; + + BfTypeDef* outerType = mSystem->GetCombinedPartial(typeDef->mOuterType); BF_ASSERT(!outerType->mIsPartial); if (TypeHasParent(mCurTypeInstance->mTypeDef, outerType)) { @@ -8699,62 +8726,87 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp if ((typedVal.mType->IsGenericParam()) && (!toType->IsGenericParam())) { if (toType == mContext->mBfObjectType) - { - /*auto resolvedType = ResolveGenericType(typedVal.mType); - if (!resolvedType->IsGenericParam()) - return CastToValue(srcNode, BfTypedValue(typedVal.mValue, resolvedType), toType, castFlags, silentFail); - return typedVal.mValue;*/ - // Always allow casting to generic + { + // Always allow casting from generic to object return typedVal.mValue; } + auto _CheckGenericParamInstance = [&](BfGenericParamInstance* genericParamInst) + { + if ((genericParamInst->mGenericParamFlags & BfGenericParamFlag_Var) != 0) + { + return typedVal.mValue; + } + if (toType->IsInterface()) + { + for (auto iface : genericParamInst->mInterfaceConstraints) + if (TypeIsSubTypeOf(iface, toType->ToTypeInstance())) + return GetDefaultValue(toType); + } + + if (genericParamInst->mTypeConstraint != NULL) + { + auto constraintTypeInst = genericParamInst->mTypeConstraint->ToTypeInstance(); + if ((constraintTypeInst != NULL) && (constraintTypeInst->mTypeDef == mCompiler->mEnumTypeDef)) + { + // Enum->int + if (toType->IsInteger()) + return GetDefaultValue(toType); + } + + auto defaultFromValue = GetDefaultTypedValue(genericParamInst->mTypeConstraint); + auto result = CastToValue(srcNode, defaultFromValue, toType, (BfCastFlags)(castFlags | BfCastFlags_SilentFail)); + + if (result) + { + if ((genericParamInst->mTypeConstraint->IsDelegate()) && (toType->IsDelegate())) + { + // Don't allow cast when we are constrained by a delegate type, because BfMethodRefs can match and we require an actual alloc + Fail(StrFormat("Unable to cast '%s' to '%s' because delegate constraints allow valueless direct method references", TypeToString(typedVal.mType).c_str(), TypeToString(toType).c_str()), srcNode); + return BfIRValue(); + } + return result; + } + } + + // Generic constrained with class or pointer type -> void* + if (toType->IsVoidPtr()) + { + if ((genericParamInst->mGenericParamFlags & (BfGenericParamFlag_Class | BfGenericParamFlag_StructPtr)) || + ((genericParamInst->mTypeConstraint != NULL) && + ((genericParamInst->mTypeConstraint->IsPointer()) || (genericParamInst->mTypeConstraint->IsObjectOrInterface())))) + { + return GetDefaultValue(toType); + } + } + + return BfIRValue(); + }; + + BfIRValue retVal; + // For these casts, it's just important we get *A* value to work with here, // as this is just use for unspecialized parsing. We don't use the generated code - auto genericParamInst = GetGenericParamInstance((BfGenericParamType*)typedVal.mType); - if ((genericParamInst->mGenericParamFlags & BfGenericParamFlag_Var) != 0) { - return typedVal.mValue; - } - if (toType->IsInterface()) - { - for (auto iface : genericParamInst->mInterfaceConstraints) - if (TypeIsSubTypeOf(iface, toType->ToTypeInstance())) - return GetDefaultValue(toType); + auto genericParamInst = GetGenericParamInstance((BfGenericParamType*)typedVal.mType); + retVal = _CheckGenericParamInstance(genericParamInst); + if (retVal) + return retVal; } - if (genericParamInst->mTypeConstraint != NULL) + // Check method generic constraints + if ((mCurMethodInstance != NULL) && (mCurMethodInstance->mIsUnspecialized) && (mCurMethodInstance->mMethodInfoEx != NULL)) { - auto constraintTypeInst = genericParamInst->mTypeConstraint->ToTypeInstance(); - if ((constraintTypeInst != NULL) && (constraintTypeInst->mTypeDef == mCompiler->mEnumTypeDef)) + for (int genericParamIdx = (int)mCurMethodInstance->mMethodInfoEx->mMethodGenericArguments.size(); + genericParamIdx < mCurMethodInstance->mMethodInfoEx->mGenericParams.size(); genericParamIdx++) { - // Enum->int - if (toType->IsInteger()) - return GetDefaultValue(toType); - } - - auto defaultFromValue = GetDefaultTypedValue(genericParamInst->mTypeConstraint); - auto result = CastToValue(srcNode, defaultFromValue, toType, (BfCastFlags)(castFlags | BfCastFlags_SilentFail)); - - if (result) - { - if ((genericParamInst->mTypeConstraint->IsDelegate()) && (toType->IsDelegate())) + auto genericParamInst = mCurMethodInstance->mMethodInfoEx->mGenericParams[genericParamIdx]; + if (genericParamInst->mExternType == typedVal.mType) { - // Don't allow cast when we are constrained by a delegate type, because BfMethodRefs can match and we require an actual alloc - Fail(StrFormat("Unable to cast '%s' to '%s' because delegate constraints allow valueless direct method references", TypeToString(typedVal.mType).c_str(), TypeToString(toType).c_str()), srcNode); - return BfIRValue(); + retVal = _CheckGenericParamInstance(genericParamInst); + if (retVal) + return retVal; } - return result; - } - } - - // Generic constrained with class or pointer type -> void* - if (toType->IsVoidPtr()) - { - if ((genericParamInst->mGenericParamFlags & (BfGenericParamFlag_Class | BfGenericParamFlag_StructPtr)) || - ((genericParamInst->mTypeConstraint != NULL) && - ((genericParamInst->mTypeConstraint->IsPointer()) || (genericParamInst->mTypeConstraint->IsObjectOrInterface())))) - { - return GetDefaultValue(toType); } } } @@ -9612,7 +9664,7 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp } return CastToValue(srcNode, operatorOut, toType, castFlags, resultFlags); - } + } } if (bestFromType == NULL) @@ -9628,6 +9680,55 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp Fail(StrFormat(errStr, TypeToString(typedVal.mType).c_str(), TypeToString(toType).c_str()), srcNode); return BfIRValue(); } + + // Check method generic constraints + if ((mCurMethodInstance != NULL) && (mCurMethodInstance->mIsUnspecialized) && (mCurMethodInstance->mMethodInfoEx != NULL)) + { + for (int genericParamIdx = 0; genericParamIdx < mCurMethodInstance->mMethodInfoEx->mGenericParams.size(); genericParamIdx++) + { + auto genericParam = mCurMethodInstance->mMethodInfoEx->mGenericParams[genericParamIdx]; + for (auto& opConstraint : genericParam->mOperatorConstraints) + { + if ((opConstraint.mCastToken == BfToken_Implicit) || + ((explicitCast) && (opConstraint.mCastToken == BfToken_Explicit))) + { + // If we can convert OUR fromVal to the constraint's fromVal then we may match + if (CanImplicitlyCast(typedVal, opConstraint.mRightType)) + { + // .. and we can convert the constraint's toType to OUR toType then we're good + auto opToVal = genericParam->mExternType; + if (CanImplicitlyCast(opToVal, toType)) + return mBfIRBuilder->GetFakeVal(); + } + } + } + } + } + + // Check type generic constraints + if ((mCurTypeInstance->IsGenericTypeInstance()) && (mCurTypeInstance->IsUnspecializedType())) + { + auto genericTypeInst = (BfGenericTypeInstance*)mCurTypeInstance; + for (int genericParamIdx = 0; genericParamIdx < genericTypeInst->mGenericParams.size(); genericParamIdx++) + { + auto genericParam = GetGenericTypeParamInstance(genericParamIdx); + for (auto& opConstraint : genericParam->mOperatorConstraints) + { + if ((opConstraint.mCastToken == BfToken_Implicit) || + ((explicitCast) && (opConstraint.mCastToken == BfToken_Explicit))) + { + // If we can convert OUR fromVal to the constraint's fromVal then we may match + if (CanImplicitlyCast(typedVal, opConstraint.mRightType)) + { + // .. and we can convert the constraint's toType to OUR toType then we're good + auto opToVal = genericParam->mExternType; + if (CanImplicitlyCast(opToVal, toType)) + return mBfIRBuilder->GetFakeVal(); + } + } + } + } + } } // Default typed primitive 'underlying casts' happen after checking cast operators @@ -10047,8 +10148,16 @@ BfTypeDef* BfModule::FindCommonOuterType(BfTypeDef* type, BfTypeDef* type2) while (curNestDepth >= 0) { - if (type == type2) - return type; + if ((!type->mIsPartial) && (!type2->mIsPartial)) + { + if (type == type2) + return type; + } + else + { + if (type->mFullNameEx == type2->mFullNameEx) + return type; + } type = type->mOuterType; type2 = type2->mOuterType; curNestDepth--; @@ -10627,7 +10736,11 @@ void BfModule::DoTypeToString(StringImpl& str, BfType* resolvedType, BfTypeNameF } auto genericParamInstance = GetGenericParamInstance(genericParam); - str += genericParamInstance->GetGenericParamDef()->mName; + auto genericParamDef = genericParamInstance->GetGenericParamDef(); + if (genericParamDef != NULL) + str += genericParamInstance->GetGenericParamDef()->mName; + else + str += "external generic " + TypeToString(genericParamInstance->mExternType, typeNameFlags, genericMethodNameOverrides); return; } else if (resolvedType->IsRef()) diff --git a/IDEHelper/Compiler/BfParser.cpp b/IDEHelper/Compiler/BfParser.cpp index 51e888da..15016b4a 100644 --- a/IDEHelper/Compiler/BfParser.cpp +++ b/IDEHelper/Compiler/BfParser.cpp @@ -53,6 +53,7 @@ static bool IsWhitespaceOrPunctuation(char c) case '!': case '%': case '&': + case '|': case '#': case '@': case '`': diff --git a/IDEHelper/Compiler/BfPrinter.cpp b/IDEHelper/Compiler/BfPrinter.cpp index b36cca87..c00b25ea 100644 --- a/IDEHelper/Compiler/BfPrinter.cpp +++ b/IDEHelper/Compiler/BfPrinter.cpp @@ -746,12 +746,14 @@ void BfPrinter::Visit(BfGenericConstraintsDeclaration* genericConstraints) { Visit(genericConstraints->ToBase()); - for (auto genericConstraint : genericConstraints->mGenericConstraints) + for (auto genericConstraintNode : genericConstraints->mGenericConstraints) { + auto genericConstraint = BfNodeDynCast(genericConstraintNode); + ExpectSpace(); VisitChild(genericConstraint->mWhereToken); ExpectSpace(); - VisitChild(genericConstraint->mGenericParamName); + VisitChild(genericConstraint->mTypeRef); ExpectSpace(); VisitChild(genericConstraint->mColonToken); ExpectSpace(); diff --git a/IDEHelper/Compiler/BfReducer.cpp b/IDEHelper/Compiler/BfReducer.cpp index f42ea741..e0545314 100644 --- a/IDEHelper/Compiler/BfReducer.cpp +++ b/IDEHelper/Compiler/BfReducer.cpp @@ -26,120 +26,6 @@ USING_NS_BF; dest->member = src; \ MoveNode(src, dest); } -static BfBinaryOp TokenToBinaryOp(BfToken token) -{ - switch (token) - { - case BfToken_Plus: - return BfBinaryOp_Add; - case BfToken_Minus: - return BfBinaryOp_Subtract; - case BfToken_Star: - return BfBinaryOp_Multiply; - case BfToken_ForwardSlash: - return BfBinaryOp_Divide; - case BfToken_Modulus: - return BfBinaryOp_Modulus; - case BfToken_Ampersand: - return BfBinaryOp_BitwiseAnd; - case BfToken_Bar: - return BfBinaryOp_BitwiseOr; - case BfToken_Carat: - return BfBinaryOp_ExclusiveOr; - case BfToken_LDblChevron: - return BfBinaryOp_LeftShift; - case BfToken_RDblChevron: - return BfBinaryOp_RightShift; - case BfToken_CompareEquals: - return BfBinaryOp_Equality; - case BfToken_CompareNotEquals: - return BfBinaryOp_InEquality; - case BfToken_RChevron: - return BfBinaryOp_GreaterThan; - case BfToken_LChevron: - return BfBinaryOp_LessThan; - case BfToken_GreaterEquals: - return BfBinaryOp_GreaterThanOrEqual; - case BfToken_LessEquals: - return BfBinaryOp_LessThanOrEqual; - case BfToken_Spaceship: - return BfBinaryOp_Compare; - case BfToken_DblAmpersand: - return BfBinaryOp_ConditionalAnd; - case BfToken_DblBar: - return BfBinaryOp_ConditionalOr; - case BfToken_DblQuestion: - return BfBinaryOp_NullCoalesce; - default: - return BfBinaryOp_None; - } -} - -static BfUnaryOp TokenToUnaryOp(BfToken token) -{ - switch (token) - { - case BfToken_Star: - return BfUnaryOp_Dereference; - case BfToken_Ampersand: - return BfUnaryOp_AddressOf; - case BfToken_Minus: - return BfUnaryOp_Negate; - case BfToken_Bang: - return BfUnaryOp_Not; - case BfToken_Plus: - return BfUnaryOp_Positive; - case BfToken_Tilde: - return BfUnaryOp_InvertBits; - case BfToken_DblPlus: - return BfUnaryOp_Increment; - case BfToken_DblMinus: - return BfUnaryOp_Decrement; - case BfToken_Ref: - return BfUnaryOp_Ref; - case BfToken_Mut: - return BfUnaryOp_Mut; - case BfToken_Out: - return BfUnaryOp_Out; - case BfToken_Params: - return BfUnaryOp_Params; - default: - return BfUnaryOp_None; - } -} - - -static BfAssignmentOp TokenToAssignmentOp(BfToken token) -{ - switch (token) - { - case BfToken_AssignEquals: - return BfAssignmentOp_Assign; - case BfToken_PlusEquals: - return BfAssignmentOp_Add; - case BfToken_MinusEquals: - return BfAssignmentOp_Subtract; - case BfToken_MultiplyEquals: - return BfAssignmentOp_Multiply; - case BfToken_DivideEquals: - return BfAssignmentOp_Divide; - case BfToken_ModulusEquals: - return BfAssignmentOp_Modulus; - case BfToken_ShiftLeftEquals: - return BfAssignmentOp_ShiftLeft; - case BfToken_ShiftRightEquals: - return BfAssignmentOp_ShiftRight; - case BfToken_AndEquals: - return BfAssignmentOp_BitwiseAnd; - case BfToken_OrEquals: - return BfAssignmentOp_BitwiseOr; - case BfToken_XorEquals: - return BfAssignmentOp_ExclusiveOr; - default: - return BfAssignmentOp_None; - } -} - BfReducer::BfReducer() { mCurTypeDecl = NULL; @@ -2122,7 +2008,7 @@ BfExpression* BfReducer::CreateExpression(BfAstNode* node, CreateExprFlags creat { BfToken nextToken = nextTokenNode->GetToken(); //TODO: Hm. What other tokens make it into a cast expr? - auto binaryOp = TokenToBinaryOp(nextToken); + auto binaryOp = BfTokenToBinaryOp(nextToken); // When we have a binary operator token following, it COULD either be a "(double)-val" or it COULD be a "(val2)-val" // But we can't tell until we determine whether the thing inside the paren is a type name or a value name, so we // have special code in BfExprEvaluator that can fix those cases at evaluation time @@ -2232,7 +2118,7 @@ BfExpression* BfReducer::CreateExpression(BfAstNode* node, CreateExprFlags creat if (exprLeft == NULL) { - BfUnaryOp unaryOp = TokenToUnaryOp(tokenNode->GetToken()); + BfUnaryOp unaryOp = BfTokenToUnaryOp(tokenNode->GetToken()); if (unaryOp != BfUnaryOp_None) { @@ -2624,7 +2510,7 @@ BfExpression* BfReducer::CreateExpression(BfAstNode* node, CreateExprFlags creat } } - BfBinaryOp binOp = TokenToBinaryOp(tokenNode->GetToken()); + BfBinaryOp binOp = BfTokenToBinaryOp(tokenNode->GetToken()); if (binOp != BfBinaryOp_None) { auto binOpExpression = mAlloc->Alloc(); @@ -2648,7 +2534,7 @@ BfExpression* BfReducer::CreateExpression(BfAstNode* node, CreateExprFlags creat return CheckBinaryOperatorPrecedence(binOpExpression); } - auto assignmentOp = TokenToAssignmentOp(tokenNode->GetToken()); + auto assignmentOp = BfTokenToAssignmentOp(tokenNode->GetToken()); if (assignmentOp != BfAssignmentOp_None) { if ((createExprFlags & CreateExprFlags_NoAssignment) != 0) @@ -3870,21 +3756,7 @@ BfAstNode* BfReducer::DoCreateStatement(BfAstNode* node, CreateStmtFlags createS auto nameNode = ExpectIdentifierAfter(methodDecl); if (nameNode != NULL) { - MEMBER_SET(methodDecl, mNameNode, nameNode); - - auto nextNode = mVisitorPos.GetNext(); - if ((tokenNode = BfNodeDynCast(nextNode))) - { - if (tokenNode->GetToken() == BfToken_LChevron) - { - auto genericParams = CreateGenericParamsDeclaration(tokenNode); - if (genericParams != NULL) - { - MEMBER_SET(methodDecl, mGenericParams, genericParams); - } - } - } - + MEMBER_SET(methodDecl, mNameNode, nameNode); ParseMethod(methodDecl, ¶ms, &commas, true); } @@ -6493,7 +6365,7 @@ BfAstNode* BfReducer::ReadTypeMember(BfAstNode* node, int depth) auto nextNode = mVisitorPos.GetNext(); if (auto nextToken = BfNodeDynCast(nextNode)) { - operatorDecl->mBinOp = TokenToBinaryOp(nextToken->GetToken()); + operatorDecl->mBinOp = BfTokenToBinaryOp(nextToken->GetToken()); if (operatorDecl->mBinOp != BfBinaryOp_None) { MEMBER_SET(operatorDecl, mOpTypeToken, nextToken); @@ -6501,7 +6373,7 @@ BfAstNode* BfReducer::ReadTypeMember(BfAstNode* node, int depth) } else { - operatorDecl->mUnaryOp = TokenToUnaryOp(nextToken->GetToken()); + operatorDecl->mUnaryOp = BfTokenToUnaryOp(nextToken->GetToken()); if (operatorDecl->mUnaryOp != BfUnaryOp_None) { MEMBER_SET(operatorDecl, mOpTypeToken, nextToken); @@ -6509,7 +6381,7 @@ BfAstNode* BfReducer::ReadTypeMember(BfAstNode* node, int depth) } else { - operatorDecl->mAssignOp = TokenToAssignmentOp(nextToken->GetToken()); + operatorDecl->mAssignOp = BfTokenToAssignmentOp(nextToken->GetToken()); if (operatorDecl->mAssignOp == BfAssignmentOp_Assign) { Fail("The assignment operator '=' cannot be overridden", nextToken); @@ -8768,7 +8640,24 @@ BfTokenNode* BfReducer::ParseMethodParams(BfAstNode* node, SizedArrayImpl* params, SizedArrayImpl* commas, bool alwaysIncludeBlock) { - auto tokenNode = ExpectTokenAfter(methodDeclaration, BfToken_LParen, BfToken_Bang); + BfTokenNode* tokenNode; + auto nextNode = mVisitorPos.GetNext(); + if (methodDeclaration->mGenericParams == NULL) + { + if ((tokenNode = BfNodeDynCast(nextNode))) + { + if (tokenNode->GetToken() == BfToken_LChevron) + { + auto genericParams = CreateGenericParamsDeclaration(tokenNode); + if (genericParams != NULL) + { + MEMBER_SET(methodDeclaration, mGenericParams, genericParams); + } + } + } + } + + tokenNode = ExpectTokenAfter(methodDeclaration, BfToken_LParen, BfToken_Bang); if (tokenNode == NULL) return false; if (tokenNode->GetToken() == BfToken_Bang) @@ -8811,7 +8700,7 @@ bool BfReducer::ParseMethod(BfMethodDeclaration* methodDeclaration, SizedArrayIm mVisitorPos.MoveNext(); auto typeDecl = mCurTypeDecl; - auto nextNode = mVisitorPos.GetNext(); + nextNode = mVisitorPos.GetNext(); if ((tokenNode = BfNodeDynCast(nextNode))) { if (tokenNode->GetToken() == BfToken_Mut) @@ -9038,7 +8927,7 @@ BfGenericConstraintsDeclaration* BfReducer::CreateGenericConstraintsDeclaration( bool isDone = false; for (int constraintIdx = 0; !isDone; constraintIdx++) - { + { BfGenericConstraint* genericConstraint = mAlloc->Alloc(); BfDeferredAstSizedArray constraintTypes(genericConstraint->mConstraintTypes, mAlloc); BfDeferredAstSizedArray commas(genericConstraint->mCommas, mAlloc); @@ -9047,11 +8936,12 @@ BfGenericConstraintsDeclaration* BfReducer::CreateGenericConstraintsDeclaration( genericConstraint->mWhereToken = tokenNode; genericConstraintsArr.push_back(genericConstraint); - auto genericParamName = ExpectIdentifierAfter(genericConstraint, "generic parameter name"); + + auto genericParamName = CreateTypeRefAfter(genericConstraint); if (genericParamName != NULL) { - MEMBER_SET(genericConstraint, mGenericParamName, genericParamName); - tokenNode = ExpectTokenAfter(genericConstraint, BfToken_Colon); + MEMBER_SET(genericConstraint, mTypeRef, genericParamName); + tokenNode = ExpectTokenAfter(genericConstraint, BfToken_Colon, BfToken_AssignEquals); } else isDone = true; @@ -9076,7 +8966,6 @@ BfGenericConstraintsDeclaration* BfReducer::CreateGenericConstraintsDeclaration( } tokenNode = ExpectTokenAfter(genericConstraint, BfToken_Comma, BfToken_LBrace, BfToken_Where, BfToken_Semicolon); - if (tokenNode == NULL) { isDone = true; @@ -9098,6 +8987,8 @@ BfGenericConstraintsDeclaration* BfReducer::CreateGenericConstraintsDeclaration( auto nextNode = mVisitorPos.GetNext(); if (auto constraintToken = BfNodeDynCast(nextNode)) { + BfAstNode* constraintNode = NULL; + bool addToConstraint = false; switch (constraintToken->GetToken()) { @@ -9107,13 +8998,43 @@ BfGenericConstraintsDeclaration* BfReducer::CreateGenericConstraintsDeclaration( case BfToken_Var: addToConstraint = true; break; + case BfToken_Operator: + { + BfGenericOperatorConstraint* opConstraint = mAlloc->Alloc(); + constraintNode = opConstraint; + + ReplaceNode(constraintToken, opConstraint); + + MEMBER_SET(opConstraint, mOperatorToken, constraintToken); + mVisitorPos.MoveNext(); + + auto opToken = BfNodeDynCast(mVisitorPos.GetNext()); + if (opToken == NULL) + { + auto typeRef = CreateTypeRefAfter(opConstraint); + if (typeRef == NULL) + break; + MEMBER_SET(opConstraint, mLeftType, typeRef); + opToken = BfNodeDynCast(mVisitorPos.GetNext()); + } + + if (opToken == NULL) + break; + MEMBER_SET(opConstraint, mOpToken, opToken); + mVisitorPos.MoveNext(); + + auto typeRef = CreateTypeRefAfter(opConstraint); + if (typeRef == NULL) + break; + MEMBER_SET(opConstraint, mRightType, typeRef); + } + break; default: break; } if (addToConstraint) { - BfAstNode* constraintNode = constraintToken; - MoveNode(constraintToken, genericConstraint); + constraintNode = constraintToken; bool addToConstraint = false; mVisitorPos.MoveNext(); @@ -9152,8 +9073,12 @@ BfGenericConstraintsDeclaration* BfReducer::CreateGenericConstraintsDeclaration( constraintTypes.push_back(typeRef); continue; - } - + } + } + + if (constraintNode != NULL) + { + MoveNode(constraintNode, genericConstraint); constraintTypes.push_back(constraintNode); continue; } diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp index 262c5d8d..8747b690 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp @@ -3754,6 +3754,15 @@ String BfTypeUtils::TypeToString(BfTypeReference* typeRef) return "???"; } +bool BfTypeUtils::TypeEquals(BfType* typeA, BfType* typeB, BfType* selfType) +{ + if (typeA->IsSelf()) + typeA = selfType; + if (typeB->IsSelf()) + typeB = selfType; + return typeA == typeB; +} + String BfTypeUtils::TypeToString(BfTypeDef* typeDef, BfTypeNameFlags typeNameFlags) { String str; diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.h b/IDEHelper/Compiler/BfResolvedTypeUtils.h index cbdbaf94..3aa3128d 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.h +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.h @@ -930,16 +930,49 @@ public: virtual BfType* GetUnderlyingType() override { return mElementType; } }; +class BfGenericOperatorConstraintInstance +{ +public: + BfType* mLeftType; + BfBinaryOp mBinaryOp; + BfUnaryOp mUnaryOp; + BfToken mCastToken; + BfType* mRightType; + +public: + BfGenericOperatorConstraintInstance() + { + mLeftType = NULL; + mBinaryOp = BfBinaryOp_None; + mUnaryOp = BfUnaryOp_None; + mCastToken = BfToken_None; + mRightType = NULL; + } + + bool operator==(const BfGenericOperatorConstraintInstance& other) const + { + return + (mLeftType == other.mLeftType) && + (mBinaryOp == other.mBinaryOp) && + (mUnaryOp == other.mUnaryOp) && + (mCastToken == other.mCastToken) && + (mRightType == other.mRightType); + } +}; + class BfGenericParamInstance { public: int mGenericParamFlags; + BfType* mExternType; Array mInterfaceConstraints; + Array mOperatorConstraints; BfType* mTypeConstraint; int mRefCount; BfGenericParamInstance() { + mExternType = NULL; mGenericParamFlags = 0; mTypeConstraint = NULL; mRefCount = 1; @@ -954,7 +987,10 @@ public: virtual ~BfGenericParamInstance() { } + virtual BfConstraintDef* GetConstraintDef() = 0; virtual BfGenericParamDef* GetGenericParamDef() = 0; + virtual BfExternalConstraintDef* GetExternConstraintDef() = 0; + virtual String GetName() = 0; }; class BfGenericTypeParamInstance : public BfGenericParamInstance @@ -962,12 +998,13 @@ class BfGenericTypeParamInstance : public BfGenericParamInstance public: BfTypeDef* mTypeDef; int mGenericIdx; + public: BfGenericTypeParamInstance(BfTypeDef* typeDef, int genericIdx) { mTypeDef = typeDef; mGenericIdx = genericIdx; - mGenericParamFlags = GetGenericParamDef()->mGenericParamFlags; + mGenericParamFlags = GetConstraintDef()->mGenericParamFlags; mTypeConstraint = NULL; } @@ -977,9 +1014,32 @@ public: return this; } + virtual BfConstraintDef* GetConstraintDef() override + { + if (mGenericIdx < (int)mTypeDef->mGenericParamDefs.size()) + return mTypeDef->mGenericParamDefs[mGenericIdx]; + return NULL; + } + virtual BfGenericParamDef* GetGenericParamDef() override { - return mTypeDef->mGenericParamDefs[mGenericIdx]; + if (mGenericIdx < (int)mTypeDef->mGenericParamDefs.size()) + return mTypeDef->mGenericParamDefs[mGenericIdx]; + return NULL; + } + + virtual BfExternalConstraintDef* GetExternConstraintDef() override + { + if (mGenericIdx < (int)mTypeDef->mGenericParamDefs.size()) + return NULL; + return NULL; + } + + virtual String GetName() override + { + if (mGenericIdx < (int)mTypeDef->mGenericParamDefs.size()) + return mTypeDef->mGenericParamDefs[mGenericIdx]->mName; + return NULL; } }; @@ -988,12 +1048,13 @@ class BfGenericMethodParamInstance : public BfGenericParamInstance public: BfMethodDef* mMethodDef; int mGenericIdx; + public: BfGenericMethodParamInstance(BfMethodDef* methodDef, int genericIdx) { mMethodDef = methodDef; mGenericIdx = genericIdx; - mGenericParamFlags = GetGenericParamDef()->mGenericParamFlags; + mGenericParamFlags = GetConstraintDef()->mGenericParamFlags; mTypeConstraint = NULL; } @@ -1003,9 +1064,32 @@ public: return this; } + virtual BfConstraintDef* GetConstraintDef() override + { + if (mGenericIdx < (int)mMethodDef->mGenericParams.size()) + return mMethodDef->mGenericParams[mGenericIdx]; + return &mMethodDef->mExternalConstraints[mGenericIdx - (int)mMethodDef->mGenericParams.size()]; + } + virtual BfGenericParamDef* GetGenericParamDef() override { - return mMethodDef->mGenericParams[mGenericIdx]; + if (mGenericIdx < (int)mMethodDef->mGenericParams.size()) + return mMethodDef->mGenericParams[mGenericIdx]; + return NULL; + } + + virtual BfExternalConstraintDef* GetExternConstraintDef() override + { + if (mGenericIdx < (int)mMethodDef->mGenericParams.size()) + return NULL; + return &mMethodDef->mExternalConstraints[mGenericIdx - (int)mMethodDef->mGenericParams.size()]; + } + + virtual String GetName() override + { + if (mGenericIdx < (int)mMethodDef->mGenericParams.size()) + return mMethodDef->mGenericParams[mGenericIdx]->mName; + return mMethodDef->mExternalConstraints[mGenericIdx - (int)mMethodDef->mGenericParams.size()].mTypeRef->ToString(); } }; @@ -2246,6 +2330,7 @@ public: static String TypeToString(BfTypeReference* 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 void GetProjectList(BfType* checkType, Array* projectVector, int immutableLength); diff --git a/IDEHelper/Compiler/BfSourceClassifier.cpp b/IDEHelper/Compiler/BfSourceClassifier.cpp index b858e76e..ba1a9f37 100644 --- a/IDEHelper/Compiler/BfSourceClassifier.cpp +++ b/IDEHelper/Compiler/BfSourceClassifier.cpp @@ -468,11 +468,8 @@ void BfSourceClassifier::Visit(BfMethodDeclaration* methodDeclaration) SetAndRestoreValue prevMember(mCurMember, methodDeclaration); BfElementVisitor::Visit(methodDeclaration); - - BfIdentifierNode* identifier = methodDeclaration->mNameNode; - if (identifier == NULL) - return; - SetElementType(identifier, BfSourceElementType_Method); + + SetElementType(methodDeclaration->mNameNode, BfSourceElementType_Method); if (methodDeclaration->mGenericParams != NULL) { @@ -485,11 +482,14 @@ void BfSourceClassifier::Visit(BfMethodDeclaration* methodDeclaration) if (methodDeclaration->mGenericConstraintsDeclaration != NULL) { - for (auto constraint : methodDeclaration->mGenericConstraintsDeclaration->mGenericConstraints) + for (auto constraintNode : methodDeclaration->mGenericConstraintsDeclaration->mGenericConstraints) { - BfIdentifierNode* typeRef = constraint->mGenericParamName; - if (typeRef != NULL) - SetElementType(typeRef, BfSourceElementType_TypeRef); + if (auto genericConstraint = BfNodeDynCast(constraintNode)) + { + BfTypeReference* typeRef = genericConstraint->mTypeRef; + if (typeRef != NULL) + SetElementType(typeRef, BfSourceElementType_TypeRef); + } } } } @@ -563,9 +563,11 @@ void BfSourceClassifier::Handle(BfTypeDeclaration* typeDeclaration) if (typeDeclaration->mGenericConstraintsDeclaration != NULL) { - for (auto constraint : typeDeclaration->mGenericConstraintsDeclaration->mGenericConstraints) + for (auto constraintNode : typeDeclaration->mGenericConstraintsDeclaration->mGenericConstraints) { - BfIdentifierNode* typeRef = constraint->mGenericParamName; + auto genericConstraint = BfNodeDynCast(constraintNode); + + BfTypeReference* typeRef = genericConstraint->mTypeRef; if (typeRef != NULL) SetElementType(typeRef, BfSourceElementType_TypeRef); } diff --git a/IDEHelper/Compiler/BfSystem.cpp b/IDEHelper/Compiler/BfSystem.cpp index e77924f0..0e1d1ec6 100644 --- a/IDEHelper/Compiler/BfSystem.cpp +++ b/IDEHelper/Compiler/BfSystem.cpp @@ -2379,11 +2379,12 @@ BfTypeDef* BfSystem::FindTypeDefEx(const StringImpl& fullTypeName) int numGenericArgs = 0; String typeName = fullTypeName.Substring(colonPos + 1); - int tildePos = (int)typeName.IndexOf('`'); + int tildePos = (int)typeName.LastIndexOf('`'); if (tildePos != -1) { + BF_ASSERT(tildePos > (int)typeName.LastIndexOf('.')); numGenericArgs = atoi(typeName.c_str() + tildePos + 1); - typeName.RemoveToEnd(tildePos); + typeName.RemoveToEnd(tildePos); } return FindTypeDef(typeName, numGenericArgs, project); @@ -2587,13 +2588,13 @@ void BfSystem::InjectNewRevision(BfTypeDef* typeDef) typeDef->mGenericParamDefs.Clear(); typeDef->mGenericParamDefs = nextTypeDef->mGenericParamDefs; - nextTypeDef->mGenericParamDefs.Clear(); + nextTypeDef->mGenericParamDefs.Clear(); typeDef->mBaseTypes = nextTypeDef->mBaseTypes; typeDef->mNestedTypes = nextTypeDef->mNestedTypes; // If we are a partial then the mOuterType gets set to the combined partial so don't do that here - if (!typeDef->mIsPartial) + if (!typeDef->mIsCombinedPartial) { for (auto nestedType : typeDef->mNestedTypes) { @@ -2658,7 +2659,7 @@ void BfSystem::AddToCompositePartial(BfPassInstance* passInstance, BfTypeDef* co BfGenericParamDef* newGeneric = new BfGenericParamDef(); *newGeneric = *generic; typeDef->mGenericParamDefs.push_back(newGeneric); - } + } typeDef->mBaseTypes = partialTypeDef->mBaseTypes; @@ -2675,7 +2676,7 @@ void BfSystem::AddToCompositePartial(BfPassInstance* passInstance, BfTypeDef* co { typeDef->mTypeCode = partialTypeDef->mTypeCode; typeDef->mTypeDeclaration = partialTypeDef->mTypeDeclaration; - } + } } // Merge attributes together diff --git a/IDEHelper/Compiler/BfSystem.h b/IDEHelper/Compiler/BfSystem.h index 4e6a8606..323ef7d2 100644 --- a/IDEHelper/Compiler/BfSystem.h +++ b/IDEHelper/Compiler/BfSystem.h @@ -574,34 +574,52 @@ public: BfAstNode* GetRefNode(); }; -enum BfGenericParamFlags : uint8 +enum BfGenericParamFlags : uint16 { - BfGenericParamFlag_None = 0, - BfGenericParamFlag_Class = 1, - BfGenericParamFlag_Struct = 2, + BfGenericParamFlag_None = 0, + BfGenericParamFlag_Class = 1, + BfGenericParamFlag_Struct = 2, BfGenericParamFlag_StructPtr = 4, - BfGenericParamFlag_New = 8, - BfGenericParamFlag_Delete = 16, - BfGenericParamFlag_Var = 32, - BfGenericParamFlag_Const = 64 + BfGenericParamFlag_New = 8, + BfGenericParamFlag_Delete = 0x10, + BfGenericParamFlag_Var = 0x20, + BfGenericParamFlag_Const = 0x40, + BfGenericParamFlag_Equals = 0x80, + BfGenericParamFlag_Equals_Op = 0x100, + BfGenericParamFlag_Equals_Type = 0x200, + BfGenericParamFlag_Equals_IFace = 0x400 }; -class BfGenericParamDef +class BfConstraintDef { public: - //BfTypeDef* mOwner; + BfGenericParamFlags mGenericParamFlags; + Array mConstraints; + + BfConstraintDef() + { + mGenericParamFlags = BfGenericParamFlag_None; + } +}; + +class BfGenericParamDef : public BfConstraintDef +{ +public: String mName; - Array mNameNodes; // 0 is always the def name - BfGenericParamFlags mGenericParamFlags; - Array mInterfaceConstraints; + Array mNameNodes; // 0 is always the def name +}; + +class BfExternalConstraintDef : public BfConstraintDef +{ +public: + BfTypeReference* mTypeRef; }; // CTOR is split into two for Objects - Ctor clears and sets up VData, Ctor_Body executes ctor body code enum BfMethodType : uint8 { BfMethodType_Ignore, - BfMethodType_Normal, - //BfMethodType_Lambda, + BfMethodType_Normal, BfMethodType_PropertyGetter, BfMethodType_PropertySetter, BfMethodType_CtorCalcAppend, @@ -658,6 +676,13 @@ enum BfCheckedKind : int8 BfCheckedKind_Unchecked }; +enum BfCommutableKind : int8 +{ + BfCommutableKind_None, + BfCommutableKind_Forward, + BfCommutableKind_Reverse, +}; + class BfMethodDef : public BfMemberDef { public: @@ -668,6 +693,7 @@ public: BfTypeReference* mReturnTypeRef; Array mParams; Array mGenericParams; + Array mExternalConstraints; BfMethodDef* mNextWithSameName; Val128 mFullHash; @@ -694,6 +720,7 @@ public: bool mIsOperator; bool mIsExtern; bool mIsNoDiscard; + BfCommutableKind mCommutableKind; BfCheckedKind mCheckedKind; BfImportKind mImportKind; BfCallingConvention mCallingConvention; @@ -726,6 +753,7 @@ public: mMethodDeclaration = NULL; mCodeChanged = false; mWantsBody = true; + mCommutableKind = BfCommutableKind_None; mCheckedKind = BfCheckedKind_NotSet; mImportKind = BfImportKind_None; mMethodType = BfMethodType_Normal; diff --git a/IDEHelper/Tests/src/Generics.bf b/IDEHelper/Tests/src/Generics.bf new file mode 100644 index 00000000..e9564c36 --- /dev/null +++ b/IDEHelper/Tests/src/Generics.bf @@ -0,0 +1,45 @@ +using System; + +namespace Tests +{ + class Generics + { + class ClassA : IDisposable + { + public void Dispose() + { + + } + } + + static void DoDispose(mut T val) where T : IDisposable + { + val.Dispose(); + } + + struct Disposer + { + static void UseDispose(IDisposable disp) + { + + } + + static void DoDisposeA(mut T val) where T : IDisposable + { + val.Dispose(); + UseDispose(val); + } + + static void DoDisposeB(mut T val) where T : IDisposable + { + val.Dispose(); + } + } + + [Test] + public static void TestBasics() + { + + } + } +} diff --git a/IDEHelper/Tests/src/Operators.bf b/IDEHelper/Tests/src/Operators.bf index 15d9c552..1581fcf6 100644 --- a/IDEHelper/Tests/src/Operators.bf +++ b/IDEHelper/Tests/src/Operators.bf @@ -1,3 +1,5 @@ +#pragma warning disable 168 + using System; namespace Tests @@ -23,6 +25,151 @@ namespace Tests } } + struct StructB + { + public int mB; + + public static StructA operator+(StructA sa, StructB sb) + { + StructA result; + result.mA = sa.mA + sb.mB + 1000; + return result; + } + } + + struct StructOp where T : operator T + T2 + { + public T DoIt(T val, T2 val2) + { + return val + val2; + } + } + + struct StructOp2 + { + public T mVal; + + public static T operator+(StructOp2 lhs, T2 rhs) where T : operator T + T2 + { + return lhs.mVal + rhs; + } + + public static T operator|(StructOp2 lhs, T2 rhs) where T : operator implicit T2 + { + T temp = rhs; + return temp; + } + + public T GetNeg(T2 val) where T : operator -T2 + { + return -val; + } + + public T GetInt() where T : Int + { + return mVal; + } + } + + /*struct OuterOp + { + public struct InnerOp + where T : operator T + T2 + where T : operator -T + where T : operator implicit T2 + { + public static T Op(T val, T2 val2) + { + return val + val2; + } + + public static T Neg(T val) + { + return -val; + } + + public static T Cast(T2 val) + { + return val; + } + + struct InnerOp2 + { + public static T Op(T val, T2 val2) + { + return val + val2; + } + + public static T Neg(T val) + { + return -val; + } + + public static T Cast(T2 val) + { + return val; + } + } + + struct InnerOp3 + { + public static T Op(T val, T2 val2) + { + return val + val2; + } + + public static T Neg(T val) + { + return -val; + } + + public static T Cast(T2 val) + { + return val; + } + } + } + } + + struct OuterOp2 + { + public struct InnerOp + { + + } + + extension InnerOp + where T : operator T + T2 + where T : operator -T + { + public static T Op(T val, T2 val2) + { + return val + val2; + } + + public static T Neg(T val) + { + return -val; + } + } + }*/ + + public static T Op(T val, T2 val2) where T : operator T + T2 + { + return val + val2; + } + + public static T Complex(T val, T2 val2) + where T : operator T + T2 + where T : operator -T + where T : operator implicit T2 + { + T conv = val2; + T result = val + val2; + result = -result; + return result; + } + [Test] public static void TestBasics() { @@ -33,6 +180,40 @@ namespace Tests StructA sa2 = sa0 + sa1; Test.Assert(sa2.mA == 3); + + StructB sb0; + sb0.mB = 11; + StructB sb1; + sb1.mB = 12; + + StructA sa3 = sa0 + sb0; + Test.Assert(sa3.mA == 1012); + + StructA sa4 = Op(sa0, sb0); + Test.Assert(sa4.mA == 1012); + + float val = Op((int32)100, (int16)23); + Test.Assert(val == 123); + + int32 i32res = Complex((int32)100, (int16)23); + Test.Assert(i32res == -123); + + StructOp sOp; + let sa5 = sOp.DoIt(sa1, sb1); + Test.Assert(sa5.mA == 1014); + + StructOp2 sOp2; + sOp2.mVal = 100; + int32 res6 = sOp2 + (int16)40; + Test.Assert(res6 == 140); + int32 res7 = sOp2.GetInt(); + Test.Assert(res7 == 100); + + /*let oai = OuterOp.InnerOp.Op(1.0f, 100); + Test.Assert(oai == 101.0f); + + let oai2 = OuterOp2.InnerOp.Op(2.0f, 200); + Test.Assert(oai2 == 202.0f);*/ } } }