github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/store/types/subtype.go (about)

     1  // Copyright 2019 Dolthub, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  //
    15  // This file incorporates work covered by the following copyright and
    16  // permission notice:
    17  //
    18  // Copyright 2016 Attic Labs, Inc. All rights reserved.
    19  // Licensed under the Apache License, version 2.0:
    20  // http://www.apache.org/licenses/LICENSE-2.0
    21  
    22  package types
    23  
    24  // IsSubtype determines whether concreteType is a subtype of requiredType. For example, `Float` is a subtype of `Float | String`.
    25  func IsSubtype(nbf *NomsBinFormat, requiredType, concreteType *Type) bool {
    26  	isSub, _ := isSubtypeTopLevel(nbf, requiredType, concreteType)
    27  	return isSub
    28  }
    29  
    30  // IsSubtypeDisallowExtraFields is a slightly weird variant of IsSubtype. It returns true IFF IsSubtype(requiredType, concreteType) AND Structs in concreteType CANNOT have field names absent in requiredType
    31  // ISSUE: https://github.com/attic-labs/noms/issues/3446
    32  func IsSubtypeDisallowExtraStructFields(nbf *NomsBinFormat, requiredType, concreteType *Type) bool {
    33  	isSub, hasExtra := isSubtypeDetails(nbf, requiredType, concreteType, false, nil)
    34  	if hasExtra {
    35  		return false
    36  	}
    37  	return isSub
    38  }
    39  
    40  // isSubtypeTopLevel returns two values: IsSub and hasExtra. See IsValueSubtypeOf()
    41  // below for an explanation.
    42  func isSubtypeTopLevel(nbf *NomsBinFormat, requiredType, concreteType *Type) (isSub bool, hasExtra bool) {
    43  	return isSubtypeDetails(nbf, requiredType, concreteType, false, nil)
    44  }
    45  
    46  // IsSubtypeDetails returns two values:
    47  //   isSub - which indicates whether concreteType is a subtype of requiredType.
    48  //   hasExtra - which indicates whether concreteType has additional fields.
    49  // See comment below on isValueSubtypeOfDetails
    50  func isSubtypeDetails(nbf *NomsBinFormat, requiredType, concreteType *Type, hasExtra bool, parentStructTypes []*Type) (bool, bool) {
    51  	if requiredType.Equals(concreteType) {
    52  		return true, hasExtra
    53  	}
    54  
    55  	// If the concrete type is a union, all component types must be compatible.
    56  	if concreteType.TargetKind() == UnionKind {
    57  		for _, t := range concreteType.Desc.(CompoundDesc).ElemTypes {
    58  			isSub, hasMore := isSubtypeDetails(nbf, requiredType, t, hasExtra, parentStructTypes)
    59  			if !isSub {
    60  				return false, hasExtra
    61  			}
    62  			hasExtra = hasExtra || hasMore
    63  		}
    64  		return true, hasExtra
    65  	}
    66  
    67  	// If the required type is a union, at least one of the component types must be compatible.
    68  	if requiredType.TargetKind() == UnionKind {
    69  		for _, t := range requiredType.Desc.(CompoundDesc).ElemTypes {
    70  			isSub, hasMore := isSubtypeDetails(nbf, t, concreteType, hasExtra, parentStructTypes)
    71  			if isSub {
    72  				hasExtra = hasExtra || hasMore
    73  				return true, hasExtra
    74  			}
    75  		}
    76  		return false, hasExtra
    77  	}
    78  
    79  	if requiredType.TargetKind() != concreteType.TargetKind() {
    80  		return requiredType.TargetKind() == ValueKind, hasExtra
    81  	}
    82  
    83  	if desc, ok := requiredType.Desc.(CompoundDesc); ok {
    84  		concreteElemTypes := concreteType.Desc.(CompoundDesc).ElemTypes
    85  		for i, t := range desc.ElemTypes {
    86  			isSub, hasMore := compoundSubtype(nbf, t, concreteElemTypes[i], hasExtra, parentStructTypes)
    87  			if !isSub {
    88  				return false, hasExtra
    89  			}
    90  			hasExtra = hasExtra || hasMore
    91  		}
    92  		return true, hasExtra
    93  	}
    94  
    95  	if requiredType.TargetKind() == StructKind {
    96  		requiredDesc := requiredType.Desc.(StructDesc)
    97  		concreteDesc := concreteType.Desc.(StructDesc)
    98  		if requiredDesc.Name != "" && requiredDesc.Name != concreteDesc.Name {
    99  			return false, hasExtra
   100  		}
   101  
   102  		// We may already be computing the subtype for this type if we have a cycle.
   103  		// In that case we exit the recursive check. We may still find that the type
   104  		// is not a subtype but that will be handled at a higher level in the callstack.
   105  		_, found := indexOfType(requiredType, parentStructTypes)
   106  		if found {
   107  			return true, hasExtra
   108  		}
   109  
   110  		i, j := 0, 0
   111  		for i < requiredDesc.Len() && j < concreteDesc.Len() {
   112  			requiredField := requiredDesc.fields[i]
   113  			concreteField := concreteDesc.fields[j]
   114  			if requiredField.Name == concreteField.Name {
   115  				// Common field name
   116  				if !requiredField.Optional && concreteField.Optional {
   117  					return false, hasExtra
   118  				}
   119  
   120  				isSub, hasMore := isSubtypeDetails(nbf, requiredField.Type, concreteField.Type, hasExtra, append(parentStructTypes, requiredType))
   121  				if !isSub {
   122  					return false, hasExtra
   123  				}
   124  				hasExtra = hasExtra || hasMore
   125  
   126  				i++
   127  				j++
   128  				continue
   129  			}
   130  
   131  			if requiredField.Name < concreteField.Name {
   132  				// Concrete lacks field in required
   133  				if !requiredField.Optional {
   134  					return false, hasExtra
   135  				}
   136  				i++
   137  			} else {
   138  				// Concrete contains extra field
   139  				hasExtra = true
   140  				j++
   141  			}
   142  		}
   143  
   144  		for i < requiredDesc.Len() {
   145  			// Fields in required not in concrete
   146  			if !requiredDesc.fields[i].Optional {
   147  				hasExtra = true
   148  				return false, hasExtra
   149  			}
   150  			i++
   151  		}
   152  
   153  		hasExtra = hasExtra || j < concreteDesc.Len()
   154  		return true, hasExtra
   155  	}
   156  
   157  	panic("unreachable")
   158  }
   159  
   160  // compoundSubtype is called when comparing the element types of two compound types. This is the only case
   161  // where a concrete type may have be a union type.
   162  func compoundSubtype(nbf *NomsBinFormat, requiredType, concreteType *Type, hasExtra bool, parentStructTypes []*Type) (bool, bool) {
   163  	// If the concrete type is a union then all the types in the union must be subtypes of the required typ. This also means that a compound type with an empty union is going to be a subtype of all compounds, List<> is a subtype of List<T> for all T.
   164  	if concreteType.TargetKind() == UnionKind {
   165  		for _, ct := range concreteType.Desc.(CompoundDesc).ElemTypes {
   166  			isSub, hasExtra1 := isSubtypeDetails(nbf, requiredType, ct, hasExtra, parentStructTypes)
   167  			if !isSub {
   168  				return false, hasExtra1
   169  			}
   170  		}
   171  		return true, hasExtra
   172  	}
   173  	return isSubtypeDetails(nbf, requiredType, concreteType, hasExtra, parentStructTypes)
   174  }
   175  
   176  func IsValueSubtypeOf(nbf *NomsBinFormat, v Value, t *Type) (bool, error) {
   177  	isSub, _, err := isValueSubtypeOfDetails(nbf, v, t, false)
   178  
   179  	if err != nil {
   180  		return false, err
   181  	}
   182  
   183  	return isSub, nil
   184  }
   185  
   186  // IsValueSubtypeOfDetails returns two values:
   187  //   isSub - which indicates whether v is a subtype of t.
   188  //   hasExtra - which indicates whether v has additional fields. This field has
   189  //              no meaning if IsSub is false.
   190  //
   191  // For example, given the following data:
   192  //   type1 := struct S {               v := Struct S1 {
   193  //       a Float | string                 a: "hello"
   194  //       b ?int                            b: 2
   195  //   }                                 }
   196  // IsValueSubtypeOfDetails(v, type1) would return isSub == true, and hasExtra == false
   197  //
   198  // And given these types:
   199  //   type2 := struct S {               v := Struct S1 {
   200  //       a Float | string                 a: "hello"
   201  //       b ?int                            b: 2
   202  //   }                                     c: "hello again"
   203  //                                     }
   204  // IsValueSubtypeOfDetails(v, type1) would return isSub == true, and hasExtra == true
   205  func IsValueSubtypeOfDetails(nbf *NomsBinFormat, v Value, t *Type) (bool, bool, error) {
   206  	return isValueSubtypeOfDetails(nbf, v, t, false)
   207  }
   208  
   209  func isValueSubtypeOfDetails(nbf *NomsBinFormat, v Value, t *Type, hasExtra bool) (bool, bool, error) {
   210  	switch t.TargetKind() {
   211  	case ValueKind:
   212  		return true, hasExtra, nil
   213  	case UnionKind:
   214  		var anonStruct *Type
   215  
   216  		for _, et := range t.Desc.(CompoundDesc).ElemTypes {
   217  			// Typically if IsSubtype(v.Type(), A|B|C|...) then exactly one of the
   218  			// element types in the union will be a supertype of v.Type() because
   219  			// of type simplification rules (only one of each kind is allowed in
   220  			// the simplified union except for structs, where one of each unique
   221  			// struct name is allowed).
   222  			//
   223  			// However there is one exception which is that type simplification
   224  			// allows the struct with empty name. So if v.Type() is a struct with a
   225  			// name, then it is possible for *two* elements in the union to match
   226  			// it -- a struct with that same name, and a struct with no name.
   227  			//
   228  			// So if we happen across an element type that is an anonymous struct, we
   229  			// save it for later and only try to use it if we can't find anything
   230  			// better.
   231  			if et.TargetKind() == StructKind && et.Desc.(StructDesc).Name == "" {
   232  				anonStruct = et
   233  				continue
   234  			}
   235  			isSub, hasMore, err := isValueSubtypeOfDetails(nbf, v, et, hasExtra)
   236  
   237  			if err != nil {
   238  				return false, false, err
   239  			}
   240  
   241  			if isSub {
   242  				hasExtra = hasExtra || hasMore
   243  				return isSub, hasExtra, nil
   244  			}
   245  		}
   246  
   247  		if anonStruct != nil {
   248  			isSub, hasMore, err := isValueSubtypeOfDetails(nbf, v, anonStruct, hasExtra)
   249  
   250  			if err != nil {
   251  				return false, false, err
   252  			}
   253  
   254  			if isSub {
   255  				hasExtra = hasExtra || hasMore
   256  				return isSub, hasExtra, nil
   257  			}
   258  		}
   259  
   260  		return false, hasExtra, nil
   261  	case CycleKind:
   262  		panic("unreachable") // CycleKind are ephemeral.
   263  	default:
   264  		if IsPrimitiveKind(t.TargetKind()) {
   265  			return v.Kind() == t.TargetKind(), hasExtra, nil
   266  		}
   267  		if v.Kind() != t.TargetKind() {
   268  			return false, hasExtra, nil
   269  		}
   270  	}
   271  
   272  	switch desc := t.Desc.(type) {
   273  	case StructDesc:
   274  		// If we provide a named struct type we require that the names match.
   275  		s := v.(Struct)
   276  		if desc.Name != "" && desc.Name != s.Name() {
   277  			return false, hasExtra, nil
   278  		}
   279  		missingOptionalFieldCnt := 0
   280  		for _, f := range desc.fields {
   281  			fv, ok, err := s.MaybeGet(f.Name)
   282  
   283  			if err != nil {
   284  				return false, false, err
   285  			}
   286  
   287  			if !ok {
   288  				if f.Optional {
   289  					missingOptionalFieldCnt += 1
   290  				} else {
   291  					return false, hasExtra, nil
   292  				}
   293  			} else {
   294  				isSub, hasMore, err := isValueSubtypeOfDetails(nbf, fv, f.Type, hasExtra)
   295  
   296  				if err != nil {
   297  					return false, false, err
   298  				}
   299  
   300  				if !isSub {
   301  					return false, hasExtra, nil
   302  				}
   303  				hasExtra = hasExtra || hasMore
   304  			}
   305  		}
   306  		if s.Len()+missingOptionalFieldCnt > len(desc.fields) {
   307  			hasExtra = true
   308  		}
   309  		return true, hasExtra, nil
   310  
   311  	case CompoundDesc:
   312  		switch v := v.(type) {
   313  		case Ref:
   314  			// Switching to the type is subtype of type here.
   315  			t, err := v.TargetType()
   316  
   317  			if err != nil {
   318  				return false, false, err
   319  			}
   320  			isSub, hasExtra := isSubtypeTopLevel(nbf, desc.ElemTypes[0], t)
   321  			return isSub, hasExtra, nil
   322  		case Map:
   323  			kt := desc.ElemTypes[0]
   324  			vt := desc.ElemTypes[1]
   325  			if seq, ok := v.orderedSequence.(mapLeafSequence); ok {
   326  				meSl, err := seq.entries()
   327  
   328  				if err != nil {
   329  					return false, false, err
   330  				}
   331  
   332  				for _, entry := range meSl.entries {
   333  					isSub, hasMore, err := isValueSubtypeOfDetails(nbf, entry.key, kt, hasExtra)
   334  
   335  					if err != nil {
   336  						return false, false, err
   337  					}
   338  
   339  					if !isSub {
   340  						return false, hasExtra, nil
   341  					}
   342  
   343  					hasExtra = hasExtra || hasMore
   344  					isSub, hasExtra, err = isValueSubtypeOfDetails(nbf, entry.value, vt, hasExtra)
   345  
   346  					if err != nil {
   347  						return false, false, err
   348  					}
   349  
   350  					if !isSub {
   351  						return false, hasExtra, nil
   352  					}
   353  					hasExtra = hasExtra || hasMore
   354  				}
   355  				return true, hasExtra, nil
   356  			}
   357  			return isMetaSequenceSubtypeOf(nbf, v.orderedSequence.(metaSequence), t, hasExtra)
   358  		case Set:
   359  			et := desc.ElemTypes[0]
   360  			if seq, ok := v.orderedSequence.(setLeafSequence); ok {
   361  				vals, err := seq.values()
   362  
   363  				if err != nil {
   364  					return false, false, err
   365  				}
   366  				for _, v := range vals {
   367  					isSub, hasMore, err := isValueSubtypeOfDetails(nbf, v, et, hasExtra)
   368  
   369  					if err != nil {
   370  						return false, false, err
   371  					}
   372  
   373  					if !isSub {
   374  						return false, hasExtra, nil
   375  					}
   376  					hasExtra = hasExtra || hasMore
   377  				}
   378  				return true, hasExtra, nil
   379  			}
   380  			return isMetaSequenceSubtypeOf(nbf, v.orderedSequence.(metaSequence), t, hasExtra)
   381  		case List:
   382  			et := desc.ElemTypes[0]
   383  			if seq, ok := v.sequence.(listLeafSequence); ok {
   384  				vals, err := seq.values()
   385  
   386  				if err != nil {
   387  					return false, false, err
   388  				}
   389  
   390  				for _, v := range vals {
   391  					isSub, hasMore, err := isValueSubtypeOfDetails(nbf, v, et, hasExtra)
   392  
   393  					if err != nil {
   394  						return false, false, err
   395  					}
   396  
   397  					if !isSub {
   398  						return false, hasExtra, nil
   399  					}
   400  					hasExtra = hasExtra || hasMore
   401  				}
   402  				return true, hasExtra, nil
   403  			}
   404  			return isMetaSequenceSubtypeOf(nbf, v.sequence.(metaSequence), t, hasExtra)
   405  		}
   406  	}
   407  	panic("unreachable")
   408  }
   409  
   410  func isMetaSequenceSubtypeOf(nbf *NomsBinFormat, ms metaSequence, t *Type, hasExtra bool) (bool, bool, error) {
   411  	// TODO: iterRefs
   412  	tups, err := ms.tuples()
   413  
   414  	if err != nil {
   415  		return false, false, err
   416  	}
   417  	for _, mt := range tups {
   418  		ref, err := mt.ref()
   419  
   420  		if err != nil {
   421  			return false, false, err
   422  		}
   423  
   424  		tt, err := ref.TargetType()
   425  
   426  		if err != nil {
   427  			return false, false, err
   428  		}
   429  
   430  		// Each prolly tree is also a List<T> where T needs to be a subtype.
   431  		isSub, hasMore := isSubtypeTopLevel(nbf, t, tt)
   432  		if !isSub {
   433  			return false, hasExtra, nil
   434  		}
   435  		hasExtra = hasExtra || hasMore
   436  	}
   437  	return true, hasExtra, nil
   438  }