mirror of
https://github.com/dolthub/dolt.git
synced 2026-05-03 19:41:24 -05:00
Remove to unresolved type (#3366)
This commit is contained in:
@@ -20,26 +20,26 @@ import "github.com/attic-labs/noms/go/d"
|
||||
// - else return true
|
||||
func ContainCommonSupertype(a, b *Type) bool {
|
||||
// Avoid cycles internally.
|
||||
return containCommonSupertypeImpl(ToUnresolvedType(a), ToUnresolvedType(b))
|
||||
return containCommonSupertypeImpl(a, b, nil, nil)
|
||||
}
|
||||
|
||||
func containCommonSupertypeImpl(a, b *Type) bool {
|
||||
func containCommonSupertypeImpl(a, b *Type, aVisited, bVisited []*Type) bool {
|
||||
if a.TargetKind() == ValueKind || b.TargetKind() == ValueKind {
|
||||
return true
|
||||
}
|
||||
if a.TargetKind() == UnionKind || b.TargetKind() == UnionKind {
|
||||
return unionsIntersect(a, b)
|
||||
return unionsIntersect(a, b, aVisited, bVisited)
|
||||
}
|
||||
if a.TargetKind() != b.TargetKind() {
|
||||
return false
|
||||
}
|
||||
switch k := a.TargetKind(); k {
|
||||
case StructKind:
|
||||
return structsIntersect(a, b)
|
||||
return structsIntersect(a, b, aVisited, bVisited)
|
||||
case ListKind, SetKind, RefKind:
|
||||
return containersIntersect(k, a, b)
|
||||
return containersIntersect(k, a, b, aVisited, bVisited)
|
||||
case MapKind:
|
||||
return mapsIntersect(a, b)
|
||||
return mapsIntersect(a, b, aVisited, bVisited)
|
||||
default:
|
||||
return true
|
||||
}
|
||||
@@ -48,11 +48,11 @@ func containCommonSupertypeImpl(a, b *Type) bool {
|
||||
|
||||
// Checks for intersection between types that may be unions. If either or
|
||||
// both is a union, union, tests all types for intersection.
|
||||
func unionsIntersect(a, b *Type) bool {
|
||||
func unionsIntersect(a, b *Type, aVisited, bVisited []*Type) bool {
|
||||
aTypes, bTypes := typeList(a), typeList(b)
|
||||
for _, t := range aTypes {
|
||||
for _, u := range bTypes {
|
||||
if containCommonSupertypeImpl(t, u) {
|
||||
if containCommonSupertypeImpl(t, u, aVisited, bVisited) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -68,12 +68,12 @@ func typeList(t *Type) typeSlice {
|
||||
return typeSlice{t}
|
||||
}
|
||||
|
||||
func containersIntersect(kind NomsKind, a, b *Type) bool {
|
||||
func containersIntersect(kind NomsKind, a, b *Type, aVisited, bVisited []*Type) bool {
|
||||
d.Chk.True(kind == a.Desc.Kind() && kind == b.Desc.Kind())
|
||||
return containCommonSupertypeImpl(a.Desc.(CompoundDesc).ElemTypes[0], b.Desc.(CompoundDesc).ElemTypes[0])
|
||||
return containCommonSupertypeImpl(a.Desc.(CompoundDesc).ElemTypes[0], b.Desc.(CompoundDesc).ElemTypes[0], aVisited, bVisited)
|
||||
}
|
||||
|
||||
func mapsIntersect(a, b *Type) bool {
|
||||
func mapsIntersect(a, b *Type, aVisited, bVisited []*Type) bool {
|
||||
// true if a and b are the same or (if either is a union) there is
|
||||
// common type between them.
|
||||
hasCommonType := func(a, b *Type) bool {
|
||||
@@ -94,10 +94,17 @@ func mapsIntersect(a, b *Type) bool {
|
||||
if !hasCommonType(aDesc.ElemTypes[0], bDesc.ElemTypes[0]) {
|
||||
return false
|
||||
}
|
||||
return containCommonSupertypeImpl(aDesc.ElemTypes[1], bDesc.ElemTypes[1])
|
||||
return containCommonSupertypeImpl(aDesc.ElemTypes[1], bDesc.ElemTypes[1], aVisited, bVisited)
|
||||
}
|
||||
|
||||
func structsIntersect(a, b *Type) bool {
|
||||
func structsIntersect(a, b *Type, aVisited, bVisited []*Type) bool {
|
||||
_, aFound := indexOfType(a, aVisited)
|
||||
_, bFound := indexOfType(b, bVisited)
|
||||
|
||||
if aFound && bFound {
|
||||
return true
|
||||
}
|
||||
|
||||
d.Chk.True(StructKind == a.TargetKind() && StructKind == b.TargetKind())
|
||||
aDesc := a.Desc.(StructDesc)
|
||||
bDesc := b.Desc.(StructDesc)
|
||||
@@ -111,7 +118,7 @@ func structsIntersect(a, b *Type) bool {
|
||||
i++
|
||||
} else if bName < aName {
|
||||
j++
|
||||
} else if !containCommonSupertypeImpl(aDesc.fields[i].Type, bDesc.fields[j].Type) {
|
||||
} else if !containCommonSupertypeImpl(aDesc.fields[i].Type, bDesc.fields[j].Type, append(aVisited, a), append(bVisited, b)) {
|
||||
i++
|
||||
j++
|
||||
} else {
|
||||
|
||||
@@ -148,6 +148,23 @@ func TestContainCommonSupertype(t *testing.T) {
|
||||
MakeStructType("", StructField{"b", BoolType, true}),
|
||||
false,
|
||||
},
|
||||
|
||||
// struct A {b: struct {a: Cycle<A>}} & struct {b: Struct A {b: struct {b: Cycle<A>}}} -> false
|
||||
{
|
||||
MakeStructType("A",
|
||||
StructField{"a", MakeStructType("",
|
||||
StructField{"a", MakeCycleType("A"), false},
|
||||
), false},
|
||||
),
|
||||
MakeStructType("",
|
||||
StructField{"a", MakeStructType("A",
|
||||
StructField{"a", MakeStructType("",
|
||||
StructField{"a", MakeCycleType("A"), false},
|
||||
), false},
|
||||
), false},
|
||||
),
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
|
||||
@@ -44,63 +44,6 @@ func indexOfType(t *Type, tl []*Type) (uint32, bool) {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// Returns a new type where cyclic pointer references are replaced with Cycle<Name> types.
|
||||
func toUnresolvedType(t *Type, seenStructs map[string]*Type) (*Type, bool) {
|
||||
switch desc := t.Desc.(type) {
|
||||
case CompoundDesc:
|
||||
ts := make(typeSlice, len(desc.ElemTypes))
|
||||
didChange := false
|
||||
for i, et := range desc.ElemTypes {
|
||||
st, changed := toUnresolvedType(et, seenStructs)
|
||||
ts[i] = st
|
||||
didChange = didChange || changed
|
||||
}
|
||||
|
||||
if !didChange {
|
||||
return t, false
|
||||
}
|
||||
|
||||
return newType(CompoundDesc{t.TargetKind(), ts}), true
|
||||
case StructDesc:
|
||||
name := desc.Name
|
||||
if name != "" {
|
||||
if _, ok := seenStructs[name]; ok {
|
||||
return newType(CycleDesc(name)), true
|
||||
}
|
||||
}
|
||||
|
||||
nt := newType(StructDesc{Name: name})
|
||||
if name != "" {
|
||||
seenStructs[name] = nt
|
||||
}
|
||||
|
||||
fs := make(structTypeFields, len(desc.fields))
|
||||
didChange := false
|
||||
for i, f := range desc.fields {
|
||||
st, changed := toUnresolvedType(f.Type, seenStructs)
|
||||
fs[i] = StructField{f.Name, st, f.Optional}
|
||||
didChange = didChange || changed
|
||||
}
|
||||
|
||||
desc.fields = fs
|
||||
nt.Desc = desc
|
||||
return nt, true
|
||||
case CycleDesc:
|
||||
cycleName := string(desc)
|
||||
d.PanicIfTrue(cycleName == "")
|
||||
_, ok := seenStructs[cycleName]
|
||||
return t, ok // Only cycles which can be resolved in the current struct.
|
||||
}
|
||||
|
||||
return t, false
|
||||
}
|
||||
|
||||
// ToUnresolvedType replaces cycles (by pointer comparison) in types to Cycle types.
|
||||
func ToUnresolvedType(t *Type) *Type {
|
||||
t2, _ := toUnresolvedType(t, map[string]*Type{})
|
||||
return t2
|
||||
}
|
||||
|
||||
func validateType(t *Type) {
|
||||
validateTypeImpl(t, map[string]struct{}{})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user