mirror of
https://github.com/dolthub/dolt.git
synced 2026-02-08 18:58:47 -06:00
Commit type: Compute the type for meta too (#2185)
This changes to compute the type for the meta field in a similar way to how we compute the type for the value field. Fixes #2179
This commit is contained in:
@@ -15,30 +15,29 @@ const (
|
||||
MetaField = "meta"
|
||||
)
|
||||
|
||||
var valueCommitType = makeCommitType(types.ValueType)
|
||||
var valueCommitType = makeCommitType(types.ValueType, nil, types.EmptyStructType, nil)
|
||||
|
||||
// NewCommit creates a new commit object. The type of Commit is computed based on the type of the value and the type of the parents.
|
||||
// It also includes a Meta field whose type is always the empty struct
|
||||
// NewCommit creates a new commit object. The type of Commit is computed based on the type of the value, the type of the meta info as well as the type of the parents.
|
||||
//
|
||||
// For the first commit we get:
|
||||
//
|
||||
// ```
|
||||
// struct Commit {
|
||||
// meta: struct {},
|
||||
// meta: M,
|
||||
// parents: Set<Ref<Cycle<0>>>,
|
||||
// value: T,
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// As long as we continue to commit values with type T that type stays the same.
|
||||
// As long as we continue to commit values with type T and meta of type M that type stays the same.
|
||||
//
|
||||
// When we later commits a value of type U we get:
|
||||
// When we later do a commit with value of type U and meta of type N we get:
|
||||
//
|
||||
// ```
|
||||
// struct Commit {
|
||||
// meta: struct {},
|
||||
// meta: N,
|
||||
// parents: Set<Ref<struct Commit {
|
||||
// meta: struct {},
|
||||
// meta: M | N,
|
||||
// parents: Set<Ref<Cycle<0>>>,
|
||||
// value: T | U
|
||||
// }>>,
|
||||
@@ -46,32 +45,39 @@ var valueCommitType = makeCommitType(types.ValueType)
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// The new type gets combined as a union type for the value of the inner commit struct.
|
||||
|
||||
// Similarly if we do a commit with a different type for the meta info.
|
||||
//
|
||||
// The new type gets combined as a union type for the value/meta of the inner commit struct.
|
||||
func NewCommit(value types.Value, parents types.Set, meta types.Struct) types.Struct {
|
||||
t := makeCommitType(value.Type(), valueTypesFromParents(parents)...)
|
||||
t := makeCommitType(value.Type(), valueTypesFromParents(parents, ValueField), meta.Type(), valueTypesFromParents(parents, MetaField))
|
||||
return types.NewStructWithType(t, types.ValueSlice{meta, parents, value})
|
||||
}
|
||||
|
||||
func makeCommitType(valueType *types.Type, parentsValueTypes ...*types.Type) *types.Type {
|
||||
tmp := make([]*types.Type, len(parentsValueTypes)+1)
|
||||
func makeCommitType(valueType *types.Type, parentsValueTypes []*types.Type, metaType *types.Type, parentsMetaTypes []*types.Type) *types.Type {
|
||||
tmp := make([]*types.Type, len(parentsValueTypes), len(parentsValueTypes)+1)
|
||||
copy(tmp, parentsValueTypes)
|
||||
tmp[len(tmp)-1] = valueType
|
||||
tmp = append(tmp, valueType)
|
||||
parentsValueUnionType := types.MakeUnionType(tmp...)
|
||||
|
||||
tmp2 := make([]*types.Type, len(parentsMetaTypes), len(parentsMetaTypes)+1)
|
||||
copy(tmp2, parentsMetaTypes)
|
||||
tmp2 = append(tmp2, metaType)
|
||||
parentsMetaUnionType := types.MakeUnionType(tmp2...)
|
||||
|
||||
fieldNames := []string{MetaField, ParentsField, ValueField}
|
||||
var parentsType *types.Type
|
||||
if parentsValueUnionType.Equals(valueType) {
|
||||
if parentsValueUnionType.Equals(valueType) && parentsMetaUnionType.Equals(metaType) {
|
||||
parentsType = types.MakeSetType(types.MakeRefType(types.MakeCycleType(0)))
|
||||
} else {
|
||||
parentsType = types.MakeSetType(types.MakeRefType(
|
||||
types.MakeStructType("Commit", fieldNames, []*types.Type{
|
||||
types.EmptyStructType,
|
||||
parentsMetaUnionType,
|
||||
types.MakeSetType(types.MakeRefType(types.MakeCycleType(0))),
|
||||
parentsValueUnionType,
|
||||
})))
|
||||
}
|
||||
fieldTypes := []*types.Type{
|
||||
types.EmptyStructType,
|
||||
metaType,
|
||||
parentsType,
|
||||
valueType,
|
||||
}
|
||||
@@ -79,17 +85,17 @@ func makeCommitType(valueType *types.Type, parentsValueTypes ...*types.Type) *ty
|
||||
return types.MakeStructType("Commit", fieldNames, fieldTypes)
|
||||
}
|
||||
|
||||
func valueTypesFromParents(parents types.Set) []*types.Type {
|
||||
func valueTypesFromParents(parents types.Set, fieldName string) []*types.Type {
|
||||
elemType := getSetElementType(parents.Type())
|
||||
switch elemType.Kind() {
|
||||
case types.UnionKind:
|
||||
ts := []*types.Type{}
|
||||
for _, rt := range elemType.Desc.(types.CompoundDesc).ElemTypes {
|
||||
ts = append(ts, valueFromRefOfCommit(rt))
|
||||
ts = append(ts, fieldTypeFromRefOfCommit(rt, fieldName))
|
||||
}
|
||||
return ts
|
||||
default:
|
||||
return []*types.Type{valueFromRefOfCommit(elemType)}
|
||||
return []*types.Type{fieldTypeFromRefOfCommit(elemType, fieldName)}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,8 +104,8 @@ func getSetElementType(t *types.Type) *types.Type {
|
||||
return t.Desc.(types.CompoundDesc).ElemTypes[0]
|
||||
}
|
||||
|
||||
func valueFromRefOfCommit(t *types.Type) *types.Type {
|
||||
return valueTypeFromCommit(getRefElementType(t))
|
||||
func fieldTypeFromRefOfCommit(t *types.Type, fieldName string) *types.Type {
|
||||
return fieldTypeFromCommit(getRefElementType(t), fieldName)
|
||||
}
|
||||
|
||||
func getRefElementType(t *types.Type) *types.Type {
|
||||
@@ -107,9 +113,9 @@ func getRefElementType(t *types.Type) *types.Type {
|
||||
return t.Desc.(types.CompoundDesc).ElemTypes[0]
|
||||
}
|
||||
|
||||
func valueTypeFromCommit(t *types.Type) *types.Type {
|
||||
func fieldTypeFromCommit(t *types.Type, fieldName string) *types.Type {
|
||||
d.Chk.True(t.Kind() == types.StructKind && t.Desc.(types.StructDesc).Name == "Commit")
|
||||
return t.Desc.(types.StructDesc).Field(ValueField)
|
||||
return t.Desc.(types.StructDesc).Field(fieldName)
|
||||
}
|
||||
|
||||
func IsCommitType(t *types.Type) bool {
|
||||
|
||||
@@ -51,12 +51,14 @@ func TestNewCommit(t *testing.T) {
|
||||
|
||||
// Now commit a String with MetaInfo
|
||||
meta := types.NewStruct("Meta", map[string]types.Value{"date": types.String("some date"), "number": types.Number(9)})
|
||||
metaType := types.MakeStructType("Meta", []string{"date", "number"}, []*types.Type{types.StringType, types.NumberType})
|
||||
assertTypeEquals(metaType, meta.Type())
|
||||
commit4 := NewCommit(types.String("Hi"), types.NewSet(types.NewRef(commit2)), meta)
|
||||
at4 := commit4.Type()
|
||||
et4 := types.MakeStructType("Commit", commitFieldNames, []*types.Type{
|
||||
types.EmptyStructType,
|
||||
metaType,
|
||||
types.MakeSetType(types.MakeRefType(types.MakeStructType("Commit", commitFieldNames, []*types.Type{
|
||||
types.EmptyStructType,
|
||||
types.MakeUnionType(types.EmptyStructType, metaType),
|
||||
types.MakeSetType(types.MakeRefType(types.MakeCycleType(0))),
|
||||
types.MakeUnionType(types.NumberType, types.StringType),
|
||||
}))),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@attic/noms",
|
||||
"license": "Apache-2.0",
|
||||
"version": "55.0.0",
|
||||
"version": "55.0.1",
|
||||
"description": "Noms JS SDK",
|
||||
"repository": "https://github.com/attic-labs/noms",
|
||||
"main": "dist/commonjs/noms.js",
|
||||
|
||||
@@ -61,12 +61,13 @@ suite('commit.js', () => {
|
||||
|
||||
// Now commit a String with MetaInfo
|
||||
const meta = newStruct('Meta', {date: 'some date', number: 9});
|
||||
const metaType = makeStructType('Meta', ['date', 'number'], [stringType, numberType]);
|
||||
const commit4 = new Commit('Hi', new Set([new Ref(commit2)]), meta);
|
||||
const at4 = commit4.type;
|
||||
const et4 = makeStructType('Commit', commitFieldNames, [
|
||||
emptyStructType,
|
||||
metaType,
|
||||
makeSetType(makeRefType(makeStructType('Commit', commitFieldNames, [
|
||||
emptyStructType,
|
||||
makeUnionType([emptyStructType, metaType]),
|
||||
makeSetType(makeRefType(makeCycleType(0))),
|
||||
makeUnionType([numberType, stringType]),
|
||||
]))),
|
||||
|
||||
@@ -33,7 +33,8 @@ const valueIndex = 2;
|
||||
|
||||
export default class Commit<T: Value> extends Struct {
|
||||
constructor(value: T, parents: Set<Ref<Commit>> = new Set(), meta: Struct = getEmptyStruct()) {
|
||||
const t = makeCommitType(getTypeOfValue(value), valueTypesFromParents(parents));
|
||||
const t = makeCommitType(getTypeOfValue(value), valueTypesFromParents(parents, 'value'),
|
||||
getTypeOfValue(meta), valueTypesFromParents(parents, 'meta'));
|
||||
super(t, [meta, parents, value]);
|
||||
}
|
||||
|
||||
@@ -73,34 +74,36 @@ export default class Commit<T: Value> extends Struct {
|
||||
}
|
||||
}
|
||||
|
||||
function makeCommitType(valueType: Type<*>, parentsValueTypes: Type<*>[]): Type<StructDesc> {
|
||||
// ../../go/datas/commit.go for the motivation for how this is computed.
|
||||
function makeCommitType(valueType: Type<*>, parentsValueTypes: Type<*>[],
|
||||
metaType: Type<*>, parentsMetaTypes: Type<*>[]): Type<StructDesc> {
|
||||
const fieldNames = ['meta', 'parents', 'value'];
|
||||
const tmp = parentsValueTypes.concat(valueType);
|
||||
const parentsValueUnionType = makeUnionType(tmp);
|
||||
const parentsValueUnionType = makeUnionType(parentsValueTypes.concat(valueType));
|
||||
const parentsMetaUnionType = makeUnionType(parentsMetaTypes.concat(metaType));
|
||||
let parentsType;
|
||||
if (equals(parentsValueUnionType, valueType)) {
|
||||
if (equals(parentsValueUnionType, valueType) && equals(parentsMetaUnionType, metaType)) {
|
||||
parentsType = makeSetType(makeRefType(makeCycleType(0)));
|
||||
} else {
|
||||
parentsType = makeSetType(makeRefType(makeStructType('Commit', fieldNames, [
|
||||
getEmptyStruct().type,
|
||||
parentsMetaUnionType,
|
||||
makeSetType(makeRefType(makeCycleType(0))),
|
||||
parentsValueUnionType,
|
||||
])));
|
||||
}
|
||||
return makeStructType('Commit', fieldNames, [
|
||||
getEmptyStruct().type,
|
||||
metaType,
|
||||
parentsType,
|
||||
valueType,
|
||||
]);
|
||||
}
|
||||
|
||||
function valueTypesFromParents(parents: Set): Type<*>[] {
|
||||
function valueTypesFromParents(parents: Set, fieldName: string): Type<*>[] {
|
||||
const elemType = getSetElementType(parents.type);
|
||||
switch (elemType.kind) {
|
||||
case Kind.Union:
|
||||
return elemType.desc.elemTypes.map(valueFromRefOfCommit);
|
||||
return elemType.desc.elemTypes.map(t => fieldTypeFromRefOfCommit(t, fieldName));
|
||||
default:
|
||||
return [valueFromRefOfCommit(elemType)];
|
||||
return [fieldTypeFromRefOfCommit(elemType, fieldName)];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,8 +112,8 @@ function getSetElementType(t: Type<CompoundDesc>): Type<*> {
|
||||
return t.desc.elemTypes[0];
|
||||
}
|
||||
|
||||
function valueFromRefOfCommit(t: Type<CompoundDesc>): Type<*> {
|
||||
return valueTypeFromCommit(getRefElementType(t));
|
||||
function fieldTypeFromRefOfCommit(t: Type<CompoundDesc>, fieldName: string): Type<*> {
|
||||
return fieldTypeFromCommit(getRefElementType(t), fieldName);
|
||||
}
|
||||
|
||||
function getRefElementType(t: Type<CompoundDesc>): Type<*> {
|
||||
@@ -118,16 +121,16 @@ function getRefElementType(t: Type<CompoundDesc>): Type<*> {
|
||||
return t.desc.elemTypes[0];
|
||||
}
|
||||
|
||||
function valueTypeFromCommit(t: Type<StructDesc>): Type<*> {
|
||||
function fieldTypeFromCommit(t: Type<StructDesc>, fieldName: string): Type<*> {
|
||||
invariant(t.desc.name === 'Commit');
|
||||
return notNull(t.desc.getField('value'));
|
||||
return notNull(t.desc.getField(fieldName));
|
||||
}
|
||||
|
||||
// Work around npm cyclic dependencies.
|
||||
let valueCommitType;
|
||||
function getValueCommitType() {
|
||||
if (!valueCommitType) {
|
||||
valueCommitType = makeCommitType(valueType, []);
|
||||
valueCommitType = makeCommitType(valueType, [], getEmptyStruct().type, []);
|
||||
}
|
||||
return valueCommitType;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user