From 75afa659e9a16589638083a1fcf9e879225619cd Mon Sep 17 00:00:00 2001 From: Yong He Date: Thu, 28 Mar 2024 16:57:53 -0700 Subject: Fix type union logic in generic type inference. (#3852) --- source/slang/slang-ast-support-types.h | 9 ++++++--- source/slang/slang-check-constraint.cpp | 12 ++++++------ source/slang/slang-check-conversion.cpp | 11 ++++++++++- source/slang/slang-check-impl.h | 3 +++ source/slang/slang-stdlib.cpp | 7 ++++++- source/slang/slang.natvis | 10 +++++++--- 6 files changed, 38 insertions(+), 14 deletions(-) (limited to 'source') diff --git a/source/slang/slang-ast-support-types.h b/source/slang/slang-ast-support-types.h index 196a1d002..93fc3365d 100644 --- a/source/slang/slang-ast-support-types.h +++ b/source/slang/slang-ast-support-types.h @@ -140,12 +140,15 @@ namespace Slang // Cost of converting a pointer to bool kConversionCost_PtrToBool = 400, + // Cost of converting an integer to int16_t + kConversionCost_IntegerTruncate = 450, + + // Cost of converting an integer to a half type + kConversionCost_IntegerToHalfConversion = 500, + // Default case (usable for user-defined conversions) kConversionCost_Default = 500, - // Cost of converting an integer to int16_t - kConversionCost_IntegerTruncate = 700, - // Catch-all for conversions that should be discouraged // (i.e., that really shouldn't be made implicitly) // diff --git a/source/slang/slang-check-constraint.cpp b/source/slang/slang-check-constraint.cpp index 97dbbcfa3..6a9b0adfa 100644 --- a/source/slang/slang-check-constraint.cpp +++ b/source/slang/slang-check-constraint.cpp @@ -105,6 +105,7 @@ namespace Slang // through types `X` that are also builtin scalar types. // Type* bestType = nullptr; + ConversionCost bestCost = kConversionCost_Explicit; if(auto basicType = dynamicCast(type)) { for(Int baseTypeFlavorIndex = 0; baseTypeFlavorIndex < Int(BaseType::CountOf); baseTypeFlavorIndex++) @@ -123,7 +124,8 @@ namespace Slang continue; // We only want to consider types where we can implicitly convert from `type` - if(!canConvertImplicitly(candidateType, type)) + auto conversionCost = getConversionCost(candidateType, type); + if(!canConvertImplicitly(conversionCost)) continue; // At this point, we have a candidate type that is usable. @@ -139,18 +141,16 @@ namespace Slang // Otherwise, we want to pick the "better" type between `candidateType` // and `bestType`. // - // We are going to be a bit loose here, and not worry about the - // case where conversion is allowed in both directions. + // The candidate type that has lower conversion cost from `type` is better. // - // TODO: make this completely robust. - // - if(canConvertImplicitly(bestType, candidateType)) + if(conversionCost < bestCost) { // Our candidate can convert to the current "best" type, so // it is logically a more specific type that satisfies our // constraints, therefore we should keep it. // bestType = candidateType; + bestCost = conversionCost; } } } diff --git a/source/slang/slang-check-conversion.cpp b/source/slang/slang-check-conversion.cpp index aeb964cc9..e55a88077 100644 --- a/source/slang/slang-check-conversion.cpp +++ b/source/slang/slang-check-conversion.cpp @@ -1388,6 +1388,15 @@ namespace Slang return expr; } + bool SemanticsVisitor::canConvertImplicitly( + ConversionCost conversionCost) + { + // Is the conversion cheap enough to be done implicitly? + if (conversionCost >= kConversionCost_GeneralConversion) + return false; + return true; + } + bool SemanticsVisitor::canConvertImplicitly( Type* toType, QualType fromType) @@ -1395,7 +1404,7 @@ namespace Slang auto conversionCost = getConversionCost(toType, fromType); // Is the conversion cheap enough to be done implicitly? - if (conversionCost >= kConversionCost_GeneralConversion) + if (canConvertImplicitly(conversionCost)) return false; return true; diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h index a3ecc28b4..945618f36 100644 --- a/source/slang/slang-check-impl.h +++ b/source/slang/slang-check-impl.h @@ -2077,6 +2077,9 @@ namespace Slang Type* toType, QualType fromType); + bool canConvertImplicitly( + ConversionCost cost); + ConversionCost getConversionCost(Type* toType, QualType fromType); Type* _tryJoinTypeWithInterface( diff --git a/source/slang/slang-stdlib.cpp b/source/slang/slang-stdlib.cpp index 2bc24d8ec..3c8b48e00 100644 --- a/source/slang/slang-stdlib.cpp +++ b/source/slang/slang-stdlib.cpp @@ -222,7 +222,12 @@ namespace Slang { return kConversionCost_IntegerToFloatConversion; } - + else if (toInfo.conversionKind == kBaseTypeConversionKind_Float + && toInfo.conversionRank >= kBaseTypeConversionRank_Int16 + && fromInfo.conversionRank >= kBaseTypeConversionRank_Int8) + { + return kConversionCost_IntegerToHalfConversion; + } // All other cases are considered as "general" conversions, // where we don't consider any one conversion better than // any others. diff --git a/source/slang/slang.natvis b/source/slang/slang.natvis index b1b52bc5c..c86faa065 100644 --- a/source/slang/slang.natvis +++ b/source/slang/slang.natvis @@ -439,7 +439,6 @@ (Slang::ResourceType*)&astNodeType (Slang::TextureTypeBase*)&astNodeType (Slang::TextureType*)&astNodeType - (Slang::TextureSamplerType*)&astNodeType (Slang::GLSLImageType*)&astNodeType (Slang::SamplerStateType*)&astNodeType (Slang::BuiltinGenericType*)&astNodeType @@ -504,6 +503,13 @@ (Slang::Type*)this,! + + DirectDeclRef{(Decl*)m_operands.m_buffer[0].values.nodeOperand} + + (Decl*)m_operands.m_buffer[0].values.nodeOperand + + + SubstitutionSet{declRef,en} @@ -581,7 +587,6 @@ {*(Slang::ResourceType*)this} {*(Slang::TextureTypeBase*)this} {*(Slang::TextureType*)this} - {*(Slang::TextureSamplerType*)this} {*(Slang::GLSLImageType*)this} {*(Slang::SamplerStateType*)this} {*(Slang::BuiltinGenericType*)this} @@ -666,7 +671,6 @@ (Slang::ResourceType*)&astNodeType (Slang::TextureTypeBase*)&astNodeType (Slang::TextureType*)&astNodeType - (Slang::TextureSamplerType*)&astNodeType (Slang::GLSLImageType*)&astNodeType (Slang::SamplerStateType*)&astNodeType (Slang::BuiltinGenericType*)&astNodeType -- cgit v1.2.3