1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-10 04:22:20 +02:00

Fixes for default interface properties and bindings

This commit is contained in:
Brian Fiete 2020-11-19 09:37:43 -08:00
parent 4e5baf3b84
commit 4cae7ff373
3 changed files with 146 additions and 96 deletions

View file

@ -2594,6 +2594,9 @@ BfType* BfExprEvaluator::BindGenericType(BfAstNode* node, BfType* bindType)
if ((mModule->mCurMethodState == NULL) || (mModule->mCurMethodInstance == NULL) || (bindType == NULL)) if ((mModule->mCurMethodState == NULL) || (mModule->mCurMethodInstance == NULL) || (bindType == NULL))
return bindType; return bindType;
if ((mModule->mCurMethodState->mClosureState != NULL) && (mModule->mCurMethodState->mClosureState->mCapturing))
return bindType;
BF_ASSERT(!mModule->mCurMethodInstance->mIsUnspecializedVariation); BF_ASSERT(!mModule->mCurMethodInstance->mIsUnspecializedVariation);
auto parser = node->GetSourceData()->ToParserData(); auto parser = node->GetSourceData()->ToParserData();
@ -2616,10 +2619,6 @@ BfType* BfExprEvaluator::BindGenericType(BfAstNode* node, BfType* bindType)
if (genericTypeBindings == NULL) if (genericTypeBindings == NULL)
return bindType; return bindType;
/*auto itr = mModule->mCurMethodState->mGenericTypeBindings->find(nodeId);
if (itr != mModule->mCurMethodState->mGenericTypeBindings->end())
return itr->second;*/
BfType** typePtr = NULL; BfType** typePtr = NULL;
if (genericTypeBindings->TryGetValue(nodeId, &typePtr)) if (genericTypeBindings->TryGetValue(nodeId, &typePtr))
return *typePtr; return *typePtr;
@ -3640,7 +3639,11 @@ BfTypedValue BfExprEvaluator::LookupIdentifier(BfAstNode* refNode, const StringI
{ {
if (forcedIFaceLookup) if (forcedIFaceLookup)
{ {
if (mPropTarget == thisValue)
{
mPropDefBypassVirtual = true;
mOrigPropTarget = mModule->GetThis();
}
} }
} }
if ((!result) && (mPropDef == NULL)) if ((!result) && (mPropDef == NULL))
@ -3788,6 +3791,20 @@ BfTypedValue BfExprEvaluator::LookupField(BfAstNode* targetSrc, BfTypedValue tar
if ((target.mType != NULL && (target.mType->IsGenericParam()))) if ((target.mType != NULL && (target.mType->IsGenericParam())))
{ {
auto genericParamInst = mModule->GetGenericParamInstance((BfGenericParamType*)target.mType); auto genericParamInst = mModule->GetGenericParamInstance((BfGenericParamType*)target.mType);
if (target.mValue)
{
for (auto iface : genericParamInst->mInterfaceConstraints)
{
auto result = LookupField(targetSrc, BfTypedValue(target.mValue, iface), fieldName, flags);
if ((result) || (mPropDef != NULL))
{
//BindGenericType(targetSrc, iface);
return result;
}
}
}
if (mModule->mCurMethodInstance->mIsUnspecialized) if (mModule->mCurMethodInstance->mIsUnspecialized)
{ {
if (genericParamInst->mTypeConstraint != NULL) if (genericParamInst->mTypeConstraint != NULL)
@ -6414,7 +6431,10 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
if (!methodDef->mIsStatic) if (!methodDef->mIsStatic)
{ {
if ((methodInstance->GetOwner()->IsInterface()) && (!target.mType->IsGenericParam()) && (!target.mType->IsConcreteInterfaceType())) bool ignoreVirtualError = (mModule->mBfIRBuilder->mIgnoreWrites) && (mModule->mCurMethodInstance != NULL) && (mModule->mCurMethodInstance->mIsForeignMethodDef);
if ((methodInstance->GetOwner()->IsInterface()) && (!target.mType->IsGenericParam()) && (!target.mType->IsConcreteInterfaceType()) &&
(!mModule->mCurTypeInstance->IsInterface()) && (!ignoreVirtualError))
{ {
if (methodInstance->mVirtualTableIdx == -1) if (methodInstance->mVirtualTableIdx == -1)
{ {
@ -8301,44 +8321,8 @@ void BfExprEvaluator::LookupQualifiedName(BfQualifiedNameNode* nameNode, bool ig
if (!mResult) if (!mResult)
return; return;
//if (mResult.mType->IsVar())
//ResolveGenericType();
auto origResult = mResult; auto origResult = mResult;
auto lookupType = BindGenericType(nameNode, mResult.mType); auto lookupType = BindGenericType(nameNode, mResult.mType);
if (mResult.mType->IsGenericParam())
{
auto genericParamInst = mModule->GetGenericParamInstance((BfGenericParamType*)mResult.mType);
if (mModule->mCurMethodInstance->mIsUnspecialized)
{
if (genericParamInst->mTypeConstraint != NULL)
mResult.mType = genericParamInst->mTypeConstraint;
else
mResult.mType = mModule->mContext->mBfObjectType;
if ((genericParamInst->mGenericParamFlags & BfGenericParamFlag_Var) != 0)
{
mResult.mType = mModule->GetPrimitiveType(BfTypeCode_Var);
}
}
else
{
if ((genericParamInst->mGenericParamFlags & BfGenericParamFlag_Var) != 0)
{
//mResult.mType = mModule->ResolveGenericType(mResult.mType);
}
else if (genericParamInst->mTypeConstraint != NULL)
{
mResult = mModule->Cast(nameNode, mResult, genericParamInst->mTypeConstraint);
BF_ASSERT(mResult);
}
else
{
// This shouldn't occur - this would infer that we are accessing a member of Object or something...
//mResult.mType = mModule->ResolveGenericType(mResult.mType);
}
}
}
if (mResult.mType->IsVar()) if (mResult.mType->IsVar())
{ {
@ -8346,7 +8330,7 @@ void BfExprEvaluator::LookupQualifiedName(BfQualifiedNameNode* nameNode, bool ig
return; return;
} }
if (!mResult.mType->IsTypeInstance()) if ((!mResult.mType->IsTypeInstance()) && (!mResult.mType->IsGenericParam()))
{ {
if (hadError != NULL) if (hadError != NULL)
*hadError = true; *hadError = true;
@ -8363,7 +8347,6 @@ void BfExprEvaluator::LookupQualifiedName(BfQualifiedNameNode* nameNode, bool ig
SizedArray<BfTypeInstance*, 8> searchConstraints; SizedArray<BfTypeInstance*, 8> searchConstraints;
for (auto ifaceConstraint : genericParamInst->mInterfaceConstraints) for (auto ifaceConstraint : genericParamInst->mInterfaceConstraints)
{ {
//if (std::find(searchConstraints.begin(), searchConstraints.end(), ifaceConstraint) == searchConstraints.end())
if (!searchConstraints.Contains(ifaceConstraint)) if (!searchConstraints.Contains(ifaceConstraint))
{ {
searchConstraints.push_back(ifaceConstraint); searchConstraints.push_back(ifaceConstraint);
@ -8371,7 +8354,6 @@ void BfExprEvaluator::LookupQualifiedName(BfQualifiedNameNode* nameNode, bool ig
for (auto& innerIFaceEntry : ifaceConstraint->mInterfaces) for (auto& innerIFaceEntry : ifaceConstraint->mInterfaces)
{ {
auto innerIFace = innerIFaceEntry.mInterfaceType; auto innerIFace = innerIFaceEntry.mInterfaceType;
//if (std::find(searchConstraints.begin(), searchConstraints.end(), innerIFace) == searchConstraints.end())
if (!searchConstraints.Contains(innerIFace)) if (!searchConstraints.Contains(innerIFace))
{ {
searchConstraints.push_back(innerIFace); searchConstraints.push_back(innerIFace);
@ -8384,7 +8366,6 @@ void BfExprEvaluator::LookupQualifiedName(BfQualifiedNameNode* nameNode, bool ig
BfPropertyDef* prevDef = NULL; BfPropertyDef* prevDef = NULL;
for (auto ifaceConstraint : searchConstraints) for (auto ifaceConstraint : searchConstraints)
{ {
//auto lookupVal = mModule->GetDefaultTypedValue(ifaceConstraint, origResult.IsAddr());
BfTypedValue lookupVal = BfTypedValue(mModule->mBfIRBuilder->GetFakeVal(), ifaceConstraint); BfTypedValue lookupVal = BfTypedValue(mModule->mBfIRBuilder->GetFakeVal(), ifaceConstraint);
mResult = LookupField(nameNode->mRight, lookupVal, fieldName); mResult = LookupField(nameNode->mRight, lookupVal, fieldName);
@ -8502,48 +8483,13 @@ void BfExprEvaluator::LookupQualifiedName(BfAstNode* nameNode, BfIdentifierNode*
mResult.mType = mResult.mType->GetUnderlyingType(); mResult.mType = mResult.mType->GetUnderlyingType();
auto origResult = mResult; auto origResult = mResult;
auto lookupType = BindGenericType(nameNode, mResult.mType);
if (mResult.mType->IsGenericParam())
{
auto genericParamInst = mModule->GetGenericParamInstance((BfGenericParamType*)mResult.mType);
if (mModule->mCurMethodInstance->mIsUnspecialized)
{
if (genericParamInst->mTypeConstraint != NULL)
mResult.mType = genericParamInst->mTypeConstraint;
else
mResult.mType = mModule->mContext->mBfObjectType;
if ((genericParamInst->mGenericParamFlags & BfGenericParamFlag_Var) != 0)
{
mResult.mType = mModule->GetPrimitiveType(BfTypeCode_Var);
}
}
else
{
if ((genericParamInst->mGenericParamFlags & BfGenericParamFlag_Var) != 0)
{
//mResult.mType = mModule->ResolveGenericType(mResult.mType);
}
else if (genericParamInst->mTypeConstraint != NULL)
{
mResult = mModule->Cast(nameNode, mResult, genericParamInst->mTypeConstraint);
BF_ASSERT(mResult);
}
else
{
// This shouldn't occur - this would infer that we are accessing a member of Object or something...
//mResult.mType = mModule->ResolveGenericType(mResult.mType);
}
}
}
if (mResult.mType->IsVar()) if (mResult.mType->IsVar())
{ {
mResult = BfTypedValue(mModule->GetDefaultValue(mResult.mType), mResult.mType, true); mResult = BfTypedValue(mModule->GetDefaultValue(mResult.mType), mResult.mType, true);
return; return;
} }
if (!mResult.mType->IsTypeInstance()) if ((!mResult.mType->IsTypeInstance()) && (!mResult.mType->IsGenericParam()))
{ {
if (mResult.mType->IsSizedArray()) if (mResult.mType->IsSizedArray())
{ {
@ -8565,7 +8511,21 @@ void BfExprEvaluator::LookupQualifiedName(BfAstNode* nameNode, BfIdentifierNode*
} }
BfTypedValue lookupVal = mResult; BfTypedValue lookupVal = mResult;
mResult = LookupField(nameRight, lookupVal, fieldName); auto lookupType = BindGenericType(nameNode, mResult.mType);
if ((lookupType->IsGenericParam()) && (!mResult.mType->IsGenericParam()))
{
// Try to lookup from generic binding
mResult = LookupField(nameRight, BfTypedValue(mModule->mBfIRBuilder->GetFakeVal(), lookupType), fieldName);
if (mPropDef != NULL)
{
mOrigPropTarget = lookupVal;
return;
}
}
if (mPropDef == NULL)
mResult = LookupField(nameRight, lookupVal, fieldName);
if ((!mResult) && (mPropDef == NULL) && (lookupType->IsGenericParam())) if ((!mResult) && (mPropDef == NULL) && (lookupType->IsGenericParam()))
{ {
auto genericParamInst = mModule->GetGenericParamInstance((BfGenericParamType*)lookupType); auto genericParamInst = mModule->GetGenericParamInstance((BfGenericParamType*)lookupType);
@ -15474,9 +15434,12 @@ BfModuleMethodInstance BfExprEvaluator::GetPropertyMethodInstance(BfMethodDef* m
auto curTypeInst = mPropTarget.mType->ToTypeInstance(); auto curTypeInst = mPropTarget.mType->ToTypeInstance();
if (mModule->TypeIsSubTypeOf(mModule->mCurTypeInstance, curTypeInst)) if (mModule->TypeIsSubTypeOf(mModule->mCurTypeInstance, curTypeInst))
{ {
// This is an explicit call to a default static interface method. We pull the methodDef into our own concrete type. if (methodDef->mBody != NULL)
mPropTarget = mModule->GetThis(); {
return mModule->GetMethodInstance(mModule->mCurTypeInstance, methodDef, BfTypeVector(), BfGetMethodInstanceFlag_ForeignMethodDef, curTypeInst); // This is an explicit call to a default static interface method. We pull the methodDef into our own concrete type.
mPropTarget = mModule->GetThis();
return mModule->GetMethodInstance(mModule->mCurTypeInstance, methodDef, BfTypeVector(), BfGetMethodInstanceFlag_ForeignMethodDef, curTypeInst);
}
} }
else else
{ {
@ -15688,9 +15651,15 @@ BfTypedValue BfExprEvaluator::GetResult(bool clearResult, bool resolveGenericTyp
return mResult; return mResult;
} }
if (matchedMethod->mName == "get__Hitbox")
{
NOP;
}
auto methodInstance = GetPropertyMethodInstance(matchedMethod); auto methodInstance = GetPropertyMethodInstance(matchedMethod);
if (methodInstance.mMethodInstance == NULL) if (methodInstance.mMethodInstance == NULL)
return mResult; return mResult;
BF_ASSERT(methodInstance.mMethodInstance->mMethodDef->mName == matchedMethod->mName);
if (!mModule->mBfIRBuilder->mIgnoreWrites) if (!mModule->mBfIRBuilder->mIgnoreWrites)
{ {
BF_ASSERT(!methodInstance.mFunc.IsFake()); BF_ASSERT(!methodInstance.mFunc.IsFake());
@ -15722,8 +15691,14 @@ BfTypedValue BfExprEvaluator::GetResult(bool clearResult, bool resolveGenericTyp
SizedArray<BfIRValue, 4> args; SizedArray<BfIRValue, 4> args;
if (!matchedMethod->mIsStatic) if (!matchedMethod->mIsStatic)
{ {
if ((mPropDefBypassVirtual) && (mPropTarget.mType != methodInstance.mMethodInstance->GetOwner())) auto owner = methodInstance.mMethodInstance->GetOwner();
mPropTarget = mModule->Cast(mPropSrc, mOrigPropTarget, methodInstance.mMethodInstance->GetOwner()); if (mPropTarget.mType != owner)
{
/*if (owner->IsInterface())
mPropTarget = mModule->Cast(mPropSrc, mPropTarget, owner);
else */ if (mPropDefBypassVirtual)
mPropTarget = mModule->Cast(mPropSrc, mOrigPropTarget, owner);
}
if ((mPropGetMethodFlags & BfGetMethodInstanceFlag_DisableObjectAccessChecks) == 0) if ((mPropGetMethodFlags & BfGetMethodInstanceFlag_DisableObjectAccessChecks) == 0)
mModule->EmitObjectAccessCheck(mPropTarget); mModule->EmitObjectAccessCheck(mPropTarget);
@ -16616,7 +16591,7 @@ void BfExprEvaluator::PerformAssignment(BfAssignmentExpression* assignExpr, bool
auto methodInstance = GetPropertyMethodInstance(setMethod); auto methodInstance = GetPropertyMethodInstance(setMethod);
if (methodInstance.mMethodInstance == NULL) if (methodInstance.mMethodInstance == NULL)
return; return;
BF_ASSERT(methodInstance.mMethodInstance->mMethodDef == setMethod); //BF_ASSERT(methodInstance.mMethodInstance->mMethodDef == setMethod);
CheckPropFail(setMethod, methodInstance.mMethodInstance, (mPropGetMethodFlags & BfGetMethodInstanceFlag_Friend) == 0); CheckPropFail(setMethod, methodInstance.mMethodInstance, (mPropGetMethodFlags & BfGetMethodInstanceFlag_Friend) == 0);
auto autoComplete = GetAutoComplete(); auto autoComplete = GetAutoComplete();
@ -16670,6 +16645,13 @@ void BfExprEvaluator::PerformAssignment(BfAssignmentExpression* assignExpr, bool
SizedArray<BfIRValue, 4> args; SizedArray<BfIRValue, 4> args;
if (!setMethod->mIsStatic) if (!setMethod->mIsStatic)
{ {
auto owner = methodInstance.mMethodInstance->GetOwner();
if (mPropTarget.mType != owner)
{
if (mPropDefBypassVirtual)
mPropTarget = mModule->Cast(mPropSrc, mOrigPropTarget, owner);
}
mModule->EmitObjectAccessCheck(mPropTarget); mModule->EmitObjectAccessCheck(mPropTarget);
PushThis(mPropSrc, mPropTarget, methodInstance.mMethodInstance, args); PushThis(mPropSrc, mPropTarget, methodInstance.mMethodInstance, args);
} }

View file

@ -9728,6 +9728,15 @@ BfModuleMethodInstance BfModule::GetMethodInstanceAtIdx(BfTypeInstance* typeInst
auto methodInstance = typeInstance->mMethodInstanceGroups[methodIdx].mDefault; auto methodInstance = typeInstance->mMethodInstanceGroups[methodIdx].mDefault;
BfMethodDef* methodDef = NULL;
BfTypeInstance* foreignType = NULL;
if (methodInstance != NULL)
{
methodDef = methodInstance->mMethodDef;
if (methodInstance->mMethodInfoEx != NULL)
foreignType = methodInstance->mMethodInfoEx->mForeignType;
}
if ((methodInstance != NULL) && (mIsReified) && (!methodInstance->mIsReified)) if ((methodInstance != NULL) && (mIsReified) && (!methodInstance->mIsReified))
{ {
// Can't use it, not reified // Can't use it, not reified
@ -9741,6 +9750,8 @@ BfModuleMethodInstance BfModule::GetMethodInstanceAtIdx(BfTypeInstance* typeInst
return BfModuleMethodInstance(methodInstance, func); return BfModuleMethodInstance(methodInstance, func);
} }
if (foreignType != NULL)
return GetMethodInstance(typeInstance, methodDef, BfTypeVector(), (BfGetMethodInstanceFlags)(flags | BfGetMethodInstanceFlag_ForeignMethodDef), foreignType);
return GetMethodInstance(typeInstance, typeInstance->mTypeDef->mMethods[methodIdx], BfTypeVector(), flags); return GetMethodInstance(typeInstance, typeInstance->mTypeDef->mMethods[methodIdx], BfTypeVector(), flags);
} }

View file

@ -101,6 +101,58 @@ namespace Tests
} }
} }
public struct Rect
{
public float x, y, width, height;
}
public class Component
{
}
public class Hitbox : Component
{
public Rect mArea = .() { x=1, y=2, width=3, height=4, };
}
public interface IEntity
{
public T GetComponent<T>() where T : Component;
}
public interface IHitbox : IEntity
{
public Hitbox HitboxValue { get; set; }
public Hitbox Hitbox
{
get
{
if (HitboxValue == null)
{
HitboxValue = GetComponent<Hitbox>();
}
return HitboxValue;
}
}
}
class GameItem : IEntity, IHitbox
{
public T GetComponent<T>() where T : Component
{
return new T();
}
public Hitbox HitboxValue { get; set; }
}
static Hitbox GetHitbox<T>(T val) where T : IHitbox
{
return val.Hitbox;
}
[Test] [Test]
public static void TestBasics() public static void TestBasics()
{ {
@ -130,6 +182,11 @@ namespace Tests
IFaceA ifa = cba; IFaceA ifa = cba;
Test.Assert(ifa.GetType() == typeof(ClassB)); Test.Assert(ifa.GetType() == typeof(ClassB));
GameItem gameItem = scope .();
var hitbox = GetHitbox(gameItem);
Test.Assert(hitbox.mArea == .() { x=1, y=2, width=3, height=4 });
delete hitbox;
} }
//// ////