mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-08 11:38:21 +02:00
Inference of tuple 'params T`
This commit is contained in:
parent
f6d18c111f
commit
66d3581911
14 changed files with 721 additions and 75 deletions
|
@ -334,6 +334,7 @@ namespace System
|
||||||
static extern void Comptime_EmitMethodEntry(int64 methodHandle, StringView text);
|
static extern void Comptime_EmitMethodEntry(int64 methodHandle, StringView text);
|
||||||
static extern void Comptime_EmitMethodExit(int64 methodHandle, StringView text);
|
static extern void Comptime_EmitMethodExit(int64 methodHandle, StringView text);
|
||||||
static extern void Comptime_EmitMixin(StringView text);
|
static extern void Comptime_EmitMixin(StringView text);
|
||||||
|
static extern String Comptime_GetStringById(int32 id);
|
||||||
|
|
||||||
[Comptime(OnlyFromComptime=true)]
|
[Comptime(OnlyFromComptime=true)]
|
||||||
public static MethodBuilder CreateMethod(Type owner, StringView methodName, Type returnType, MethodFlags methodFlags)
|
public static MethodBuilder CreateMethod(Type owner, StringView methodName, Type returnType, MethodFlags methodFlags)
|
||||||
|
|
|
@ -1392,6 +1392,10 @@ namespace System
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
|
int charsLeft = len - pos;
|
||||||
|
Reserve(mLength + charsLeft);
|
||||||
|
char8* ptr = Ptr;
|
||||||
|
|
||||||
int p = pos;
|
int p = pos;
|
||||||
int i = pos;
|
int i = pos;
|
||||||
while (pos < len)
|
while (pos < len)
|
||||||
|
@ -1418,7 +1422,8 @@ namespace System
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Append(ch);
|
//Append(ch);
|
||||||
|
ptr[mLength++] = ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pos == len) break;
|
if (pos == len) break;
|
||||||
|
@ -1519,6 +1524,16 @@ namespace System
|
||||||
}
|
}
|
||||||
if (ch != '}') return FormatError();
|
if (ch != '}') return FormatError();
|
||||||
pos++;
|
pos++;
|
||||||
|
|
||||||
|
if ((provider == null) && (fmt.IsEmpty) && (width == 0))
|
||||||
|
{
|
||||||
|
if (arg == null)
|
||||||
|
s.Append("null");
|
||||||
|
else
|
||||||
|
arg.ToString(this);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if (s == null)
|
if (s == null)
|
||||||
s = scope:: String(128);
|
s = scope:: String(128);
|
||||||
|
|
||||||
|
@ -1539,6 +1554,7 @@ namespace System
|
||||||
Append(s);
|
Append(s);
|
||||||
if (leftJustify && pad > 0) Append(' ', pad);
|
if (leftJustify && pad > 0) Append(' ', pad);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return .Ok;
|
return .Ok;
|
||||||
}
|
}
|
||||||
|
@ -2999,6 +3015,16 @@ namespace System
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String GetById(int id)
|
||||||
|
{
|
||||||
|
if (Compiler.IsComptime)
|
||||||
|
{
|
||||||
|
return Compiler.[Friend]Comptime_GetStringById((.)id);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return sIdStringLiterals[id];
|
||||||
|
}
|
||||||
|
|
||||||
public struct RawEnumerator : IRefEnumerator<char8*>, IEnumerator<char8>
|
public struct RawEnumerator : IRefEnumerator<char8*>, IEnumerator<char8>
|
||||||
{
|
{
|
||||||
char8* mPtr;
|
char8* mPtr;
|
||||||
|
|
|
@ -650,6 +650,17 @@ namespace System
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual TypeInstance WrappedType
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (Compiler.IsComptime)
|
||||||
|
return Comptime_GetWrappedType((.)mTypeId) as TypeInstance;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public virtual TypeInstance.InterfaceEnumerator Interfaces
|
public virtual TypeInstance.InterfaceEnumerator Interfaces
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
@ -754,6 +765,7 @@ namespace System
|
||||||
static extern int32 Comptime_Type_GetBaseType(int32 typeId);
|
static extern int32 Comptime_Type_GetBaseType(int32 typeId);
|
||||||
static extern bool Comptime_Type_HasDeclaredMember(int32 typeId, int32 kind, StringView name);
|
static extern bool Comptime_Type_HasDeclaredMember(int32 typeId, int32 kind, StringView name);
|
||||||
static extern Type Comptime_GetTypeById(int32 typeId);
|
static extern Type Comptime_GetTypeById(int32 typeId);
|
||||||
|
static extern Type Comptime_GetWrappedType(int32 typeId);
|
||||||
static extern Type Comptime_GetTypeByName(StringView name);
|
static extern Type Comptime_GetTypeByName(StringView name);
|
||||||
static extern String Comptime_Type_ToString(int32 typeId);
|
static extern String Comptime_Type_ToString(int32 typeId);
|
||||||
static extern String Comptime_TypeName_ToString(int32 typeId);
|
static extern String Comptime_TypeName_ToString(int32 typeId);
|
||||||
|
@ -864,6 +876,15 @@ namespace System
|
||||||
return type == this || (type.IsTypedPrimitive && type.UnderlyingType == this);
|
return type == this || (type.IsTypedPrimitive && type.UnderlyingType == this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual bool ImplementsInterface(Type checkInterface)
|
||||||
|
{
|
||||||
|
var wrappedType = WrappedType;
|
||||||
|
if (wrappedType != null)
|
||||||
|
return wrappedType.ImplementsInterface(checkInterface);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public virtual Result<FieldInfo> GetField(String fieldName)
|
public virtual Result<FieldInfo> GetField(String fieldName)
|
||||||
{
|
{
|
||||||
return .Err;
|
return .Err;
|
||||||
|
@ -1247,6 +1268,19 @@ namespace System.Reflection
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool ImplementsInterface(Type checkInterface)
|
||||||
|
{
|
||||||
|
for (int ifaceIdx < mInterfaceCount)
|
||||||
|
{
|
||||||
|
if (mInterfaceDataPtr[ifaceIdx].mInterfaceType == checkInterface.TypeId)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
var baseType = BaseType;
|
||||||
|
if (baseType != null)
|
||||||
|
return baseType.ImplementsInterface(checkInterface);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public override void GetFullName(String strBuffer)
|
public override void GetFullName(String strBuffer)
|
||||||
{
|
{
|
||||||
if (mTypeFlags.HasFlag(TypeFlags.Tuple))
|
if (mTypeFlags.HasFlag(TypeFlags.Tuple))
|
||||||
|
@ -1528,7 +1562,8 @@ namespace System.Reflection
|
||||||
public override void GetFullName(String strBuffer)
|
public override void GetFullName(String strBuffer)
|
||||||
{
|
{
|
||||||
strBuffer.Append("const ");
|
strBuffer.Append("const ");
|
||||||
switch (GetType(mValueType))
|
var type = GetType(mValueType);
|
||||||
|
switch (type)
|
||||||
{
|
{
|
||||||
case typeof(float):
|
case typeof(float):
|
||||||
(*(float*)&mValue).ToString(strBuffer);
|
(*(float*)&mValue).ToString(strBuffer);
|
||||||
|
@ -1543,6 +1578,10 @@ namespace System.Reflection
|
||||||
strBuffer.Append('\'');
|
strBuffer.Append('\'');
|
||||||
case typeof(uint64), typeof(uint):
|
case typeof(uint64), typeof(uint):
|
||||||
(*(uint64*)&mValue).ToString(strBuffer);
|
(*(uint64*)&mValue).ToString(strBuffer);
|
||||||
|
case typeof(String):
|
||||||
|
int32 stringId = *(int32*)&mValue;
|
||||||
|
String str = String.GetById(stringId);
|
||||||
|
str.Quote(strBuffer);
|
||||||
default:
|
default:
|
||||||
mValue.ToString(strBuffer);
|
mValue.ToString(strBuffer);
|
||||||
}
|
}
|
||||||
|
|
|
@ -846,7 +846,7 @@ public:
|
||||||
return (mKind == BfTypedValueKind_NoValue) && (mType != NULL);
|
return (mKind == BfTypedValueKind_NoValue) && (mType != NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsParams()
|
bool IsParams() const
|
||||||
{
|
{
|
||||||
return (mKind == BfTypedValueKind_ParamsSplat) || (mKind == BfTypedValueKind_Params);
|
return (mKind == BfTypedValueKind_ParamsSplat) || (mKind == BfTypedValueKind_Params);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2032,6 +2032,39 @@ bool BfMethodMatcher::CheckMethod(BfTypeInstance* targetTypeInstance, BfTypeInst
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (paramsType->IsParamsType())
|
||||||
|
{
|
||||||
|
paramsType = paramsType->GetUnderlyingType();
|
||||||
|
if (paramsType->IsGenericParam())
|
||||||
|
{
|
||||||
|
auto genericParamType = (BfGenericParamType*)paramsType;
|
||||||
|
if (genericParamType->mGenericParamKind == BfGenericParamKind_Method)
|
||||||
|
{
|
||||||
|
auto genericParamInst = methodInstance->mMethodInfoEx->mGenericParams[genericParamType->mGenericParamIdx];
|
||||||
|
if ((genericParamInst->mTypeConstraint != NULL) && (genericParamInst->mTypeConstraint->IsInstanceOf(mModule->mCompiler->mTupleTypeDef)))
|
||||||
|
{
|
||||||
|
bool isValid = true;
|
||||||
|
BfTypeVector genericArgs;
|
||||||
|
|
||||||
|
for (int argIdx = methodInstance->mParams.mSize - 1 - inferParamOffset; argIdx < (int)mArguments.size(); argIdx++)
|
||||||
|
{
|
||||||
|
BfTypedValue argTypedValue = ResolveArgTypedValue(mArguments[argIdx], NULL, genericArgumentsSubstitute);
|
||||||
|
if (!argTypedValue)
|
||||||
|
{
|
||||||
|
isValid = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
genericArgs.Add(mModule->FixIntUnknown(argTypedValue.mType));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isValid)
|
||||||
|
{
|
||||||
|
(*genericArgumentsSubstitute)[genericParamType->mGenericParamIdx] = mModule->CreateTupleType(genericArgs, SubstituteList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!deferredArgs.IsEmpty())
|
if (!deferredArgs.IsEmpty())
|
||||||
|
@ -4388,6 +4421,10 @@ BfTypedValue BfExprEvaluator::LoadLocal(BfLocalVariable* varDecl, bool allowRef)
|
||||||
else
|
else
|
||||||
localResult = BfTypedValue(varDecl->mAddr, varDecl->mResolvedType, varDecl->mIsReadOnly ? BfTypedValueKind_ReadOnlyAddr : BfTypedValueKind_Addr);
|
localResult = BfTypedValue(varDecl->mAddr, varDecl->mResolvedType, varDecl->mIsReadOnly ? BfTypedValueKind_ReadOnlyAddr : BfTypedValueKind_Addr);
|
||||||
}
|
}
|
||||||
|
else if ((varDecl->mResolvedType->IsModifiedTypeType()) && (((BfModifiedTypeType*)varDecl->mResolvedType)->mModifiedKind == BfToken_Params))
|
||||||
|
{
|
||||||
|
localResult = BfTypedValue(BfIRValue(), varDecl->mResolvedType);
|
||||||
|
}
|
||||||
else if (varDecl->mResolvedType->IsValuelessNonOpaqueType())
|
else if (varDecl->mResolvedType->IsValuelessNonOpaqueType())
|
||||||
{
|
{
|
||||||
if ((varDecl->mResolvedType->IsRef()) && (!allowRef))
|
if ((varDecl->mResolvedType->IsRef()) && (!allowRef))
|
||||||
|
@ -4400,9 +4437,99 @@ BfTypedValue BfExprEvaluator::LoadLocal(BfLocalVariable* varDecl, bool allowRef)
|
||||||
localResult = BfTypedValue(mModule->mBfIRBuilder->GetFakeVal(), varDecl->mResolvedType, true);
|
localResult = BfTypedValue(mModule->mBfIRBuilder->GetFakeVal(), varDecl->mResolvedType, true);
|
||||||
}
|
}
|
||||||
else if (varDecl->mCompositeCount >= 0)
|
else if (varDecl->mCompositeCount >= 0)
|
||||||
|
{
|
||||||
|
if ((mBfEvalExprFlags & BfEvalExprFlags_InParamsExpr) != 0)
|
||||||
{
|
{
|
||||||
localResult = BfTypedValue(BfIRValue(), mModule->GetPrimitiveType(BfTypeCode_None));
|
localResult = BfTypedValue(BfIRValue(), mModule->GetPrimitiveType(BfTypeCode_None));
|
||||||
}
|
}
|
||||||
|
else if (!varDecl->mAddr)
|
||||||
|
{
|
||||||
|
bool isValid = true;
|
||||||
|
|
||||||
|
Array<BfTypedValue> argVals;
|
||||||
|
|
||||||
|
auto methodState = mModule->mCurMethodState->GetMethodStateForLocal(varDecl);
|
||||||
|
for (int compositeIdx = 0; compositeIdx < varDecl->mCompositeCount; compositeIdx++)
|
||||||
|
{
|
||||||
|
BfResolvedArg compositeResolvedArg;
|
||||||
|
auto compositeLocalVar = methodState->mLocals[varDecl->mLocalVarIdx + compositeIdx + 1];
|
||||||
|
auto argValue = LoadLocal(compositeLocalVar, true);
|
||||||
|
if (argValue)
|
||||||
|
{
|
||||||
|
if (!argValue.mType->IsStruct())
|
||||||
|
argValue = mModule->LoadValue(argValue, NULL, mIsVolatileReference);
|
||||||
|
argVals.Add(argValue);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
isValid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isValid)
|
||||||
|
{
|
||||||
|
BfTypeInstance* tupleType = NULL;
|
||||||
|
if (varDecl->mResolvedType->IsTuple())
|
||||||
|
tupleType = (BfTupleType*)varDecl->mResolvedType;
|
||||||
|
else if ((varDecl->mResolvedType->IsDelegateOrFunction()))
|
||||||
|
{
|
||||||
|
auto invokeFunction = mModule->GetDelegateInvokeMethod(varDecl->mResolvedType->ToTypeInstance());
|
||||||
|
if (invokeFunction != NULL)
|
||||||
|
{
|
||||||
|
BfTypeVector fieldTypes;
|
||||||
|
SubstituteList fieldNames;
|
||||||
|
for (int paramIdx = 0; paramIdx < invokeFunction->GetParamCount(); paramIdx++)
|
||||||
|
{
|
||||||
|
fieldNames.Add(invokeFunction->GetParamName(paramIdx));
|
||||||
|
fieldTypes.Add(invokeFunction->GetParamType(paramIdx));
|
||||||
|
}
|
||||||
|
tupleType = mModule->CreateTupleType(fieldTypes, fieldNames);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tupleType == NULL)
|
||||||
|
{
|
||||||
|
isValid = false;
|
||||||
|
}
|
||||||
|
else if (tupleType->IsValuelessType())
|
||||||
|
{
|
||||||
|
localResult = mModule->GetDefaultTypedValue(tupleType);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BF_ASSERT(tupleType->mFieldInstances.mSize == argVals.mSize);
|
||||||
|
|
||||||
|
auto instAlloca = mModule->CreateAlloca(tupleType);
|
||||||
|
|
||||||
|
for (int i = 0; i < argVals.mSize; i++)
|
||||||
|
{
|
||||||
|
auto& fieldInstance = tupleType->mFieldInstances[i];
|
||||||
|
if (fieldInstance.mDataIdx >= 0)
|
||||||
|
{
|
||||||
|
auto val = mModule->Cast(varDecl->mNameNode, argVals[i], fieldInstance.mResolvedType);
|
||||||
|
if (val)
|
||||||
|
{
|
||||||
|
val = mModule->LoadOrAggregateValue(val);
|
||||||
|
if (!val.mType->IsValuelessType())
|
||||||
|
{
|
||||||
|
auto elemPtr = mModule->mBfIRBuilder->CreateInBoundsGEP(instAlloca, 0, fieldInstance.mDataIdx);
|
||||||
|
mModule->mBfIRBuilder->CreateStore(val.mValue, elemPtr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
varDecl->mResolvedType = tupleType;
|
||||||
|
varDecl->mAddr = instAlloca;
|
||||||
|
varDecl->mIsReadOnly = true;
|
||||||
|
localResult = BfTypedValue(varDecl->mAddr, varDecl->mResolvedType, BfTypedValueKind_ReadOnlyAddr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isValid)
|
||||||
|
{
|
||||||
|
localResult = mModule->GetDefaultTypedValue(mModule->ResolveTypeDef(mModule->mCompiler->mTupleTypeDef));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
BF_ASSERT((mModule->mCurMethodState->mClosureState != NULL) || (mModule->mBfIRBuilder->mIgnoreWrites));
|
BF_ASSERT((mModule->mCurMethodState->mClosureState != NULL) || (mModule->mBfIRBuilder->mIgnoreWrites));
|
||||||
|
@ -4539,11 +4666,6 @@ BfTypedValue BfExprEvaluator::LookupIdentifier(BfAstNode* refNode, const StringI
|
||||||
if ((closureTypeInst != NULL) && (wantName == "this"))
|
if ((closureTypeInst != NULL) && (wantName == "this"))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if ((varDecl->mCompositeCount >= 0) && ((mBfEvalExprFlags & BfEvalExprFlags_AllowParamsExpr) == 0))
|
|
||||||
{
|
|
||||||
mModule->Fail("Invalid use of 'params' parameter", refNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (varDecl->mResolvedType->IsVoid())
|
if (varDecl->mResolvedType->IsVoid())
|
||||||
{
|
{
|
||||||
if ((varDecl->mIsReadOnly) && (varDecl->mParamIdx == -2) && (varDecl->mParamFailed))
|
if ((varDecl->mIsReadOnly) && (varDecl->mParamIdx == -2) && (varDecl->mParamFailed))
|
||||||
|
@ -4556,6 +4678,12 @@ BfTypedValue BfExprEvaluator::LookupIdentifier(BfAstNode* refNode, const StringI
|
||||||
mModule->SetElementType(identifierNode, (varDecl->IsParam()) ? BfSourceElementType_Parameter : BfSourceElementType_Local);
|
mModule->SetElementType(identifierNode, (varDecl->IsParam()) ? BfSourceElementType_Parameter : BfSourceElementType_Local);
|
||||||
|
|
||||||
BfTypedValue localResult = LoadLocal(varDecl);
|
BfTypedValue localResult = LoadLocal(varDecl);
|
||||||
|
|
||||||
|
if ((localResult) && (localResult.mType->IsParamsType()) && ((mBfEvalExprFlags & BfEvalExprFlags_AllowParamsExpr) == 0))
|
||||||
|
{
|
||||||
|
localResult = mModule->LoadOrAggregateValue(localResult);
|
||||||
|
}
|
||||||
|
|
||||||
auto autoComplete = GetAutoComplete();
|
auto autoComplete = GetAutoComplete();
|
||||||
if (identifierNode != NULL)
|
if (identifierNode != NULL)
|
||||||
{
|
{
|
||||||
|
@ -6355,9 +6483,8 @@ void BfExprEvaluator::ResolveArgValues(BfResolvedArgs& resolvedArgs, BfResolveAr
|
||||||
auto methodState = mModule->mCurMethodState->GetMethodStateForLocal(localVar);
|
auto methodState = mModule->mCurMethodState->GetMethodStateForLocal(localVar);
|
||||||
if (localVar->mCompositeCount >= 0)
|
if (localVar->mCompositeCount >= 0)
|
||||||
{
|
{
|
||||||
if ((resolvedArg.mArgFlags & BfArgFlag_ParamsExpr) == 0)
|
if ((resolvedArg.mArgFlags & BfArgFlag_ParamsExpr) != 0)
|
||||||
mModule->Warn(0, "'params' token expected", argExpr);
|
{
|
||||||
|
|
||||||
for (int compositeIdx = 0; compositeIdx < localVar->mCompositeCount; compositeIdx++)
|
for (int compositeIdx = 0; compositeIdx < localVar->mCompositeCount; compositeIdx++)
|
||||||
{
|
{
|
||||||
BfResolvedArg compositeResolvedArg;
|
BfResolvedArg compositeResolvedArg;
|
||||||
|
@ -6372,10 +6499,20 @@ void BfExprEvaluator::ResolveArgValues(BfResolvedArgs& resolvedArgs, BfResolveAr
|
||||||
resolvedArg.mExpression = argExpr;
|
resolvedArg.mExpression = argExpr;
|
||||||
resolvedArg.mArgFlags = (BfArgFlags)(resolvedArg.mArgFlags | BfArgFlag_FromParamComposite);
|
resolvedArg.mArgFlags = (BfArgFlags)(resolvedArg.mArgFlags | BfArgFlag_FromParamComposite);
|
||||||
resolvedArgs.mResolvedArgs.push_back(resolvedArg);
|
resolvedArgs.mResolvedArgs.push_back(resolvedArg);
|
||||||
|
|
||||||
|
exprEvaluator.mIsVolatileReference = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((localVar->mResolvedType->IsModifiedTypeType()) && (((BfModifiedTypeType*)localVar->mResolvedType)->mModifiedKind == BfToken_Params))
|
||||||
|
{
|
||||||
|
// Is a 'params'
|
||||||
|
}
|
||||||
|
else
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
exprEvaluator.mResult = mModule->LoadOrAggregateValue(exprEvaluator.mResult);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exprEvaluator.CheckResultForReading(exprEvaluator.mResult);
|
exprEvaluator.CheckResultForReading(exprEvaluator.mResult);
|
||||||
|
@ -7903,6 +8040,7 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
|
||||||
BfIRValue expandedParamAlloca;
|
BfIRValue expandedParamAlloca;
|
||||||
BfTypedValue expandedParamsArray;
|
BfTypedValue expandedParamsArray;
|
||||||
BfType* expandedParamsElementType = NULL;
|
BfType* expandedParamsElementType = NULL;
|
||||||
|
bool hadDelegateParamIdx = false;
|
||||||
int extendedParamIdx = 0;
|
int extendedParamIdx = 0;
|
||||||
|
|
||||||
AddCallDependencies(methodInstance);
|
AddCallDependencies(methodInstance);
|
||||||
|
@ -8170,6 +8308,8 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (paramKind == BfParamKind_DelegateParam)
|
||||||
|
hadDelegateParamIdx = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
BfAstNode* arg = NULL;
|
BfAstNode* arg = NULL;
|
||||||
|
@ -8181,7 +8321,7 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu
|
||||||
if (argExprIdx < (int)argValues.size())
|
if (argExprIdx < (int)argValues.size())
|
||||||
{
|
{
|
||||||
arg = argValues[argExprIdx].mExpression;
|
arg = argValues[argExprIdx].mExpression;
|
||||||
if (((argValues[argExprIdx].mArgFlags & BfArgFlag_StringInterpolateArg) != 0) && (!expandedParamsArray))
|
if (((argValues[argExprIdx].mArgFlags & BfArgFlag_StringInterpolateArg) != 0) && (!expandedParamsArray) && (!hadDelegateParamIdx))
|
||||||
{
|
{
|
||||||
BfAstNode* errorRef = arg;
|
BfAstNode* errorRef = arg;
|
||||||
int checkIdx = argExprIdx - 1;
|
int checkIdx = argExprIdx - 1;
|
||||||
|
@ -10418,7 +10558,10 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
|
||||||
if ((mModule->mCurMethodState != NULL) && (exprEvaluator.mResultLocalVar != NULL) && (exprEvaluator.mResultLocalVarRefNode != NULL))
|
if ((mModule->mCurMethodState != NULL) && (exprEvaluator.mResultLocalVar != NULL) && (exprEvaluator.mResultLocalVarRefNode != NULL))
|
||||||
{
|
{
|
||||||
auto localVar = exprEvaluator.mResultLocalVar;
|
auto localVar = exprEvaluator.mResultLocalVar;
|
||||||
if ((localVar->mCompositeCount >= 0) && (localVar->mResolvedType == fieldVal.mType))
|
auto checkType = localVar->mResolvedType;
|
||||||
|
if (checkType->IsParamsType())
|
||||||
|
checkType = checkType->GetUnderlyingType();
|
||||||
|
if ((localVar->mCompositeCount >= 0) && (checkType == fieldVal.mType))
|
||||||
{
|
{
|
||||||
delegateFailed = false;
|
delegateFailed = false;
|
||||||
if (mModule->mCurMethodInstance->mIsUnspecialized)
|
if (mModule->mCurMethodInstance->mIsUnspecialized)
|
||||||
|
@ -19984,12 +20127,12 @@ void BfExprEvaluator::CheckResultForReading(BfTypedValue& typedValue)
|
||||||
int fieldIdx = mResultLocalVarField - 1;
|
int fieldIdx = mResultLocalVarField - 1;
|
||||||
|
|
||||||
auto localVar = mResultLocalVar;
|
auto localVar = mResultLocalVar;
|
||||||
if (localVar->mCompositeCount > 0)
|
/*if (localVar->mCompositeCount > 0)
|
||||||
{
|
{
|
||||||
mModule->Fail(StrFormat("Cannot read from composite '%s', it can only be used in an argument list", localVar->mName.c_str()), mResultLocalVarRefNode);
|
mModule->Fail(StrFormat("Cannot read from composite '%s', it can only be used in an argument list", localVar->mName.c_str()), mResultLocalVarRefNode);
|
||||||
typedValue = BfTypedValue();
|
typedValue = BfTypedValue();
|
||||||
return;
|
return;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
if (localVar->mAssignedKind == BfLocalVarAssignKind_None)
|
if (localVar->mAssignedKind == BfLocalVarAssignKind_None)
|
||||||
{
|
{
|
||||||
|
@ -22849,9 +22992,7 @@ void BfExprEvaluator::PerformUnaryOperation(BfExpression* unaryOpExpr, BfUnaryOp
|
||||||
|
|
||||||
///
|
///
|
||||||
{
|
{
|
||||||
// If this is a cast, we don't want the value to be coerced before the unary operator is applied.
|
SetAndRestoreValue<BfEvalExprFlags> prevFlags(mBfEvalExprFlags);
|
||||||
// WAIT: Why not?
|
|
||||||
//SetAndRestoreValue<BfType*> prevExpectingType(mExpectingType, NULL);
|
|
||||||
|
|
||||||
BfType* prevExpedcting = mExpectingType;
|
BfType* prevExpedcting = mExpectingType;
|
||||||
switch (unaryOp)
|
switch (unaryOp)
|
||||||
|
@ -22876,6 +23017,9 @@ void BfExprEvaluator::PerformUnaryOperation(BfExpression* unaryOpExpr, BfUnaryOp
|
||||||
mExpectingType = NULL;
|
mExpectingType = NULL;
|
||||||
// Otherwise keep expecting type
|
// Otherwise keep expecting type
|
||||||
break;
|
break;
|
||||||
|
case BfUnaryOp_Params:
|
||||||
|
mBfEvalExprFlags = (BfEvalExprFlags)(mBfEvalExprFlags | BfEvalExprFlags_InParamsExpr);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
mExpectingType = NULL;
|
mExpectingType = NULL;
|
||||||
}
|
}
|
||||||
|
@ -23570,6 +23714,8 @@ void BfExprEvaluator::PerformUnaryOperation_OnResult(BfExpression* unaryOpExpr,
|
||||||
if (allowParams)
|
if (allowParams)
|
||||||
{
|
{
|
||||||
mResult = mModule->LoadValue(mResult);
|
mResult = mModule->LoadValue(mResult);
|
||||||
|
if ((mResult.mType != NULL) && (mResult.mType->IsParamsType()))
|
||||||
|
mResult.mType = mResult.mType->GetUnderlyingType();
|
||||||
if (mResult.IsSplat())
|
if (mResult.IsSplat())
|
||||||
mResult.mKind = BfTypedValueKind_ParamsSplat;
|
mResult.mKind = BfTypedValueKind_ParamsSplat;
|
||||||
else
|
else
|
||||||
|
|
|
@ -578,6 +578,8 @@ void BfGNUMangler::Mangle(MangleContext& mangleContext, StringImpl& name, BfType
|
||||||
name += "U5alloc";
|
name += "U5alloc";
|
||||||
else if (retTypeType->mModifiedKind == BfToken_Nullable)
|
else if (retTypeType->mModifiedKind == BfToken_Nullable)
|
||||||
name += "U8nullable";
|
name += "U8nullable";
|
||||||
|
else if (retTypeType->mModifiedKind == BfToken_Params)
|
||||||
|
name += "U6params";
|
||||||
else
|
else
|
||||||
BF_FATAL("Unhandled");
|
BF_FATAL("Unhandled");
|
||||||
Mangle(mangleContext, name, retTypeType->mElementType);
|
Mangle(mangleContext, name, retTypeType->mElementType);
|
||||||
|
@ -1729,6 +1731,8 @@ void BfMSMangler::Mangle(MangleContext& mangleContext, StringImpl& name, BfType*
|
||||||
name += "alloc$";
|
name += "alloc$";
|
||||||
else if (retType->mModifiedKind == BfToken_Nullable)
|
else if (retType->mModifiedKind == BfToken_Nullable)
|
||||||
name += "nullable$";
|
name += "nullable$";
|
||||||
|
else if (retType->mModifiedKind == BfToken_Params)
|
||||||
|
name += "params$";
|
||||||
else
|
else
|
||||||
BF_FATAL("Unhandled");
|
BF_FATAL("Unhandled");
|
||||||
Mangle(mangleContext, name, retType->mElementType);
|
Mangle(mangleContext, name, retType->mElementType);
|
||||||
|
|
|
@ -13520,6 +13520,16 @@ BfTypedValue BfModule::LoadOrAggregateValue(BfTypedValue typedValue)
|
||||||
return AggregateSplat(typedValue);
|
return AggregateSplat(typedValue);
|
||||||
if (typedValue.IsAddr())
|
if (typedValue.IsAddr())
|
||||||
return LoadValue(typedValue);
|
return LoadValue(typedValue);
|
||||||
|
|
||||||
|
if ((typedValue.mType != NULL) && (typedValue.mType->IsParamsType()) && (!typedValue.IsParams()))
|
||||||
|
{
|
||||||
|
return GetDefaultTypedValue(ResolveTypeDef(mCompiler->mTupleTypeDef));
|
||||||
|
}
|
||||||
|
else if ((typedValue.IsParams()) && (typedValue.mType->IsGenericParam()))
|
||||||
|
{
|
||||||
|
return BfTypedValue(mBfIRBuilder->GetFakeVal(), typedValue.mType);
|
||||||
|
}
|
||||||
|
|
||||||
return typedValue;
|
return typedValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17144,6 +17154,8 @@ void BfModule::CreateDelegateInvokeMethod()
|
||||||
|
|
||||||
for (int i = 1; i < (int)mCurMethodState->mLocals.size(); i++)
|
for (int i = 1; i < (int)mCurMethodState->mLocals.size(); i++)
|
||||||
{
|
{
|
||||||
|
if (mCurMethodState->mLocals[i]->mCompositeCount >= 0)
|
||||||
|
continue;
|
||||||
BfTypedValue localVal = exprEvaluator.LoadLocal(mCurMethodState->mLocals[i], true);
|
BfTypedValue localVal = exprEvaluator.LoadLocal(mCurMethodState->mLocals[i], true);
|
||||||
exprEvaluator.PushArg(localVal, staticFuncArgs);
|
exprEvaluator.PushArg(localVal, staticFuncArgs);
|
||||||
exprEvaluator.PushArg(localVal, memberFuncArgs);
|
exprEvaluator.PushArg(localVal, memberFuncArgs);
|
||||||
|
@ -20029,6 +20041,16 @@ void BfModule::ProcessMethod_SetupParams(BfMethodInstance* methodInstance, BfTyp
|
||||||
paramVar->mIsImplicitParam = true;
|
paramVar->mIsImplicitParam = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (methodInstance->GetParamKind(paramIdx) == BfParamKind_Params)
|
||||||
|
{
|
||||||
|
if ((paramVar->mResolvedType->IsModifiedTypeType()) && (((BfModifiedTypeType*)paramVar->mResolvedType)->mModifiedKind == BfToken_Params))
|
||||||
|
{
|
||||||
|
paramVar->mValue = BfIRValue();
|
||||||
|
paramVar->mCompositeCount = 0;
|
||||||
|
paramVar->mIsSplat = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!mCurTypeInstance->IsDelegateOrFunction())
|
if (!mCurTypeInstance->IsDelegateOrFunction())
|
||||||
CheckVariableDef(paramVar);
|
CheckVariableDef(paramVar);
|
||||||
paramVar->Init();
|
paramVar->Init();
|
||||||
|
@ -20073,6 +20095,18 @@ void BfModule::ProcessMethod_SetupParams(BfMethodInstance* methodInstance, BfTyp
|
||||||
if ((genericParamInstance->mTypeConstraint->IsDelegate()) || (genericParamInstance->mTypeConstraint->IsFunction()) || (genericParamInstance->mTypeConstraint->IsTuple()) ||
|
if ((genericParamInstance->mTypeConstraint->IsDelegate()) || (genericParamInstance->mTypeConstraint->IsFunction()) || (genericParamInstance->mTypeConstraint->IsTuple()) ||
|
||||||
((typeInstConstraint != NULL) &&
|
((typeInstConstraint != NULL) &&
|
||||||
((typeInstConstraint->IsInstanceOf(mCompiler->mDelegateTypeDef)) || (typeInstConstraint->IsInstanceOf(mCompiler->mFunctionTypeDef)) || (typeInstConstraint->IsInstanceOf(mCompiler->mTupleTypeDef)))))
|
((typeInstConstraint->IsInstanceOf(mCompiler->mDelegateTypeDef)) || (typeInstConstraint->IsInstanceOf(mCompiler->mFunctionTypeDef)) || (typeInstConstraint->IsInstanceOf(mCompiler->mTupleTypeDef)))))
|
||||||
|
{
|
||||||
|
bool doAdd = true;
|
||||||
|
|
||||||
|
// TODO: Remove
|
||||||
|
if (!mCurMethodState->mLocals.IsEmpty())
|
||||||
|
{
|
||||||
|
auto checkVar = mCurMethodState->mLocals.back();
|
||||||
|
if (checkVar->mName == paramDef->mName)
|
||||||
|
doAdd = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (doAdd)
|
||||||
{
|
{
|
||||||
BfLocalVariable* localVar = new BfLocalVariable();
|
BfLocalVariable* localVar = new BfLocalVariable();
|
||||||
localVar->mName = paramDef->mName;
|
localVar->mName = paramDef->mName;
|
||||||
|
@ -20082,6 +20116,7 @@ void BfModule::ProcessMethod_SetupParams(BfMethodInstance* methodInstance, BfTyp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else if (paramsType->IsDelegate())
|
else if (paramsType->IsDelegate())
|
||||||
{
|
{
|
||||||
BfMethodInstance* invokeMethodInstance = GetRawMethodInstanceAtIdx(paramsType->ToTypeInstance(), 0, "Invoke");
|
BfMethodInstance* invokeMethodInstance = GetRawMethodInstanceAtIdx(paramsType->ToTypeInstance(), 0, "Invoke");
|
||||||
|
@ -24999,13 +25034,15 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
|
||||||
}
|
}
|
||||||
else if (resolvedParamType->IsGenericParam())
|
else if (resolvedParamType->IsGenericParam())
|
||||||
{
|
{
|
||||||
|
bool isGenericDelegateParams = false;
|
||||||
|
bool addDelegateParamsType = false;
|
||||||
|
|
||||||
auto genericParamInstance = GetGenericParamInstance((BfGenericParamType*)resolvedParamType, false, BfFailHandleKind_Ignore);
|
auto genericParamInstance = GetGenericParamInstance((BfGenericParamType*)resolvedParamType, false, BfFailHandleKind_Ignore);
|
||||||
if (genericParamInstance == NULL)
|
if (genericParamInstance == NULL)
|
||||||
{
|
{
|
||||||
// Delegate case with a 'params T'?
|
// Delegate case with a 'params T'?
|
||||||
mCurMethodInstance->mHadGenericDelegateParams = true;
|
isGenericDelegateParams = true;
|
||||||
isValid = true;
|
addDelegateParamsType = true;
|
||||||
addParams = false;
|
|
||||||
}
|
}
|
||||||
else if (genericParamInstance->mTypeConstraint != NULL)
|
else if (genericParamInstance->mTypeConstraint != NULL)
|
||||||
{
|
{
|
||||||
|
@ -25021,10 +25058,29 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
|
||||||
else if ((genericParamInstance->mTypeConstraint->IsDelegate()) || (genericParamInstance->mTypeConstraint->IsFunction()) || (genericParamInstance->mTypeConstraint->IsTuple()) ||
|
else if ((genericParamInstance->mTypeConstraint->IsDelegate()) || (genericParamInstance->mTypeConstraint->IsFunction()) || (genericParamInstance->mTypeConstraint->IsTuple()) ||
|
||||||
((genericParamInstance != NULL) && (typeInstConstraint != NULL) &&
|
((genericParamInstance != NULL) && (typeInstConstraint != NULL) &&
|
||||||
((typeInstConstraint->IsInstanceOf(mCompiler->mDelegateTypeDef)) || (typeInstConstraint->IsInstanceOf(mCompiler->mFunctionTypeDef)) || (typeInstConstraint->IsInstanceOf(mCompiler->mTupleTypeDef)))))
|
((typeInstConstraint->IsInstanceOf(mCompiler->mDelegateTypeDef)) || (typeInstConstraint->IsInstanceOf(mCompiler->mFunctionTypeDef)) || (typeInstConstraint->IsInstanceOf(mCompiler->mTupleTypeDef)))))
|
||||||
|
{
|
||||||
|
isGenericDelegateParams = true;
|
||||||
|
//addDelegateParamsType = typeInstConstraint->IsInstanceOf(mCompiler->mTupleTypeDef);
|
||||||
|
addDelegateParamsType = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isGenericDelegateParams)
|
||||||
{
|
{
|
||||||
mCurMethodInstance->mHadGenericDelegateParams = true;
|
mCurMethodInstance->mHadGenericDelegateParams = true;
|
||||||
isValid = true;
|
isValid = true;
|
||||||
addParams = false;
|
addParams = false;
|
||||||
|
|
||||||
|
if (addDelegateParamsType)
|
||||||
|
{
|
||||||
|
BfMethodParam methodParam;
|
||||||
|
methodParam.mResolvedType = CreateModifiedTypeType(resolvedParamType, BfToken_Params);
|
||||||
|
methodParam.mParamDefIdx = paramDefIdx;
|
||||||
|
mCurMethodInstance->mParams.Add(methodParam);
|
||||||
|
|
||||||
|
//TODO: Why do we have this 'if'
|
||||||
|
if (!methodInstance->IsSpecializedGenericMethod())
|
||||||
|
AddDependency(methodParam.mResolvedType, mCurTypeInstance, BfDependencyMap::DependencyFlag_ParamOrReturnValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25032,9 +25088,9 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
|
||||||
{
|
{
|
||||||
auto paramTypeInst = resolvedParamType->ToTypeInstance();
|
auto paramTypeInst = resolvedParamType->ToTypeInstance();
|
||||||
if ((paramTypeInst != NULL) &&
|
if ((paramTypeInst != NULL) &&
|
||||||
((paramTypeInst->IsInstanceOf(mCompiler->mDelegateTypeDef)) || (paramTypeInst->IsInstanceOf(mCompiler->mFunctionTypeDef))))
|
((paramTypeInst->IsInstanceOf(mCompiler->mDelegateTypeDef)) || (paramTypeInst->IsInstanceOf(mCompiler->mFunctionTypeDef)) || (paramTypeInst->IsInstanceOf(mCompiler->mTupleTypeDef))))
|
||||||
{
|
{
|
||||||
// If we have a 'params T' and 'T' gets specialized with actually 'Delegate' or 'Function' then just ignore it
|
// If we have a 'params T' and 'T' gets specialized with actually 'Tuple', 'Delegate' or 'Function' then just ignore it
|
||||||
isValid = true;
|
isValid = true;
|
||||||
addParams = false;
|
addParams = false;
|
||||||
}
|
}
|
||||||
|
@ -25042,7 +25098,7 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
|
||||||
|
|
||||||
if (!isValid)
|
if (!isValid)
|
||||||
{
|
{
|
||||||
Fail("Parameters with 'params' specifiers can only be used for array, span, delegate, or function types", paramDef->mParamDeclaration->mModToken);
|
Fail("Parameters with 'params' specifiers can only be used for array, span, tuple, delegate, or function types", paramDef->mParamDeclaration->mModToken);
|
||||||
// Failure case, make it an Object[]
|
// Failure case, make it an Object[]
|
||||||
resolvedParamType = CreateArrayType(mContext->mBfObjectType, 1);
|
resolvedParamType = CreateArrayType(mContext->mBfObjectType, 1);
|
||||||
}
|
}
|
||||||
|
@ -25100,7 +25156,7 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool
|
||||||
auto tupleType = (BfTupleType*)methodParam.mResolvedType;
|
auto tupleType = (BfTupleType*)methodParam.mResolvedType;
|
||||||
auto& fieldInstance = tupleType->mFieldInstances[methodParam.mDelegateParamIdx];
|
auto& fieldInstance = tupleType->mFieldInstances[methodParam.mDelegateParamIdx];
|
||||||
auto paramName = fieldInstance.GetFieldDef()->mName;
|
auto paramName = fieldInstance.GetFieldDef()->mName;
|
||||||
if (!usedNames.Add(paramName))
|
if ((!usedNames.Add(paramName)) || (::isdigit((uint8)paramName[0])))
|
||||||
methodParam.mDelegateParamNameCombine = true;
|
methodParam.mDelegateParamNameCombine = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -93,6 +93,7 @@ enum BfEvalExprFlags : int64
|
||||||
BfEvalExprFlags_AppendFieldInitializer = 0x80000000,
|
BfEvalExprFlags_AppendFieldInitializer = 0x80000000,
|
||||||
BfEvalExprFlags_NameOf = 0x100000000LL,
|
BfEvalExprFlags_NameOf = 0x100000000LL,
|
||||||
BfEvalExprFlags_NameOfSuccess = 0x200000000LL,
|
BfEvalExprFlags_NameOfSuccess = 0x200000000LL,
|
||||||
|
BfEvalExprFlags_InParamsExpr = 0x400000000LL,
|
||||||
|
|
||||||
BfEvalExprFlags_InheritFlags = BfEvalExprFlags_NoAutoComplete | BfEvalExprFlags_Comptime | BfEvalExprFlags_DeclType
|
BfEvalExprFlags_InheritFlags = BfEvalExprFlags_NoAutoComplete | BfEvalExprFlags_Comptime | BfEvalExprFlags_DeclType
|
||||||
};
|
};
|
||||||
|
|
|
@ -15280,6 +15280,13 @@ BfTypedValue BfModule::Cast(BfAstNode* srcNode, const BfTypedValue& typedVal, Bf
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
BfCastResultFlags castResultFlags = BfCastResultFlags_None;
|
BfCastResultFlags castResultFlags = BfCastResultFlags_None;
|
||||||
|
|
||||||
|
if ((typedVal.IsParams()) && (toType->IsParamsType()))
|
||||||
|
{
|
||||||
|
if (typedVal.mType == toType->GetUnderlyingType())
|
||||||
|
return BfTypedValue(mBfIRBuilder->GetFakeVal(), toType);
|
||||||
|
}
|
||||||
|
|
||||||
auto castedValue = CastToValue(srcNode, typedVal, toType, castFlags, &castResultFlags);
|
auto castedValue = CastToValue(srcNode, typedVal, toType, castFlags, &castResultFlags);
|
||||||
if (!castedValue)
|
if (!castedValue)
|
||||||
return BfTypedValue();
|
return BfTypedValue();
|
||||||
|
|
|
@ -1176,11 +1176,6 @@ void BfMethodInstance::GetParamName(int paramIdx, StringImpl& name, int& namePre
|
||||||
else
|
else
|
||||||
name = fieldInstance.GetFieldDef()->mName;
|
name = fieldInstance.GetFieldDef()->mName;
|
||||||
|
|
||||||
if (name == "p__a__a")
|
|
||||||
{
|
|
||||||
NOP;
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -626,6 +626,7 @@ public:
|
||||||
virtual bool IsOnDemand() { return false; }
|
virtual bool IsOnDemand() { return false; }
|
||||||
virtual bool IsTemporary() { return false; }
|
virtual bool IsTemporary() { return false; }
|
||||||
virtual bool IsModifiedTypeType() { return false; }
|
virtual bool IsModifiedTypeType() { return false; }
|
||||||
|
virtual bool IsParamsType() { return false; }
|
||||||
virtual bool IsConcreteInterfaceType() { return false; }
|
virtual bool IsConcreteInterfaceType() { return false; }
|
||||||
virtual bool IsTypeAlias() { return false; }
|
virtual bool IsTypeAlias() { return false; }
|
||||||
virtual bool HasPackingHoles() { return false; }
|
virtual bool HasPackingHoles() { return false; }
|
||||||
|
@ -1142,6 +1143,7 @@ public:
|
||||||
BfType* mElementType;
|
BfType* mElementType;
|
||||||
|
|
||||||
virtual bool IsModifiedTypeType() override { return true; }
|
virtual bool IsModifiedTypeType() override { return true; }
|
||||||
|
virtual bool IsParamsType() override { return mModifiedKind == BfToken_Params; }
|
||||||
virtual bool CanBeValuelessType() override { return true; }
|
virtual bool CanBeValuelessType() override { return true; }
|
||||||
virtual bool IsValuelessType() override { return true; }
|
virtual bool IsValuelessType() override { return true; }
|
||||||
|
|
||||||
|
|
|
@ -6311,6 +6311,25 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8*
|
||||||
_FixVariables();
|
_FixVariables();
|
||||||
CeSetAddrVal(stackPtr + 0, reflectType, ptrSize);
|
CeSetAddrVal(stackPtr + 0, reflectType, ptrSize);
|
||||||
}
|
}
|
||||||
|
else if (checkFunction->mFunctionKind == CeFunctionKind_GetWrappedType)
|
||||||
|
{
|
||||||
|
int32 typeId = *(int32*)((uint8*)stackPtr + ceModule->mSystem->mPtrSize);
|
||||||
|
|
||||||
|
BfType* type = GetBfType(typeId);
|
||||||
|
bool success = false;
|
||||||
|
if (type == NULL)
|
||||||
|
{
|
||||||
|
_Fail("Invalid type");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
addr_ce reflectType = NULL;
|
||||||
|
type = ceModule->GetWrappedStructType(type);
|
||||||
|
if (type != NULL)
|
||||||
|
reflectType = GetReflectType(type->mTypeId);
|
||||||
|
_FixVariables();
|
||||||
|
CeSetAddrVal(stackPtr + 0, reflectType, ptrSize);
|
||||||
|
}
|
||||||
else if (checkFunction->mFunctionKind == CeFunctionKind_GetReflectTypeByName)
|
else if (checkFunction->mFunctionKind == CeFunctionKind_GetReflectTypeByName)
|
||||||
{
|
{
|
||||||
addr_ce strViewPtr = *(addr_ce*)((uint8*)stackPtr + ptrSize);
|
addr_ce strViewPtr = *(addr_ce*)((uint8*)stackPtr + ptrSize);
|
||||||
|
@ -6896,6 +6915,19 @@ bool CeContext::Execute(CeFunction* startFunction, uint8* startStackPtr, uint8*
|
||||||
|
|
||||||
mCurModule->CEMixin(mCurCallSource->mRefNode, emitStr);
|
mCurModule->CEMixin(mCurCallSource->mRefNode, emitStr);
|
||||||
}
|
}
|
||||||
|
else if (checkFunction->mFunctionKind == CeFunctionKind_GetStringById)
|
||||||
|
{
|
||||||
|
int32 stringId = *(int32*)((uint8*)stackPtr + ptrSize);
|
||||||
|
|
||||||
|
String string = "";
|
||||||
|
BfStringPoolEntry* valuePtr = NULL;
|
||||||
|
mCurModule->mContext->mStringObjectIdMap.TryGetValue(stringId, &valuePtr);
|
||||||
|
if (valuePtr != NULL)
|
||||||
|
string = valuePtr->mString;
|
||||||
|
|
||||||
|
CeSetAddrVal(stackPtr + 0, GetString(string), ptrSize);
|
||||||
|
_FixVariables();
|
||||||
|
}
|
||||||
else if (checkFunction->mFunctionKind == CeFunctionKind_Sleep)
|
else if (checkFunction->mFunctionKind == CeFunctionKind_Sleep)
|
||||||
{
|
{
|
||||||
int32 sleepMS = *(int32*)((uint8*)stackPtr);
|
int32 sleepMS = *(int32*)((uint8*)stackPtr);
|
||||||
|
@ -10019,6 +10051,10 @@ void CeMachine::CheckFunctionKind(CeFunction* ceFunction)
|
||||||
{
|
{
|
||||||
ceFunction->mFunctionKind = CeFunctionKind_GetReflectTypeById;
|
ceFunction->mFunctionKind = CeFunctionKind_GetReflectTypeById;
|
||||||
}
|
}
|
||||||
|
else if (methodDef->mName == "Comptime_GetWrappedType")
|
||||||
|
{
|
||||||
|
ceFunction->mFunctionKind = CeFunctionKind_GetWrappedType;
|
||||||
|
}
|
||||||
else if (methodDef->mName == "Comptime_GetTypeByName")
|
else if (methodDef->mName == "Comptime_GetTypeByName")
|
||||||
{
|
{
|
||||||
ceFunction->mFunctionKind = CeFunctionKind_GetReflectTypeByName;
|
ceFunction->mFunctionKind = CeFunctionKind_GetReflectTypeByName;
|
||||||
|
@ -10126,6 +10162,10 @@ void CeMachine::CheckFunctionKind(CeFunction* ceFunction)
|
||||||
{
|
{
|
||||||
ceFunction->mFunctionKind = CeFunctionKind_EmitMixin;
|
ceFunction->mFunctionKind = CeFunctionKind_EmitMixin;
|
||||||
}
|
}
|
||||||
|
else if (methodDef->mName == "Comptime_GetStringById")
|
||||||
|
{
|
||||||
|
ceFunction->mFunctionKind = CeFunctionKind_GetStringById;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (owner->IsInstanceOf(mCeModule->mCompiler->mDiagnosticsDebugTypeDef))
|
else if (owner->IsInstanceOf(mCeModule->mCompiler->mDiagnosticsDebugTypeDef))
|
||||||
{
|
{
|
||||||
|
|
|
@ -436,6 +436,7 @@ enum CeFunctionKind
|
||||||
CeFunctionKind_HasDeclaredMember,
|
CeFunctionKind_HasDeclaredMember,
|
||||||
CeFunctionKind_GetReflectType,
|
CeFunctionKind_GetReflectType,
|
||||||
CeFunctionKind_GetReflectTypeById,
|
CeFunctionKind_GetReflectTypeById,
|
||||||
|
CeFunctionKind_GetWrappedType,
|
||||||
CeFunctionKind_GetReflectTypeByName,
|
CeFunctionKind_GetReflectTypeByName,
|
||||||
CeFunctionKind_GetReflectSpecializedType,
|
CeFunctionKind_GetReflectSpecializedType,
|
||||||
CeFunctionKind_Type_ToString,
|
CeFunctionKind_Type_ToString,
|
||||||
|
@ -463,6 +464,7 @@ enum CeFunctionKind
|
||||||
CeFunctionKind_EmitMethodEntry,
|
CeFunctionKind_EmitMethodEntry,
|
||||||
CeFunctionKind_EmitMethodExit,
|
CeFunctionKind_EmitMethodExit,
|
||||||
CeFunctionKind_EmitMixin,
|
CeFunctionKind_EmitMixin,
|
||||||
|
CeFunctionKind_GetStringById,
|
||||||
|
|
||||||
CeFunctionKind_BfpDirectory_Create,
|
CeFunctionKind_BfpDirectory_Create,
|
||||||
CeFunctionKind_BfpDirectory_Rename,
|
CeFunctionKind_BfpDirectory_Rename,
|
||||||
|
|
|
@ -1,9 +1,293 @@
|
||||||
|
#pragma warning disable 168
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
namespace Tests;
|
namespace Tests;
|
||||||
|
|
||||||
class Params
|
class Params
|
||||||
{
|
{
|
||||||
|
[AttributeUsage(.Method)]
|
||||||
|
struct StringFormatAttribute : Attribute, IOnMethodInit
|
||||||
|
{
|
||||||
|
[Comptime]
|
||||||
|
public void OnMethodInit(MethodInfo methodInfo, Self* prev)
|
||||||
|
{
|
||||||
|
String code = scope .();
|
||||||
|
|
||||||
|
String format = null;
|
||||||
|
|
||||||
|
if (var constType = methodInfo.GetGenericArgType(0) as ConstExprType)
|
||||||
|
{
|
||||||
|
if (constType.ValueType == typeof(String))
|
||||||
|
{
|
||||||
|
format = String.GetById(constType.ValueData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (String.IsNullOrEmpty(format))
|
||||||
|
return;
|
||||||
|
|
||||||
|
int pos = 0;
|
||||||
|
int len = format.Length;
|
||||||
|
char8 ch = '\x00';
|
||||||
|
|
||||||
|
String s = null;
|
||||||
|
String fmt = "";
|
||||||
|
int autoArgIdx = 0;
|
||||||
|
bool hasTempStr = false;
|
||||||
|
|
||||||
|
void FormatError()
|
||||||
|
{
|
||||||
|
Runtime.FatalError("Format Error");
|
||||||
|
}
|
||||||
|
|
||||||
|
String bufOut = scope .();
|
||||||
|
|
||||||
|
void FlushOut()
|
||||||
|
{
|
||||||
|
if (bufOut.IsEmpty)
|
||||||
|
return;
|
||||||
|
code.Append("outStr.Append(");
|
||||||
|
bufOut.Quote(code);
|
||||||
|
code.Append(");\n");
|
||||||
|
bufOut.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
int p = pos;
|
||||||
|
int i = pos;
|
||||||
|
while (pos < len)
|
||||||
|
{
|
||||||
|
ch = format[pos];
|
||||||
|
|
||||||
|
pos++;
|
||||||
|
if (ch == '}')
|
||||||
|
{
|
||||||
|
if (pos < len && format[pos] == '}') // Treat as escape character for }}
|
||||||
|
pos++;
|
||||||
|
else
|
||||||
|
FormatError();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ch == '{')
|
||||||
|
{
|
||||||
|
if (pos < len && format[pos] == '{') // Treat as escape character for {{
|
||||||
|
pos++;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pos--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bufOut.Append(ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pos == len) break;
|
||||||
|
pos++;
|
||||||
|
int index = 0;
|
||||||
|
if (pos == len || (ch = format[pos]) < '0' || ch > '9')
|
||||||
|
{
|
||||||
|
if ((pos < len) &&
|
||||||
|
((ch == '}') || (ch == ':') || (ch == ',')))
|
||||||
|
index = autoArgIdx++;
|
||||||
|
else
|
||||||
|
FormatError();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
repeat
|
||||||
|
{
|
||||||
|
index = index * 10 + ch - '0';
|
||||||
|
pos++;
|
||||||
|
if (pos == len) FormatError();
|
||||||
|
ch = format[pos];
|
||||||
|
}
|
||||||
|
while (ch >= '0' && ch <= '9' && index < 1000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
var paramType = methodInfo.GetParamType(index + 3);
|
||||||
|
var paramName = methodInfo.GetParamName(index + 3);
|
||||||
|
|
||||||
|
while (pos < len && (ch = format[pos]) == ' ') pos++;
|
||||||
|
bool leftJustify = false;
|
||||||
|
int width = 0;
|
||||||
|
if (ch == ',')
|
||||||
|
{
|
||||||
|
pos++;
|
||||||
|
while (pos < len && format[pos] == ' ') pos++;
|
||||||
|
|
||||||
|
if (pos == len) FormatError();
|
||||||
|
ch = format[pos];
|
||||||
|
if (ch == '-')
|
||||||
|
{
|
||||||
|
leftJustify = true;
|
||||||
|
pos++;
|
||||||
|
if (pos == len) FormatError();
|
||||||
|
ch = format[pos];
|
||||||
|
}
|
||||||
|
if (ch < '0' || ch > '9') FormatError();
|
||||||
|
repeat
|
||||||
|
{
|
||||||
|
width = width * 10 + ch - '0';
|
||||||
|
pos++;
|
||||||
|
if (pos == len) FormatError();
|
||||||
|
ch = format[pos];
|
||||||
|
}
|
||||||
|
while (ch >= '0' && ch <= '9' && width < 1000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (pos < len && (ch = format[pos]) == ' ') pos++;
|
||||||
|
|
||||||
|
//Object arg = args[index];
|
||||||
|
if (ch == ':')
|
||||||
|
{
|
||||||
|
if (fmt == "")
|
||||||
|
fmt = scope:: String(64);
|
||||||
|
else
|
||||||
|
fmt.Clear();
|
||||||
|
|
||||||
|
bool isFormatEx = false;
|
||||||
|
pos++;
|
||||||
|
p = pos;
|
||||||
|
i = pos;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (pos == len) FormatError();
|
||||||
|
ch = format[pos];
|
||||||
|
pos++;
|
||||||
|
if (ch == '{')
|
||||||
|
{
|
||||||
|
isFormatEx = true;
|
||||||
|
if (pos < len && format[pos] == '{') // Treat as escape character for {{
|
||||||
|
pos++;
|
||||||
|
else
|
||||||
|
FormatError();
|
||||||
|
}
|
||||||
|
else if (ch == '}')
|
||||||
|
{
|
||||||
|
// We only treat '}}' as an escape character if the format had an opening '{'. Otherwise we just close on the first '}'
|
||||||
|
if ((isFormatEx) && (pos < len && format[pos] == '}')) // Treat as escape character for }}
|
||||||
|
pos++;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pos--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fmt == null)
|
||||||
|
{
|
||||||
|
fmt = scope:: String(0x100);
|
||||||
|
}
|
||||||
|
fmt.Append(ch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ch != '}') Runtime.FatalError("Format error");
|
||||||
|
pos++;
|
||||||
|
FlushOut();
|
||||||
|
|
||||||
|
bool checkNull = paramType.IsObject || paramType.IsInterface;
|
||||||
|
bool hasWidth = width != 0;
|
||||||
|
bool hasFmt = fmt != "";
|
||||||
|
|
||||||
|
if (checkNull)
|
||||||
|
{
|
||||||
|
code.AppendF($"if ({paramName} == null)\n");
|
||||||
|
code.Append(" outStr.Append(\"null\");\nelse\n{\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((!leftJustify) && (width > 0))
|
||||||
|
{
|
||||||
|
// We need a temporary string
|
||||||
|
if (!hasTempStr)
|
||||||
|
{
|
||||||
|
code.Insert(0, "var s = scope String(128);\n");
|
||||||
|
hasTempStr = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
code.Append("s.Clear();\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (paramType.ImplementsInterface(typeof(IFormattable)))
|
||||||
|
{
|
||||||
|
if (!hasFmt)
|
||||||
|
{
|
||||||
|
code.AppendF("if (provider != null)\n ");
|
||||||
|
}
|
||||||
|
|
||||||
|
code.AppendF($"((IFormattable){paramName}).ToString(s, ");
|
||||||
|
fmt.Quote(code);
|
||||||
|
code.AppendF($", provider);\n");
|
||||||
|
|
||||||
|
if (!hasFmt)
|
||||||
|
{
|
||||||
|
code.AppendF("else\n");
|
||||||
|
code.AppendF($" {paramName}.ToString(s);\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
code.AppendF($"{paramName}.ToString(s);\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
code.AppendF($"outStr.Append(' ', {width} - s.[Friend]mLength);\n");
|
||||||
|
code.Append("outStr.Append(s);\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (hasWidth)
|
||||||
|
{
|
||||||
|
code.AppendF($"int start_{pos} = outStr.[Friend]mLength;\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (paramType.ImplementsInterface(typeof(IFormattable)))
|
||||||
|
{
|
||||||
|
if (!hasFmt)
|
||||||
|
{
|
||||||
|
code.AppendF("if (provider != null)\n ");
|
||||||
|
}
|
||||||
|
|
||||||
|
code.AppendF($"((IFormattable){paramName}).ToString(outStr, ");
|
||||||
|
fmt.Quote(code);
|
||||||
|
code.AppendF($", provider);\n");
|
||||||
|
|
||||||
|
if (!hasFmt)
|
||||||
|
{
|
||||||
|
code.AppendF("else\n");
|
||||||
|
code.AppendF($" {paramName}.ToString(outStr);\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
code.AppendF($"{paramName}.ToString(outStr);\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasWidth)
|
||||||
|
{
|
||||||
|
code.AppendF($"outStr.Append(' ', {width} - (outStr.[Friend]mLength - start_{pos}));\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (checkNull)
|
||||||
|
{
|
||||||
|
code.Append("}\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FlushOut();
|
||||||
|
Compiler.EmitMethodEntry(methodInfo, code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[StringFormat]
|
||||||
|
static void StrFormat<TStr, TArgs>(String outStr, IFormatProvider provider, TStr formatStr, params TArgs args) where TStr : const String where TArgs : Tuple
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
class ClassA<T> where T : Tuple
|
class ClassA<T> where T : Tuple
|
||||||
{
|
{
|
||||||
public static int Test(delegate int(char8 a, params T) dlg, params T par)
|
public static int Test(delegate int(char8 a, params T) dlg, params T par)
|
||||||
|
@ -17,6 +301,39 @@ class Params
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void Test1<T>(params T args) where T : Tuple
|
||||||
|
{
|
||||||
|
Test3<T>(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Test2<T>(params T args) where T : Delegate
|
||||||
|
{
|
||||||
|
var vals = args;
|
||||||
|
Test3(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Test3<T>(T args) where T : Tuple
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Test4<T>(params (int, float) args)
|
||||||
|
{
|
||||||
|
var a = args;
|
||||||
|
int arg0 = a.0;
|
||||||
|
float arg1 = a.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct StructA
|
||||||
|
{
|
||||||
|
public int mA;
|
||||||
|
|
||||||
|
public override void ToString(String strBuffer)
|
||||||
|
{
|
||||||
|
strBuffer.AppendF($"StructA({mA})");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public static void TestBasics()
|
public static void TestBasics()
|
||||||
{
|
{
|
||||||
|
@ -25,5 +342,15 @@ class Params
|
||||||
return (.)a + (.)__a + (.)b;
|
return (.)a + (.)__a + (.)b;
|
||||||
}, 10, 2.3f);
|
}, 10, 2.3f);
|
||||||
Test.Assert(val == 65+10+2);
|
Test.Assert(val == 65+10+2);
|
||||||
|
|
||||||
|
Test1(1, 2.3f);
|
||||||
|
delegate void(int a, float b) dlg = default;
|
||||||
|
Test2<delegate void(int a, float b)>(1, 2.3f);
|
||||||
|
|
||||||
|
String tStr = null;
|
||||||
|
|
||||||
|
StructA sa = .() { mA = 123 };
|
||||||
|
String str = StrFormat(.. scope .(), null, $"This is a test string {123,-6} with some numbers in it {234,6} {0x1234:X} {sa} {tStr}.");
|
||||||
|
Test.Assert(str == "This is a test string 123 with some numbers in it 234 1234 StructA(123) null.");
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Add table
Add a link
Reference in a new issue