1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-08 11:38:21 +02:00

Added nullable(T), Result<T> can use null conditionals

This commit is contained in:
Brian Fiete 2020-04-27 15:09:10 -07:00
parent 336226d686
commit 68bf7bc801
19 changed files with 343 additions and 210 deletions

View file

@ -59,6 +59,15 @@ namespace System
return default(T);
}
public static nullable(T) operator?(Self val)
{
switch (val)
{
case .Ok(let inner): return inner;
case .Err: return null;
}
}
[SkipCall]
public void Dispose()
{
@ -151,6 +160,15 @@ namespace System
return default(T);
}
public static nullable(T) operator?(Self val)
{
switch (val)
{
case .Ok(let inner): return inner;
case .Err: return null;
}
}
[SkipCall]
public void Dispose()
{

View file

@ -50,6 +50,15 @@ namespace System
return default(T);
}
public static nullable(T) operator?(Self val)
{
switch (val)
{
case .Ok(let inner): return inner;
case .Err: return null;
}
}
[SkipCall]
public void Dispose()
{
@ -84,6 +93,18 @@ namespace System
}
}
/*extension Result<T> where T : class
{
public static T operator?(Self val)
{
switch (val)
{
case .Ok(let inner): return inner;
case .Err: return default;
}
}
}*/
enum Result<T, TErr>
{
case Ok(T val);
@ -138,6 +159,15 @@ namespace System
return default(T);
}
public static nullable(T) operator?(Self val)
{
switch (val)
{
case .Ok(let inner): return inner;
case .Err: return null;
}
}
[SkipCall]
public void Dispose()
{

View file

@ -149,6 +149,7 @@ enum BfToken : uint8
BfToken_Namespace,
BfToken_New,
BfToken_Null,
BfToken_Nullable,
BfToken_Operator,
BfToken_Out,
BfToken_Override,
@ -359,7 +360,7 @@ class BfGenericConstraintsDeclaration;
class BfAttributeDirective;
class BfNullableTypeRef;
class BfRefTypeRef;
class BfRetTypeTypeRef;
class BfModifiedTypeRef;
class BfConstTypeRef;
class BfConstExprTypeRef;
class BfInlineAsmStatement;
@ -443,7 +444,7 @@ public:
virtual void Visit(BfConstTypeRef* typeRef);
virtual void Visit(BfConstExprTypeRef* typeRef);
virtual void Visit(BfRefTypeRef* typeRef);
virtual void Visit(BfRetTypeTypeRef* typeRef);
virtual void Visit(BfModifiedTypeRef* typeRef);
virtual void Visit(BfArrayTypeRef* typeRef);
virtual void Visit(BfGenericInstanceTypeRef* typeRef);
virtual void Visit(BfTupleTypeRef* typeRef);
@ -1737,6 +1738,7 @@ enum BfUnaryOp
BfUnaryOp_Decrement,
BfUnaryOp_PostIncrement,
BfUnaryOp_PostDecrement,
BfUnaryOp_NullConditional,
BfUnaryOp_Ref,
BfUnaryOp_Out,
BfUnaryOp_Mut,
@ -2317,15 +2319,15 @@ public:
ASTREF(BfTypeReference*) mElementType;
}; BF_AST_DECL(BfElementedTypeRef, BfTypeReference);
class BfRetTypeTypeRef : public BfElementedTypeRef
class BfModifiedTypeRef : public BfElementedTypeRef
{
public:
BF_AST_TYPE(BfRetTypeTypeRef, BfElementedTypeRef);
BF_AST_TYPE(BfModifiedTypeRef, BfElementedTypeRef);
BfTokenNode* mRetTypeToken;
BfTokenNode* mOpenParen;
BfTokenNode* mCloseParen;
}; BF_AST_DECL(BfRetTypeTypeRef, BfElementedTypeRef);
}; BF_AST_DECL(BfModifiedTypeRef, BfElementedTypeRef);
class BfArrayTypeRef : public BfElementedTypeRef
{
@ -3195,6 +3197,7 @@ BfBinaryOp BfGetFlippedBinaryOp(BfBinaryOp origOp);
int BfGetBinaryOpPrecendence(BfBinaryOp binOp);
const char* BfGetOpName(BfBinaryOp binOp);
const char* BfGetOpName(BfUnaryOp unaryOp);
bool BfCanOverloadOperator(BfUnaryOp unaryOp);
BfBinaryOp BfTokenToBinaryOp(BfToken token);
BfUnaryOp BfTokenToUnaryOp(BfToken token);
BfAssignmentOp BfTokenToAssignmentOp(BfToken token);

View file

@ -1511,6 +1511,16 @@ bool BfAutoComplete::CheckMemberReference(BfAstNode* target, BfAstNode* dotToken
{
if (dotTokenNode->GetToken() == BfToken_QuestionDot)
{
if (!targetValue.mType->IsNullable())
{
// We need this for Result<T>
SetAndRestoreValue<bool> prevIgnore(mModule->mBfIRBuilder->mIgnoreWrites, true);
BfExprEvaluator exprEvaluator(mModule);
auto opResult = exprEvaluator.PerformUnaryOperation_TryOperator(targetValue, NULL, BfUnaryOp_NullConditional, dotTokenNode);
if (opResult)
targetValue = opResult;
}
// ?. should look inside nullable types
if (targetValue.mType->IsNullable())
{

View file

@ -4150,7 +4150,7 @@ void BfCompiler::AddToRebuildTypeList(BfTypeInstance* typeInst, HashSet<BfTypeIn
bool allowRebuild = ((!typeInst->IsGenericTypeInstance()) ||
((typeInst->IsUnspecializedType()) && (!typeInst->IsUnspecializedTypeVariation())));
if ((typeInst->IsClosure()) || (typeInst->IsConcreteInterfaceType()) || (typeInst->IsRetTypeType()))
if ((typeInst->IsClosure()) || (typeInst->IsConcreteInterfaceType()) || (typeInst->IsModifiedTypeType()))
allowRebuild = false;
if (allowRebuild)
rebuildTypeInstList.Add(typeInst);

View file

@ -370,7 +370,7 @@ public:
BfAllocPool<BfBoxedType> mBoxedTypePool;
BfAllocPool<BfTupleType> mTupleTypePool;
BfAllocPool<BfRefType> mRefTypePool;
BfAllocPool<BfRetTypeType> mRetTypeTypePool;
BfAllocPool<BfModifiedTypeType> mRetTypeTypePool;
BfAllocPool<BfGenericTypeInstance> mGenericTypeInstancePool;
BfAllocPool<BfGenericTypeAliasType> mGenericTypeAliasPool;
BfAllocPool<BfArrayType> mArrayTypeInstancePool;

View file

@ -325,7 +325,7 @@ void BfElementVisitor::Visit(BfRefTypeRef* typeRef)
VisitChild(typeRef->mElementType);
}
void BfElementVisitor::Visit(BfRetTypeTypeRef * typeRef)
void BfElementVisitor::Visit(BfModifiedTypeRef * typeRef)
{
Visit((BfTypeReference*)typeRef); // Skip the Elemented part so we can put the element in the right spot

View file

@ -54,7 +54,7 @@ public:
virtual void Visit(BfConstTypeRef* typeRef);
virtual void Visit(BfConstExprTypeRef* typeRef);
virtual void Visit(BfRefTypeRef* typeRef);
virtual void Visit(BfRetTypeTypeRef* typeRef);
virtual void Visit(BfModifiedTypeRef* typeRef);
virtual void Visit(BfArrayTypeRef* typeRef);
virtual void Visit(BfGenericInstanceTypeRef* typeRef);
virtual void Visit(BfTupleTypeRef* typeRef);

View file

@ -6695,7 +6695,7 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
delegateFailed = false;
if (mModule->mCurMethodInstance->mIsUnspecialized)
{
auto retTypeType = mModule->CreateRetTypeType(fieldVal.mType);
auto retTypeType = mModule->CreateModifiedTypeType(fieldVal.mType, BfToken_RetType);
return mModule->GetFakeTypedValue(retTypeType);
}
}
@ -15919,6 +15919,10 @@ BfTypedValue BfExprEvaluator::SetupNullConditional(BfTypedValue thisValue, BfTok
return thisValue;
}
auto opResult = PerformUnaryOperation_TryOperator(thisValue, NULL, BfUnaryOp_NullConditional, dotToken);
if (opResult)
thisValue = opResult;
//TODO: But make null conditional work for Nullable types
if (thisValue.mType->IsNullable())
{
@ -15956,6 +15960,7 @@ BfTypedValue BfExprEvaluator::SetupNullConditional(BfTypedValue thisValue, BfTok
}
BfIRValue isNotNull;
if (thisValue.mType->IsNullable())
{
BfGenericTypeInstance* nullableType = (BfGenericTypeInstance*)thisValue.mType->ToTypeInstance();
@ -16645,35 +16650,17 @@ void BfExprEvaluator::PerformUnaryOperation(BfExpression* unaryOpExpr, BfUnaryOp
BfExprEvaluator::PerformUnaryOperation_OnResult(unaryOpExpr, unaryOp, opToken);
}
void BfExprEvaluator::PerformUnaryOperation_OnResult(BfExpression* unaryOpExpr, BfUnaryOp unaryOp, BfTokenNode* opToken)
BfTypedValue BfExprEvaluator::PerformUnaryOperation_TryOperator(const BfTypedValue& inValue, BfExpression* unaryOpExpr, BfUnaryOp unaryOp, BfTokenNode* opToken)
{
BfAstNode* propSrc = mPropSrc;
BfTypedValue propTarget = mPropTarget;
BfPropertyDef* propDef = mPropDef;
SizedArray<BfResolvedArg, 2> indexerVals = mIndexerValues;
BfTypedValue writeToProp;
if ((!inValue.mType->IsTypeInstance()) && (!inValue.mType->IsGenericParam()))
return BfTypedValue();
GetResult();
if (!mResult)
return;
if (mResult.mType->IsRef())
mResult.mType = mResult.mType->GetUnderlyingType();
if (mResult.mType->IsVar())
{
mResult = BfTypedValue(mModule->GetDefaultValue(mResult.mType), mResult.mType);
return;
}
if ((mResult.mType->IsTypeInstance()) || (mResult.mType->IsGenericParam()))
{
SizedArray<BfResolvedArg, 1> args;
BfResolvedArg resolvedArg;
resolvedArg.mTypedValue = mResult;
resolvedArg.mTypedValue = inValue;
args.push_back(resolvedArg);
BfMethodMatcher methodMatcher(opToken, mModule, "", args, NULL);
BfBaseClassWalker baseClassWalker(mResult.mType, NULL, mModule);
BfBaseClassWalker baseClassWalker(inValue.mType, NULL, mModule);
BfUnaryOp findOp = unaryOp;
bool isPostOp = false;
@ -16709,35 +16696,8 @@ void BfExprEvaluator::PerformUnaryOperation_OnResult(BfExpression* unaryOpExpr,
}
}
if (methodMatcher.mBestMethodDef != NULL)
if (methodMatcher.mBestMethodDef == NULL)
{
if (!baseClassWalker.mMayBeFromInterface)
mModule->SetElementType(opToken, BfSourceElementType_Method);
auto methodDef = methodMatcher.mBestMethodDef;
auto autoComplete = GetAutoComplete();
if ((autoComplete != NULL) && (autoComplete->IsAutocompleteNode(opToken)))
{
auto operatorDecl = BfNodeDynCast<BfOperatorDeclaration>(methodDef->mMethodDeclaration);
if ((operatorDecl != NULL) && (operatorDecl->mOpTypeToken != NULL))
autoComplete->SetDefinitionLocation(operatorDecl->mOpTypeToken);
}
SizedArray<BfExpression*, 2> argSrcs;
argSrcs.push_back(unaryOpExpr);
mResult = CreateCall(&methodMatcher, BfTypedValue());
if ((mResult.mType != NULL) && (methodMatcher.mSelfType != NULL) && (mResult.mType->IsSelf()))
{
BF_ASSERT(mModule->IsInGeneric());
mResult = mModule->GetDefaultTypedValue(methodMatcher.mSelfType);
}
if (isPostOp)
mResult = args[0].mTypedValue;
return;
}
// Check method generic constraints
if ((mModule->mCurMethodInstance != NULL) && (mModule->mCurMethodInstance->mIsUnspecialized) && (mModule->mCurMethodInstance->mMethodInfoEx != NULL))
{
@ -16750,8 +16710,7 @@ void BfExprEvaluator::PerformUnaryOperation_OnResult(BfExpression* unaryOpExpr,
{
if (mModule->CanCast(args[0].mTypedValue, opConstraint.mRightType))
{
mResult = BfTypedValue(mModule->mBfIRBuilder->GetFakeVal(), genericParam->mExternType);
return;
return BfTypedValue(mModule->mBfIRBuilder->GetFakeVal(), genericParam->mExternType);
}
}
}
@ -16771,12 +16730,71 @@ void BfExprEvaluator::PerformUnaryOperation_OnResult(BfExpression* unaryOpExpr,
{
if (mModule->CanCast(args[0].mTypedValue, opConstraint.mRightType))
{
mResult = BfTypedValue(mModule->mBfIRBuilder->GetFakeVal(), genericParam->mExternType);
return BfTypedValue(mModule->mBfIRBuilder->GetFakeVal(), genericParam->mExternType);
}
}
}
}
}
return BfTypedValue();
}
if (!baseClassWalker.mMayBeFromInterface)
mModule->SetElementType(opToken, BfSourceElementType_Method);
auto methodDef = methodMatcher.mBestMethodDef;
auto autoComplete = GetAutoComplete();
if ((autoComplete != NULL) && (autoComplete->IsAutocompleteNode(opToken)))
{
auto operatorDecl = BfNodeDynCast<BfOperatorDeclaration>(methodDef->mMethodDeclaration);
if ((operatorDecl != NULL) && (operatorDecl->mOpTypeToken != NULL))
autoComplete->SetDefinitionLocation(operatorDecl->mOpTypeToken);
}
SizedArray<BfExpression*, 2> argSrcs;
argSrcs.push_back(unaryOpExpr);
auto result = CreateCall(&methodMatcher, BfTypedValue());
if ((result.mType != NULL) && (methodMatcher.mSelfType != NULL) && (result.mType->IsSelf()))
{
BF_ASSERT(mModule->IsInGeneric());
result = mModule->GetDefaultTypedValue(methodMatcher.mSelfType);
}
if (isPostOp)
result = args[0].mTypedValue;
return result;
}
void BfExprEvaluator::PerformUnaryOperation_OnResult(BfExpression* unaryOpExpr, BfUnaryOp unaryOp, BfTokenNode* opToken)
{
BfAstNode* propSrc = mPropSrc;
BfTypedValue propTarget = mPropTarget;
BfPropertyDef* propDef = mPropDef;
SizedArray<BfResolvedArg, 2> indexerVals = mIndexerValues;
BfTypedValue writeToProp;
GetResult();
if (!mResult)
return;
if (mResult.mType->IsRef())
mResult.mType = mResult.mType->GetUnderlyingType();
if (mResult.mType->IsVar())
{
mResult = BfTypedValue(mModule->GetDefaultValue(mResult.mType), mResult.mType);
return;
}
}
}
}
if (BfCanOverloadOperator(unaryOp))
{
auto opResult = PerformUnaryOperation_TryOperator(mResult, unaryOpExpr, unaryOp, opToken);
if (opResult)
{
mResult = opResult;
return;
}
}

View file

@ -389,6 +389,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);
BfTypedValue PerformUnaryOperation_TryOperator(const BfTypedValue& inValue, 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);

View file

@ -2050,7 +2050,7 @@ void BfIRBuilder::CreateTypeDeclaration(BfType* type, bool forceDbgDefine)
trackDIType = true;
}
}
else if ((type->IsGenericParam()) || (type->IsRetTypeType()))
else if ((type->IsGenericParam()) || (type->IsModifiedTypeType()))
{
//mModule->PopulateType(mModule->mContext->mBfObjectType, BfPopulateType_Declaration);
irType = MapType(mModule->mContext->mBfObjectType);

View file

@ -539,10 +539,15 @@ void BfGNUMangler::Mangle(MangleContext& mangleContext, StringImpl& name, BfType
AddPrefix(mangleContext, name, startIdx, "R");
return;
}
else if (type->IsRetTypeType())
else if (type->IsModifiedTypeType())
{
BfRetTypeType* retTypeType = (BfRetTypeType*)type;
BfModifiedTypeType* retTypeType = (BfModifiedTypeType*)type;
if (retTypeType->mModifiedKind == BfToken_RetType)
name += "U7rettype";
else if (retTypeType->mModifiedKind == BfToken_Nullable)
name += "U8nullable";
else
BF_FATAL("Unhandled");
Mangle(mangleContext, name, retTypeType->mElementType);
return;
}
@ -1573,10 +1578,15 @@ void BfMSMangler::Mangle(MangleContext& mangleContext, StringImpl& name, BfType*
name += "out$";
Mangle(mangleContext, name, refType->mElementType);
}
else if (type->IsRetTypeType())
else if (type->IsModifiedTypeType())
{
auto retType = (BfRetTypeType*)type;
auto retType = (BfModifiedTypeType*)type;
if (retType->mModifiedKind == BfToken_RetType)
name += "rettype$";
else if (retType->mModifiedKind == BfToken_Nullable)
name += "nullable$";
else
BF_FATAL("Unhandled");
Mangle(mangleContext, name, retType->mElementType);
}
else if (type->IsConcreteInterfaceType())

View file

@ -1352,7 +1352,7 @@ BfIRValue BfModule::GetDefaultValue(BfType* type)
}
if (type->IsPointer() || type->IsObjectOrInterface() || type->IsGenericParam() || type->IsVar() || type->IsRef() || type->IsNull() ||
type->IsRetTypeType() || type->IsConcreteInterfaceType())
type->IsModifiedTypeType() || type->IsConcreteInterfaceType())
return mBfIRBuilder->CreateConstNull(mBfIRBuilder->MapType(type));
if ((type->IsIntegral()) || (type->IsBoolean()))
{

View file

@ -1628,7 +1628,7 @@ public:
BfTupleType* CreateTupleType(const BfTypeVector& fieldTypes, const Array<String>& fieldNames);
BfTupleType* SantizeTupleType(BfTupleType* tupleType);
BfRefType* CreateRefType(BfType* resolvedTypeRef, BfRefType::RefKind refKind = BfRefType::RefKind_Ref);
BfRetTypeType* CreateRetTypeType(BfType* resolvedTypeRef);
BfModifiedTypeType* CreateModifiedTypeType(BfType* resolvedTypeRef, BfToken modifiedKind);
BfConcreteInterfaceType* CreateConcreteInterfaceType(BfTypeInstance* interfaceType);
BfTypeInstance* GetWrappedStructType(BfType* type, bool allowSpecialized = true);
BfTypeInstance* GetPrimitiveStructType(BfTypeCode typeCode);

View file

@ -1023,9 +1023,9 @@ bool BfModule::PopulateType(BfType* resolvedTypeRef, BfPopulateType populateType
return true;
}
if (resolvedTypeRef->IsRetTypeType())
if (resolvedTypeRef->IsModifiedTypeType())
{
BfRetTypeType* retTypeType = (BfRetTypeType*)resolvedTypeRef;
BfModifiedTypeType* retTypeType = (BfModifiedTypeType*)resolvedTypeRef;
BF_ASSERT(retTypeType->mElementType->IsGenericParam());
resolvedTypeRef->mSize = mContext->mBfObjectType->mSize;
resolvedTypeRef->mAlign = mContext->mBfObjectType->mAlign;
@ -4967,15 +4967,16 @@ BfRefType* BfModule::CreateRefType(BfType* resolvedTypeRef, BfRefType::RefKind r
return (BfRefType*)resolvedRefType;
}
BfRetTypeType* BfModule::CreateRetTypeType(BfType* resolvedTypeRef)
BfModifiedTypeType* BfModule::CreateModifiedTypeType(BfType* resolvedTypeRef, BfToken modifiedKind)
{
auto retTypeType = mContext->mRetTypeTypePool.Get();
retTypeType->mContext = mContext;
retTypeType->mModifiedKind = modifiedKind;
retTypeType->mElementType = resolvedTypeRef;
auto resolvedRetTypeType = ResolveType(retTypeType);
if (resolvedRetTypeType != retTypeType)
mContext->mRetTypeTypePool.GiveBack(retTypeType);
return (BfRetTypeType*)resolvedRetTypeType;
return (BfModifiedTypeType*)resolvedRetTypeType;
}
BfConcreteInterfaceType* BfModule::CreateConcreteInterfaceType(BfTypeInstance* interfaceType)
@ -7147,7 +7148,9 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
return ResolveTypeResult(typeRef, resolvedTypeRef->mType, populateType, resolveFlags);
}
if (auto retTypeTypeRef = BfNodeDynCastExact<BfRetTypeTypeRef>(typeRef))
if (auto retTypeTypeRef = BfNodeDynCastExact<BfModifiedTypeRef>(typeRef))
{
if (retTypeTypeRef->mRetTypeToken->mToken == BfToken_RetType)
{
bool allowThrough = false;
BfType* resolvedType = NULL;
@ -7208,6 +7211,36 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
return ResolveTypeResult(typeRef, resolvedType, populateType, resolveFlags);
}
}
else if (retTypeTypeRef->mRetTypeToken->mToken == BfToken_Nullable)
{
bool allowThrough = false;
BfType* resolvedType = NULL;
if (retTypeTypeRef->mElementType != NULL)
{
resolvedType = ResolveTypeRef(retTypeTypeRef->mElementType, BfPopulateType_Declaration, BfResolveTypeRefFlag_AllowGenericParamConstValue);
}
if ((resolvedType != NULL) && (resolvedType->IsGenericParam()))
{
//resolvedType = CreateModifiedTypeType(resolvedType, BfToken_Nullable);
BfTypeVector typeVec;
typeVec.push_back(resolvedType);
resolvedType = ResolveTypeDef(mCompiler->mNullableTypeDef, typeVec, BfPopulateType_Declaration);
}
else if ((resolvedType != NULL) && (resolvedType->IsValueType()))
{
BfTypeVector typeVec;
typeVec.push_back(resolvedType);
resolvedType = ResolveTypeDef(mCompiler->mNullableTypeDef, typeVec, BfPopulateType_Declaration);
}
if (resolvedType != NULL)
PopulateType(resolvedType, populateType);
return resolvedType;
}
else
BF_FATAL("Unhandled");
}
if (auto refTypeRef = BfNodeDynCastExact<BfRefTypeRef>(typeRef))
{
@ -7799,9 +7832,10 @@ BfType* BfModule::ResolveTypeRef(BfTypeReference* typeRef, BfPopulateType popula
BF_ASSERT(BfResolvedTypeSet::Hash(genericParamType, &lookupCtx) == resolvedEntry->mHash);
return ResolveTypeResult(typeRef, genericParamType, populateType, resolveFlags);
}
else if (auto retTypeTypeRef = BfNodeDynCast<BfRetTypeTypeRef>(typeRef))
else if (auto retTypeTypeRef = BfNodeDynCast<BfModifiedTypeRef>(typeRef))
{
auto retTypeType = new BfRetTypeType();
auto retTypeType = new BfModifiedTypeType();
retTypeType->mModifiedKind = retTypeTypeRef->mRetTypeToken->mToken;
retTypeType->mElementType = ResolveTypeRef(retTypeTypeRef->mElementType, BfPopulateType_Declaration, BfResolveTypeRefFlag_AllowGenericParamConstValue);
// We know this is a generic param type, it can't fail to resolve
BF_ASSERT(retTypeType->mElementType);
@ -8467,7 +8501,7 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp
((toType->IsInterface()) || (toType == mContext->mBfObjectType)))
{
// Make sure there's no conversion operator before we box
if ((!typedVal.mType->IsRef()) && (!typedVal.mType->IsRetTypeType()))
if ((!typedVal.mType->IsRef()) && (!typedVal.mType->IsModifiedTypeType()))
mayBeBox = true;
}
@ -10060,7 +10094,7 @@ void BfModule::DoTypeToString(StringImpl& str, BfType* resolvedType, BfTypeNameF
str += "]";
return;
}
else if ((resolvedType->IsNullable()) && (!resolvedType->IsUnspecializedType()))
else if (resolvedType->IsNullable())
{
auto genericType = (BfGenericTypeInstance*)resolvedType;
auto elementType = genericType->mTypeGenericArguments[0];
@ -10508,10 +10542,11 @@ void BfModule::DoTypeToString(StringImpl& str, BfType* resolvedType, BfTypeNameF
return;
}
}
else if (resolvedType->IsRetTypeType())
else if (resolvedType->IsModifiedTypeType())
{
auto retTypeType = (BfRetTypeType*)resolvedType;
str += "rettype(";
auto retTypeType = (BfModifiedTypeType*)resolvedType;
str += BfTokenToString(retTypeType->mModifiedKind);
str += "(";
DoTypeToString(str, retTypeType->mElementType, typeNameFlags, genericMethodNameOverrides);
str += ")";
return;

View file

@ -2784,6 +2784,8 @@ void BfParser::NextToken(int endIdx)
case TOKEN_HASH('n', 'u', 'l', 'l'):
if (SrcPtrHasToken("null"))
mToken = BfToken_Null;
else if (SrcPtrHasToken("nullable"))
mToken = BfToken_Nullable;
break;
case TOKEN_HASH('o', 'p', 'e', 'r'):
if (SrcPtrHasToken("operator"))

View file

@ -267,7 +267,7 @@ bool BfReducer::IsTypeReference(BfAstNode* checkNode, BfToken successToken, int*
{
// Tuple start
}
else if ((checkToken == BfToken_Decltype) || (checkToken == BfToken_RetType))
else if ((checkToken == BfToken_Decltype) || (checkToken == BfToken_RetType) || (checkToken == BfToken_Nullable))
{
// Decltype start
}
@ -760,7 +760,7 @@ bool BfReducer::IsTypeReference(BfAstNode* checkNode, BfToken successToken, int*
checkIdx = funcEndNode;
continue;
}
else if ((checkToken == BfToken_Decltype) || (checkToken == BfToken_RetType))
else if ((checkToken == BfToken_Decltype) || (checkToken == BfToken_RetType) || (checkToken == BfToken_Nullable))
{
int endNodeIdx = checkIdx + 1;
@ -4168,6 +4168,7 @@ bool BfReducer::IsTerminatingExpression(BfAstNode* node)
case BfToken_Scope:
case BfToken_New:
case BfToken_RetType:
case BfToken_Nullable:
case BfToken_SizeOf:
case BfToken_This:
case BfToken_TypeOf:
@ -4572,9 +4573,9 @@ BfTypeReference* BfReducer::DoCreateTypeRef(BfAstNode* firstNode, CreateTypeRefF
return elementType;
}
}
else if (token == BfToken_RetType)
else if ((token == BfToken_RetType) || (token == BfToken_Nullable))
{
auto retTypeTypeRef = mAlloc->Alloc<BfRetTypeTypeRef>();
auto retTypeTypeRef = mAlloc->Alloc<BfModifiedTypeRef>();
ReplaceNode(firstNode, retTypeTypeRef);
MEMBER_SET(retTypeTypeRef, mRetTypeToken, tokenNode);
@ -6269,6 +6270,7 @@ BfAstNode* BfReducer::ReadTypeMember(BfAstNode* node, int depth)
else if ((token == BfToken_Var) ||
(token == BfToken_Let) ||
(token == BfToken_RetType) ||
(token == BfToken_Nullable) ||
(token == BfToken_Decltype) ||
(token == BfToken_LParen))
{

View file

@ -2199,9 +2199,9 @@ int BfResolvedTypeSet::Hash(BfType* type, LookupContext* ctx, bool allowRef)
int elemHash = Hash(refType->mElementType, ctx) ^ (HASH_VAL_REF + (int)refType->mRefKind);
return (elemHash << 5) - elemHash;
}
else if (type->IsRetTypeType())
else if (type->IsModifiedTypeType())
{
auto retTypeType = (BfRetTypeType*)type;
auto retTypeType = (BfModifiedTypeType*)type;
int elemHash = Hash(retTypeType->mElementType, ctx) ^ HASH_RETTYPE;
return (elemHash << 5) - elemHash;
}
@ -2621,7 +2621,7 @@ int BfResolvedTypeSet::Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHash
auto primType = ctx->mModule->GetPrimitiveType(BfTypeCode_Let);
return Hash(primType, ctx);
}
else if (auto retTypeTypeRef = BfNodeDynCastExact<BfRetTypeTypeRef>(typeRef))
else if (auto retTypeTypeRef = BfNodeDynCastExact<BfModifiedTypeRef>(typeRef))
{
// Don't cause infinite loop, but if we have an inner 'rettype' then try to directly resolve that --
// Only use the HAS_RETTYPE for root-level rettype insertions
@ -2882,13 +2882,14 @@ bool BfResolvedTypeSet::Equals(BfType* lhs, BfType* rhs, LookupContext* ctx)
BfRefType* rhsRefType = (BfRefType*)rhs;
return (lhsRefType->mElementType == rhsRefType->mElementType) && (lhsRefType->mRefKind == rhsRefType->mRefKind);
}
else if (lhs->IsRetTypeType())
else if (lhs->IsModifiedTypeType())
{
if (!rhs->IsRetTypeType())
if (!rhs->IsModifiedTypeType())
return false;
BfRetTypeType* lhsRetTypeType = (BfRetTypeType*)lhs;
BfRetTypeType* rhsRetTypeType = (BfRetTypeType*)rhs;
return (lhsRetTypeType->mElementType == rhsRetTypeType->mElementType);
BfModifiedTypeType* lhsRetTypeType = (BfModifiedTypeType*)lhs;
BfModifiedTypeType* rhsRetTypeType = (BfModifiedTypeType*)rhs;
return (lhsRetTypeType->mModifiedKind == rhsRetTypeType->mModifiedKind) &&
(lhsRetTypeType->mElementType == rhsRetTypeType->mElementType);
}
else if (lhs->IsConcreteInterfaceType())
{
@ -3093,7 +3094,7 @@ bool BfResolvedTypeSet::Equals(BfType* lhs, BfTypeReference* rhs, LookupContext*
if (ctx->mRootTypeRef != rhs)
{
if (auto retTypeRef = BfNodeDynCastExact<BfRetTypeTypeRef>(rhs))
if (auto retTypeRef = BfNodeDynCastExact<BfModifiedTypeRef>(rhs))
{
auto resolvedType = ctx->mModule->ResolveTypeRef(rhs);
return lhs == resolvedType;
@ -3341,12 +3342,14 @@ bool BfResolvedTypeSet::Equals(BfType* lhs, BfTypeReference* rhs, LookupContext*
return (lhsRefType->mRefKind == refKind) &&
Equals(lhsRefType->mElementType, rhsRefTypeRef->mElementType, ctx);
}
else if (lhs->IsRetTypeType())
else if (lhs->IsModifiedTypeType())
{
auto lhsRetTypeType = (BfRetTypeType*)lhs;
auto rhsRetTypeTypeRef = BfNodeDynCastExact<BfRetTypeTypeRef>(rhs);
auto lhsRetTypeType = (BfModifiedTypeType*)lhs;
auto rhsRetTypeTypeRef = BfNodeDynCastExact<BfModifiedTypeRef>(rhs);
if (rhsRetTypeTypeRef == NULL)
return false;
if (lhsRetTypeType->mModifiedKind != rhsRetTypeTypeRef->mRetTypeToken->mToken)
return false;
return Equals(lhsRetTypeType->mElementType, rhsRetTypeTypeRef->mElementType, ctx);
}
else if (lhs->IsConcreteInterfaceType())

View file

@ -489,7 +489,7 @@ public:
virtual bool IsTuple() { return false; }
virtual bool IsOnDemand() { return false; }
virtual bool IsTemporary() { return false; }
virtual bool IsRetTypeType() { return false; }
virtual bool IsModifiedTypeType() { return false; }
virtual bool IsConcreteInterfaceType() { return false; }
virtual bool IsTypeAlias() { return false; }
virtual bool HasPackingHoles() { return false; }
@ -921,13 +921,14 @@ public:
virtual bool IsReified() override { return false; }
};
// This just captures rettype(T) since it can't be resolved directly
class BfRetTypeType : public BfType
// This just captures rettype(T)/nullable(T) since it can't be resolved directly
class BfModifiedTypeType : public BfType
{
public:
BfToken mModifiedKind;
BfType* mElementType;
virtual bool IsRetTypeType() override { return true; }
virtual bool IsModifiedTypeType() override { return true; }
virtual bool CanBeValuelessType() override { return true; }
virtual bool IsValuelessType() override { return true; }