diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 37897150..d731402b 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -6551,6 +6551,18 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp if (target) { + // Turn T* into a T, if we can + if ((target.mType->IsPointer()) && (target.mType->GetUnderlyingType()->IsGenericParam())) + { + auto underlyingType = target.mType->GetUnderlyingType(); + auto genericParam = mModule->GetGenericParamInstance((BfGenericParamType*)underlyingType); + if (((genericParam->mTypeConstraint != NULL) && (genericParam->mTypeConstraint->IsValueType())) || + ((genericParam->mGenericParamFlags & (BfGenericParamFlag_Struct)) != 0)) + { + target.mType = underlyingType; + } + } + if ((!target.mType->IsGenericParam()) && (!target.IsSplat()) && (!target.mType->IsVar())) target = MakeCallableTarget(targetSrc, target); } @@ -6682,6 +6694,7 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp BfTypeDef* curTypeDef = NULL; BfTypeInstance* targetTypeInst = NULL; bool checkNonStatic = true; + if (target) { if (targetType->IsVar()) @@ -12740,14 +12753,26 @@ BfAllocTarget BfExprEvaluator::ResolveAllocTarget(BfAstNode* allocNode, BfTokenN } BfTypedValue BfExprEvaluator::MakeCallableTarget(BfAstNode* targetSrc, BfTypedValue target) -{ - if (((target.mType->IsRef()) || (target.mType->IsPointer())) && - (target.mType->GetUnderlyingType()->IsStruct())) - { - auto pointerType = (BfPointerType*) target.mType; - target = mModule->LoadValue(target); - target.mType = pointerType->mElementType; - target.mKind = BfTypedValueKind_Addr; +{ + if ((target.mType->IsRef()) || (target.mType->IsPointer())) + { + auto underlying = target.mType->GetUnderlyingType(); + bool underlyingIsStruct = underlying->IsStruct(); +// if (underlying->IsGenericParam()) +// { +// auto genericParam = mModule->GetGenericParamInstance((BfGenericParamType*)underlying); +// if (((genericParam->mTypeConstraint != NULL) && (genericParam->mTypeConstraint->IsValueType())) || +// ((genericParam->mGenericParamFlags & (BfGenericParamFlag_Struct)) != 0)) +// underlyingIsStruct = true; +// } + + if (underlyingIsStruct) + { + auto pointerType = (BfPointerType*)target.mType; + target = mModule->LoadValue(target); + target.mType = pointerType->mElementType; + target.mKind = BfTypedValueKind_Addr; + } } if ((target.mType->IsStruct()) && (!target.IsAddr())) diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index 3392886f..0fbe09a6 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -8130,7 +8130,21 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula if (resolvedType != NULL) { if (resolvedType->IsGenericParam()) - resolvedType = CreateModifiedTypeType(resolvedType, BfToken_AllocType); + { + auto genericParam = GetGenericParamInstance((BfGenericParamType*)resolvedType); + if (((genericParam->mTypeConstraint != NULL) && (genericParam->mTypeConstraint->IsValueType())) || + ((genericParam->mGenericParamFlags & (BfGenericParamFlag_Struct | BfGenericParamFlag_StructPtr)) != 0)) + { + resolvedType = CreatePointerType(resolvedType); + } + else if (((genericParam->mTypeConstraint != NULL) && (!genericParam->mTypeConstraint->IsValueType())) || + ((genericParam->mGenericParamFlags & (BfGenericParamFlag_Class)) != 0)) + { + // Leave as 'T' + } + else + resolvedType = CreateModifiedTypeType(resolvedType, BfToken_AllocType); + } else if (resolvedType->IsValueType()) resolvedType = CreatePointerType(resolvedType); } diff --git a/IDEHelper/Tests/src/Generics.bf b/IDEHelper/Tests/src/Generics.bf index 7a54a555..baee9cbc 100644 --- a/IDEHelper/Tests/src/Generics.bf +++ b/IDEHelper/Tests/src/Generics.bf @@ -1,3 +1,5 @@ +#pragma warning disable 168 + using System; using System.Collections; @@ -124,6 +126,29 @@ namespace Tests } } + public static void Alloc0() where T : new, delete, IDisposable + { + alloctype(T) val = new T(); + val.Dispose(); + delete val; + } + + public static void Alloc1() where T : new, delete, IDisposable, Object + { + alloctype(T) val = new T(); + T val2 = val; + val.Dispose(); + delete val; + } + + public static void Alloc2() where T : new, delete, IDisposable, struct + { + alloctype(T) val = new T(); + T* val2 = val; + val2.Dispose(); + delete val; + } + [Test] public static void TestBasics() { @@ -169,7 +194,7 @@ namespace Tests Test.Assert(totals == 10+20+30+40+50); } - public static mixin TransformArray(Input[InputSize] array, delegate void(Input, ref Output) predicate) where InputSize : const int where Output : new + public static mixin TransformArray(Input[InputSize] array, delegate void(Input, ref Output) predicate) where InputSize : const int where Output : new, class { Output[2] output = default; for (int i = 0; i < array.Count; i++)