diff --git a/IDEHelper/Compiler/BfCompiler.cpp b/IDEHelper/Compiler/BfCompiler.cpp index f99cd5d8..c437c0f6 100644 --- a/IDEHelper/Compiler/BfCompiler.cpp +++ b/IDEHelper/Compiler/BfCompiler.cpp @@ -3828,7 +3828,10 @@ void BfCompiler::ProcessAutocompleteTempType() if (BfNodeIsA(fieldDef->mTypeRef)) { if (fieldDef->mInitializer == NULL) - mPassInstance->Fail("Implicitly-typed fields must be initialized", fieldDef->mFieldDeclaration); + { + if ((fieldDef->mTypeRef->IsA()) || (fieldDef->mTypeRef->IsA())) + mPassInstance->Fail("Implicitly-typed fields must be initialized", fieldDef->GetRefNode()); + } } } } diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 8f917b00..810e9fa3 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -3053,6 +3053,9 @@ BfTypedValue BfExprEvaluator::LookupField(BfAstNode* targetSrc, BfTypedValue tar fieldInstance->mResolvedType = mModule->ResolveVarFieldType(curCheckType, fieldInstance, field); if (fieldInstance->mResolvedType == NULL) return BfTypedValue(); + + if ((fieldInstance->mResolvedType->IsVar()) && (mModule->mCompiler->mIsResolveOnly)) + mModule->Fail("Field type reference failed to resolve", targetSrc); } auto resolvedFieldType = fieldInstance->mResolvedType; @@ -3332,7 +3335,7 @@ BfTypedValue BfExprEvaluator::LookupField(BfAstNode* targetSrc, BfTypedValue tar { if (retVal.IsAddr()) retVal.mKind = BfTypedValueKind_TempAddr; - } + } return retVal; } @@ -5080,7 +5083,10 @@ BfTypedValue BfExprEvaluator::CreateCall(BfAstNode* targetSrc, const BfTypedValu } auto func = moduleMethodInstance.mFunc; - return CreateCall(methodInstance, func, bypassVirtual, irArgs); + BfTypedValue result = CreateCall(methodInstance, func, bypassVirtual, irArgs); + if ((result.mType != NULL) && (result.mType->IsVar()) && (mModule->mCompiler->mIsResolveOnly)) + mModule->Fail("Method return type reference failed to resolve", targetSrc); + return result; } BfTypedValue BfExprEvaluator::MatchConstructor(BfAstNode* targetSrc, BfMethodBoundExpression* methodBoundExpr, BfTypedValue target, BfTypeInstance* targetType, BfResolvedArgs& argValues, bool callCtorBodyOnly, bool allowAppendAlloc, BfTypedValue* appendIndexValue) @@ -7718,13 +7724,45 @@ void BfExprEvaluator::Visit(BfCheckTypeExpression* checkTypeExpr) auto objectType = mModule->mContext->mBfObjectType; mModule->PopulateType(objectType, BfPopulateType_Full); + + targetValue = mModule->LoadValue(targetValue); + + BfTypeInstance* srcTypeInstance = targetValue.mType->ToTypeInstance(); + BfTypeInstance* targetTypeInstance = targetType->ToTypeInstance(); + bool wasGenericParamType = false; + + if ((srcTypeInstance != NULL) && (targetTypeInstance != NULL)) + { + if (mModule->TypeIsSubTypeOf(srcTypeInstance, targetTypeInstance)) + { + // We don't give this warning when we have wasGenericParmType set because that indicates we had a generic type constraint, + // and a type constraint infers that the ACTUAL type used will be equal to or derived from that type and therefore + // it may be a "necessary cast" indeed + if ((!wasGenericParamType) && (mModule->mCurMethodState->mMixinState == NULL)) + { + if (srcTypeInstance == targetType) + mModule->Warn(BfWarning_BF4203_UnnecessaryDynamicCast, StrFormat("Unnecessary cast, the value is already type '%s'", + mModule->TypeToString(srcTypeInstance).c_str()), checkTypeExpr->mIsToken); + else + mModule->Warn(BfWarning_BF4203_UnnecessaryDynamicCast, StrFormat("Unnecessary cast, '%s' is a subtype of '%s'", + mModule->TypeToString(srcTypeInstance).c_str(), mModule->TypeToString(targetType).c_str()), checkTypeExpr->mIsToken); + } + + mResult = BfTypedValue(mModule->mBfIRBuilder->CreateConst(BfTypeCode_Boolean, 1), boolType); + return; + } + else if ((!targetType->IsInterface()) && (srcTypeInstance != mModule->mContext->mBfObjectType) && (!mModule->TypeIsSubTypeOf(targetTypeInstance, srcTypeInstance))) + { + mModule->Fail(StrFormat("Cannot convert type '%s' to '%s' via any conversion", + mModule->TypeToString(targetValue.mType).c_str(), mModule->TypeToString(targetTypeInstance).c_str()), checkTypeExpr->mIsToken); + } + } + if (mModule->mCompiler->IsAutocomplete()) { mResult = mModule->GetDefaultTypedValue(boolType, false, BfDefaultValueKind_Addr); return; } - - targetValue = mModule->LoadValue(targetValue); auto irb = mModule->mBfIRBuilder; auto prevBB = mModule->mBfIRBuilder->GetInsertBlock(); @@ -7835,6 +7873,9 @@ void BfExprEvaluator::Visit(BfDynamicCastExpression* dynCastExpr) auto boolType = mModule->GetPrimitiveType(BfTypeCode_Boolean); if (targetValue.mType->IsValueTypeOrValueTypePtr()) { + mModule->Warn(0, StrFormat("Type '%s' is not applicable for dynamic casting", + mModule->TypeToString(targetValue.mType).c_str()), dynCastExpr->mAsToken); + auto typeInstance = targetValue.mType->ToTypeInstance(); if (targetValue.mType->IsWrappableType()) typeInstance = mModule->GetWrappedStructType(targetValue.mType); @@ -7955,7 +7996,7 @@ void BfExprEvaluator::Visit(BfDynamicCastExpression* dynCastExpr) else if ((!targetType->IsInterface()) && (!mModule->TypeIsSubTypeOf(targetTypeInstance, srcTypeInstance))) { mModule->Fail(StrFormat("Cannot convert type '%s' to '%s' via any conversion", - mModule->TypeToString(targetTypeInstance).c_str(), mModule->TypeToString(targetValue.mType).c_str()), dynCastExpr->mAsToken); + mModule->TypeToString(targetValue.mType).c_str(), mModule->TypeToString(targetTypeInstance).c_str()), dynCastExpr->mAsToken); } if (autoComplete != NULL) @@ -12514,9 +12555,13 @@ void BfExprEvaluator::DoInvocation(BfAstNode* target, BfMethodBoundExpression* m } else if (auto expr = BfNodeDynCast(memberRefExpression->mTarget)) { + BfType* expectingTargetType = NULL; + if (memberRefExpression->mDotToken->mToken == BfToken_DotDot) + expectingTargetType = mExpectingType; + bool handled = false; if (auto subMemberRefExpr = BfNodeDynCast(expr)) - { + { String findName; if (subMemberRefExpr->mMemberName != NULL) findName = subMemberRefExpr->mMemberName->ToString(); @@ -12570,7 +12615,7 @@ void BfExprEvaluator::DoInvocation(BfAstNode* target, BfMethodBoundExpression* m if (!handled) { SetAndRestoreValue prevAttributeState(mModule->mAttributeState, &attributeState); - auto flags = BfEvalExprFlags_PropogateNullConditional; + auto flags = (BfEvalExprFlags)(BfEvalExprFlags_PropogateNullConditional | BfEvalExprFlags_NoCast); if (mFunctionBindResult != NULL) { if (auto paranExpr = BfNodeDynCast(expr)) @@ -12582,7 +12627,7 @@ void BfExprEvaluator::DoInvocation(BfAstNode* target, BfMethodBoundExpression* m } if (expr != NULL) - mResult = mModule->CreateValueFromExpression(expr, NULL, flags); + mResult = mModule->CreateValueFromExpression(expr, expectingTargetType, flags); } } @@ -13253,7 +13298,11 @@ BfTypedValue BfExprEvaluator::GetResult(bool clearResult, bool resolveGenericTyp else mResult = CreateCall(methodInstance.mMethodInstance, methodInstance.mFunc, mPropDefBypassVirtual, args); if (mResult.mType != NULL) + { + if ((mResult.mType->IsVar()) && (mModule->mCompiler->mIsResolveOnly)) + mModule->Fail("Property type reference failed to resolve", mPropSrc); BF_ASSERT(!mResult.mType->IsRef()); + } } mPropDef = NULL; mPropDefBypassVirtual = false; diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 9f662ff9..2cdc236d 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -2462,6 +2462,12 @@ void BfModule::SetElementType(BfAstNode* astNode, BfSourceElementType elementTyp } } +void BfModule::SetHadVarUsage() +{ + mHadVarUsage = true; + mHadBuildError = true; +} + BfError* BfModule::Fail(const StringImpl& error, BfAstNode* refNode, bool isPersistent) { BP_ZONE("BfModule::Fail"); @@ -3340,6 +3346,8 @@ BfType* BfModule::ResolveVarFieldType(BfTypeInstance* typeInstance, BfFieldInsta bool staticOnly = (field->mIsStatic) && (!isDeclType); + if (!fieldInstance->mIsInferredType) + return fieldType; if (!fieldType->IsVar()) return fieldType; @@ -3353,7 +3361,8 @@ BfType* BfModule::ResolveVarFieldType(BfTypeInstance* typeInstance, BfFieldInsta if ((!field->mIsStatic) && (typeDef->mIsStatic)) { AssertErrorState(); - return mContext->mBfObjectType; + SetHadVarUsage(); + return GetPrimitiveType(BfTypeCode_Var); } bool hadInferenceCycle = false; @@ -3372,7 +3381,8 @@ BfType* BfModule::ResolveVarFieldType(BfTypeInstance* typeInstance, BfFieldInsta fieldModule->Fail(StrFormat("Field '%s.%s' creates a type inference cycle", TypeToString(fieldOwner).c_str(), fieldDef->mName.c_str()), fieldDef->mTypeRef, true); } - return mContext->mBfObjectType; + SetHadVarUsage(); + return GetPrimitiveType(BfTypeCode_Var); } } mContext->mFieldResolveReentrys.push_back(fieldInstance); @@ -3383,8 +3393,10 @@ BfType* BfModule::ResolveVarFieldType(BfTypeInstance* typeInstance, BfFieldInsta if ((field->mInitializer == NULL) && (!isDeclType)) { - Fail("Implicitly-typed fields must be initialized", field->mFieldDeclaration); - return mContext->mBfObjectType; + if ((field->mTypeRef->IsA()) || (field->mTypeRef->IsA())) + Fail("Implicitly-typed fields must be initialized", field->GetRefNode()); + SetHadVarUsage(); + return GetPrimitiveType(BfTypeCode_Var); } BfType* resolvedType = NULL; @@ -3421,7 +3433,7 @@ BfType* BfModule::ResolveVarFieldType(BfTypeInstance* typeInstance, BfFieldInsta } if (resolvedType == NULL) - return mContext->mBfObjectType; + return GetPrimitiveType(BfTypeCode_Var); fieldInstance->SetResolvedType(resolvedType); @@ -11839,7 +11851,7 @@ void BfModule::DoAddLocalVariable(BfLocalVariable* localVar) { if (localVar->mResolvedType->IsVar()) { - BF_ASSERT((mCurMethodInstance->mIsUnspecialized) || (mCurMethodState->mClosureState != NULL)); + BF_ASSERT((mCurMethodInstance->mIsUnspecialized) || (mCurMethodState->mClosureState != NULL) || (mHadVarUsage)); } localVar->mLocalVarIdx = (int)mCurMethodState->mLocals.size(); @@ -12008,7 +12020,7 @@ void BfModule::CreateDIRetVal() if ((mCurMethodState->mRetVal) || (mCurMethodState->mRetValAddr)) { - BF_ASSERT(!mBfIRBuilder->mIgnoreWrites); + BF_ASSERT((!mBfIRBuilder->mIgnoreWrites) || (mHadVarUsage)); BfType* dbgType = mCurMethodInstance->mReturnType; BfIRValue dbgValue = mCurMethodState->mRetVal.mValue; @@ -13150,12 +13162,17 @@ void BfModule::CreateStaticCtor() // For extensions, only handle these fields in the appropriate extension if ((fieldDef->mDeclaringType->mTypeDeclaration != methodDef->mDeclaringType->mTypeDeclaration)) continue; - + UpdateSrcPos(fieldDef->mInitializer); auto fieldInst = &mCurTypeInstance->mFieldInstances[fieldDef->mIdx]; if (!fieldInst->mFieldIncluded) continue; + if (fieldInst->mResolvedType->IsVar()) + { + BF_ASSERT(mHadVarUsage); + continue; + } auto assignValue = GetFieldInitializerValue(fieldInst); if (assignValue) { @@ -18665,11 +18682,11 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool if ((resolvedReturnType != NULL) && (resolvedReturnType->IsVar()) && (methodDef->mMethodType != BfMethodType_Mixin)) { Fail("Cannot declare var return types", methodDef->mReturnTypeRef); - resolvedReturnType = mContext->mBfObjectType; + resolvedReturnType = GetPrimitiveType(BfTypeCode_Var); } if (resolvedReturnType == NULL) - resolvedReturnType = mContext->mBfObjectType; // Fake an object + resolvedReturnType = GetPrimitiveType(BfTypeCode_Var); } else { @@ -18807,7 +18824,7 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool } if (resolvedParamType == NULL) { - resolvedParamType = mContext->mBfObjectType; // Fake an object + resolvedParamType = GetPrimitiveType(BfTypeCode_Var); unresolvedParamType = resolvedParamType; if (mCurTypeInstance->IsBoxed()) { diff --git a/IDEHelper/Compiler/BfModule.h b/IDEHelper/Compiler/BfModule.h index dec835f7..9bd99078 100644 --- a/IDEHelper/Compiler/BfModule.h +++ b/IDEHelper/Compiler/BfModule.h @@ -1340,8 +1340,9 @@ public: bool mWroteToLib; bool mHadBuildError; bool mHadBuildWarning; + bool mHadVarUsage; bool mIgnoreErrors; - bool mIgnoreWarnings; + bool mIgnoreWarnings; bool mSetIllegalSrcPosition; bool mHadIgnoredError; bool mReportErrors; // Still puts system in error state when set to false @@ -1362,6 +1363,7 @@ public: void GetAccessAllowed(BfTypeInstance* checkType, bool& allowProtected, bool& allowPrivate); bool CheckProtection(BfProtectionCheckFlags& flags, BfTypeInstance* memberOwner, BfProtection memberProtection, BfTypeInstance* lookupStartType); void SetElementType(BfAstNode* astNode, BfSourceElementType elementType); + void SetHadVarUsage(); BfError* Fail(const StringImpl& error, BfAstNode* refNode = NULL, bool isPersistent = false); BfError* FailAfter(const StringImpl& error, BfAstNode* refNode); BfError* Warn(int warningNum, const StringImpl& warning, BfAstNode* refNode = NULL, bool isPersistent = false); diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index 2e2099da..e1f62544 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -2265,6 +2265,7 @@ bool BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy resolveEntry.mTypeArrayIdx = (int)llvmFieldTypes.size(); deferredVarResolves.push_back(resolveEntry); + fieldInstance->mIsInferredType = true; // For 'let', make read-only } else @@ -2273,10 +2274,11 @@ bool BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy resolvedFieldType = ResolveTypeRef(field->mTypeRef, BfPopulateType_Declaration, BfResolveTypeRefFlag_NoResolveGenericParam); if (resolvedFieldType == NULL) { - // Failed, just put in placeholder 'Object' + // Failed, just put in placeholder 'var' AssertErrorState(); - resolvedFieldType = mContext->mBfObjectType; - } + resolvedFieldType = GetPrimitiveType(BfTypeCode_Var); + SetHadVarUsage(); + } } if (resolvedFieldType->IsMethodRef()) @@ -8659,7 +8661,7 @@ BfIRValue BfModule::CastToValue(BfAstNode* srcNode, BfTypedValue typedVal, BfTyp // * <-> Var if ((typedVal.mType->IsVar()) || (toType->IsVar())) { - BF_ASSERT((mCurMethodInstance->mIsUnspecialized) || (mCurMethodState->mClosureState != NULL)); + BF_ASSERT((mCurMethodInstance->mIsUnspecialized) || (mCurMethodState->mClosureState != NULL) || (mHadVarUsage)); return GetDefaultValue(toType); } diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.h b/IDEHelper/Compiler/BfResolvedTypeUtils.h index cc8ece19..704106e0 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.h +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.h @@ -1088,6 +1088,7 @@ public: bool mFieldIncluded; bool mIsEnumPayloadCase; bool mIsThreadLocal; + bool mIsInferredType; int mLastRevisionReferenced; public: @@ -1109,7 +1110,8 @@ public: mFieldIncluded = copyFrom.mFieldIncluded; mIsEnumPayloadCase = copyFrom.mIsEnumPayloadCase; mIsThreadLocal = copyFrom.mIsThreadLocal; - mLastRevisionReferenced = copyFrom.mLastRevisionReferenced; + mIsInferredType = copyFrom.mIsInferredType; + mLastRevisionReferenced = copyFrom.mLastRevisionReferenced; } BfFieldInstance() @@ -1126,6 +1128,7 @@ public: mDataSize = 0; mFieldIncluded = true; mIsThreadLocal = false; + mIsInferredType = false; mLastRevisionReferenced = -1; } diff --git a/IDEHelper/Compiler/BfStmtEvaluator.cpp b/IDEHelper/Compiler/BfStmtEvaluator.cpp index c52294d1..b9c4ec27 100644 --- a/IDEHelper/Compiler/BfStmtEvaluator.cpp +++ b/IDEHelper/Compiler/BfStmtEvaluator.cpp @@ -1383,8 +1383,11 @@ BfLocalVariable* BfModule::HandleVariableDeclaration(BfVariableDeclaration* varD } } } - if (!initValue) - initValue = GetDefaultTypedValue(mContext->mBfObjectType); + if (!initValue) + { + initValue = GetDefaultTypedValue(GetPrimitiveType(BfTypeCode_Var)); + SetHadVarUsage(); + } if (initValue.mType->IsNull()) { Fail("Implicitly-typed variables cannot be initialized to 'null'", varDecl->mInitializer);