diff options
author | udovichenko-r <rvu@ydb.tech> | 2022-12-01 22:49:47 +0300 |
---|---|---|
committer | udovichenko-r <rvu@ydb.tech> | 2022-12-01 22:49:47 +0300 |
commit | 4dafd91976dfadc522dc2edee34eeb89e185cac7 (patch) | |
tree | bcca0a1b684b81b7faec9b614433c82150e602b0 | |
parent | 2b0b4db1eacf74f69bad89a8e15c141a9ff37ad0 (diff) | |
download | ydb-4dafd91976dfadc522dc2edee34eeb89e185cac7.tar.gz |
[yql] Improve type differ. Use it in case of incompatible Apply types
-rw-r--r-- | ydb/library/yql/core/type_ann/type_ann_core.cpp | 2 | ||||
-rw-r--r-- | ydb/library/yql/core/yql_expr_type_annotation.cpp | 176 | ||||
-rw-r--r-- | ydb/library/yql/core/yql_expr_type_annotation.h | 1 |
3 files changed, 147 insertions, 32 deletions
diff --git a/ydb/library/yql/core/type_ann/type_ann_core.cpp b/ydb/library/yql/core/type_ann/type_ann_core.cpp index 8c2268c03bf..39e54e39e7b 100644 --- a/ydb/library/yql/core/type_ann/type_ann_core.cpp +++ b/ydb/library/yql/core/type_ann/type_ann_core.cpp @@ -7380,7 +7380,7 @@ template <NKikimr::NUdf::EDataSlot DataSlot> } else { ctx.Expr.AddError(TIssue(ctx.Expr.GetPosition(input->Child(i)->Pos()), TStringBuilder() << "Mismatch type argument #" << i - << ", source type: " << *srcType << ", target type: " << *arg.Type)); + << ", type diff: " << GetTypeDiff(*arg.Type, *srcType))); } return IGraphTransformer::TStatus::Error; } diff --git a/ydb/library/yql/core/yql_expr_type_annotation.cpp b/ydb/library/yql/core/yql_expr_type_annotation.cpp index a67593c9c23..cbef00b8e09 100644 --- a/ydb/library/yql/core/yql_expr_type_annotation.cpp +++ b/ydb/library/yql/core/yql_expr_type_annotation.cpp @@ -3,6 +3,7 @@ #include "yql_opt_rewrite_io.h" #include "yql_opt_utils.h" #include "yql_expr_optimize.h" +#include "yql_type_helpers.h" #include <ydb/library/yql/public/udf/udf_data_type.h> #include <ydb/library/yql/minikql/dom/json.h> @@ -4752,64 +4753,177 @@ bool IsEmptyList(const TTypeAnnotationNode& type) { return type.GetKind() == ETypeAnnotationKind::EmptyList; } -static TString GetStructDiff(const TStructExprType& left, const TStructExprType& right) { +namespace { + +using TIndentPrinter = std::function<void(TStringBuilder& res, size_t)>; +void PrintTypeDiff(TStringBuilder& res, size_t level, const TIndentPrinter& indent, const TTypeAnnotationNode& left, const TTypeAnnotationNode& right); + +void PrintStructDiff(TStringBuilder& res, size_t level, const TIndentPrinter& indent, const TStructExprType& left, const TStructExprType& right) { THashMap<TStringBuf, const TItemExprType*> rightItems; for (auto item: right.GetItems()) { rightItems.insert({item->GetName(), item}); } - TStringBuilder res; + bool diff = false; for (auto item: left.GetItems()) { if (auto rightItem = rightItems.Value(item->GetName(), nullptr)) { if (!IsSameAnnotation(*item, *rightItem)) { - res << item->GetName() << '(' << GetTypeDiff(*item->GetItemType(), *rightItem->GetItemType()) << TStringBuf("),"); + indent(res, level); + res << item->GetName() << ':'; + PrintTypeDiff(res, level, indent, *item->GetItemType(), *rightItem->GetItemType()); + res << ','; + diff = true; } rightItems.erase(item->GetName()); } else { - res << '-' << item->GetName() << '(' << *item->GetItemType() << TStringBuf("),"); + diff = true; + indent(res, level); + res << '-' << item->GetName() << ':' << *item->GetItemType() << ','; } } for (auto& item: rightItems) { - res << '+' << item.first << '(' << *item.second->GetItemType() << TStringBuf("),"); + diff = true; + indent(res, level); + res << '+' << item.first << ':' << *item.second->GetItemType() << ','; } - if (!res.empty()) { - return res.pop_back(); // remove trailing comma + if (diff) { + res.pop_back(); // remove trailing comma + } else { + indent(res, level); + res << "no diff"; } - return "no diff"; } -TString GetTypeDiff(const TTypeAnnotationNode& left, const TTypeAnnotationNode& right) { +void PrintTupleDiff(TStringBuilder& res, size_t level, const TIndentPrinter& indent, const TTupleExprType& left, const TTupleExprType& right) { + const size_t minSize = Min(left.GetSize(), right.GetSize()); + bool diff = false; + for (size_t i = 0; i < minSize; ++i) { + if (!IsSameAnnotation(*left.GetItems()[i], *right.GetItems()[i])) { + indent(res, level); + res << i << ':'; + PrintTypeDiff(res, level, indent, *left.GetItems()[i], *right.GetItems()[i]); + res << ','; + diff = true; + } + } + if (left.GetSize() > minSize) { + for (size_t i = minSize; i < left.GetSize(); ++i) { + indent(res, level); + res << '-' << *left.GetItems()[i] << ','; + } + diff = true; + } + if (right.GetSize() > minSize) { + for (size_t i = minSize; i < right.GetSize(); ++i) { + indent(res, level); + res << '+' << *right.GetItems()[i] << ','; + } + diff = true; + } + if (diff) { + res.pop_back(); + } else { + indent(res, level); + res << "no diff"; + } +} + +static void PrintTypeDiff(TStringBuilder& res, size_t level, const TIndentPrinter& indent, const TTypeAnnotationNode& left, const TTypeAnnotationNode& right) { if (&left == &right) { - return "no diff"; + res << "no diff"; + return; } - TStringBuilder res; if (left.GetKind() == right.GetKind()) { switch (left.GetKind()) { case ETypeAnnotationKind::List: - res << TStringBuf("List<") - << GetTypeDiff(*left.Cast<TListExprType>()->GetItemType(), *right.Cast<TListExprType>()->GetItemType()) - << '>'; - return res; + case ETypeAnnotationKind::Optional: case ETypeAnnotationKind::Stream: - res << TStringBuf("Stream<") - << GetTypeDiff(*left.Cast<TStreamExprType>()->GetItemType(), *right.Cast<TStreamExprType>()->GetItemType()) - << '>'; - return res; - case ETypeAnnotationKind::Struct: - res << TStringBuf("Struct<") - << GetStructDiff(*left.Cast<TStructExprType>(), *right.Cast<TStructExprType>()) - << '>'; - return res; case ETypeAnnotationKind::Flow: - res << TStringBuf("Flow<") - << GetTypeDiff(*left.Cast<TFlowExprType>()->GetItemType(), *right.Cast<TFlowExprType>()->GetItemType()) - << '>'; - return res; + res << left.GetKind() << '<'; + indent(res, level + 1); + PrintTypeDiff(res, level + 1, indent, *GetItemType(left), *GetItemType(right)); + indent(res, level); + res << '>'; + break; + case ETypeAnnotationKind::Struct: + res << left.GetKind() << '<'; + PrintStructDiff(res, level + 1, indent, *left.Cast<TStructExprType>(), *right.Cast<TStructExprType>()); + indent(res, level); + res << '>'; + break; + case ETypeAnnotationKind::Variant: + res << left.GetKind() << '<'; + if (left.Cast<TVariantExprType>()->GetUnderlyingType()->GetKind() == right.Cast<TVariantExprType>()->GetUnderlyingType()->GetKind()) { + if (left.Cast<TVariantExprType>()->GetUnderlyingType()->GetKind() == ETypeAnnotationKind::Struct) { + PrintStructDiff(res, level + 1, indent, *left.Cast<TVariantExprType>()->GetUnderlyingType()->Cast<TStructExprType>(), *right.Cast<TVariantExprType>()->GetUnderlyingType()->Cast<TStructExprType>()); + } else { + YQL_ENSURE(left.Cast<TVariantExprType>()->GetUnderlyingType()->GetKind() == ETypeAnnotationKind::Tuple); + PrintTupleDiff(res, level + 1, indent, *left.Cast<TVariantExprType>()->GetUnderlyingType()->Cast<TTupleExprType>(), *right.Cast<TVariantExprType>()->GetUnderlyingType()->Cast<TTupleExprType>()); + } + } else { + res << left.Cast<TVariantExprType>()->GetUnderlyingType()->GetKind() << "!=" << right.Cast<TVariantExprType>()->GetUnderlyingType()->GetKind(); + } + indent(res, level); + res << '>'; + break; + case ETypeAnnotationKind::Tagged: + res << left.GetKind() << "<\"" << left.Cast<TTaggedExprType>()->GetTag() << '"'; + if (left.Cast<TTaggedExprType>()->GetTag() != right.Cast<TTaggedExprType>()->GetTag()) { + res << "!=\"" << right.Cast<TTaggedExprType>()->GetTag() << '"'; + } + res << ','; + PrintTypeDiff(res, level + 1, indent, *left.Cast<TTaggedExprType>()->GetBaseType(), *right.Cast<TTaggedExprType>()->GetBaseType()); + indent(res, level); + res << '>'; + break; + case ETypeAnnotationKind::Dict: { + res << left.GetKind() << '<'; + bool keyDiff = false; + if (!IsSameAnnotation(*left.Cast<TDictExprType>()->GetKeyType(), *right.Cast<TDictExprType>()->GetKeyType())) { + res << "key:"; + PrintTypeDiff(res, level + 1, indent, *left.Cast<TDictExprType>()->GetKeyType(), *right.Cast<TDictExprType>()->GetKeyType()); + keyDiff = true; + } + if (!IsSameAnnotation(*left.Cast<TDictExprType>()->GetPayloadType(), *right.Cast<TDictExprType>()->GetPayloadType())) { + if (keyDiff) { + res << ','; + } + res << "payload:"; + PrintTypeDiff(res, level + 1, indent, *left.Cast<TDictExprType>()->GetPayloadType(), *right.Cast<TDictExprType>()->GetPayloadType()); + } + indent(res, level); + res << '>'; + break; + } + case ETypeAnnotationKind::Tuple: + res << left.GetKind() << '<'; + PrintTupleDiff(res, level + 1, indent, *left.Cast<TTupleExprType>(), *right.Cast<TTupleExprType>()); + indent(res, level); + res << '>'; + break; default: - res << left << TStringBuf("!=") << right; - return res; + res << left << "!=" << right; } + } else { + res << left << "!=" << right; } - res << left.GetKind() << TStringBuf("!=") << right.GetKind(); +} + +} + +TString GetTypeDiff(const TTypeAnnotationNode& left, const TTypeAnnotationNode& right) { + TStringBuilder res; + PrintTypeDiff(res, 0, [](TStringBuilder&, size_t) {}, left, right); + return res; +} + +TString GetTypePrettyDiff(const TTypeAnnotationNode& left, const TTypeAnnotationNode& right) { + TStringBuilder res; + PrintTypeDiff(res, 0, [](TStringBuilder& res, size_t level) { + res << '\n'; + for (size_t i = 0; i < level; ++i) { + res << ' '; + } + }, left, right); return res; } diff --git a/ydb/library/yql/core/yql_expr_type_annotation.h b/ydb/library/yql/core/yql_expr_type_annotation.h index 465b490b26d..65409df2277 100644 --- a/ydb/library/yql/core/yql_expr_type_annotation.h +++ b/ydb/library/yql/core/yql_expr_type_annotation.h @@ -277,6 +277,7 @@ bool IsEmptyList(const TTypeAnnotationNode& type); bool IsInstantEqual(const TTypeAnnotationNode& type); TString GetTypeDiff(const TTypeAnnotationNode& left, const TTypeAnnotationNode& right); +TString GetTypePrettyDiff(const TTypeAnnotationNode& left, const TTypeAnnotationNode& right); TExprNode::TPtr ExpandType(TPositionHandle position, const TTypeAnnotationNode& type, TExprContext& ctx); bool IsSystemMember(const TStringBuf& memberName); |