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 }