Unify takes two types and tries to make them equivalent. If they are both basic types without any unification variables, then we compare them directly, and this is equivalent to running the *types.Type Cmp method. This function works by drawing conclusions from the assertion that the two sides are e
(typ1, typ2 *types.Type)
| 46 | // modify the input types, copy them before use if this is an issue. If you only |
| 47 | // want to do a compare, you can safely use UnifyCmp. |
| 48 | func Unify(typ1, typ2 *types.Type) error { |
| 49 | if typ1 == nil || typ2 == nil { |
| 50 | return fmt.Errorf("nil type") |
| 51 | } |
| 52 | |
| 53 | // Both types are real and don't contain any unification variables, so |
| 54 | // we just compare them directly. -- Actually don't, these could contain |
| 55 | // unification variables, so leave that to the recursive call below. |
| 56 | //if typ1.Uni == nil && typ2.Uni == nil { |
| 57 | // return typ1.Cmp(typ2) |
| 58 | //} |
| 59 | |
| 60 | // Here we have one type that is a ?1 type, and the other one *might* be |
| 61 | // a full type or it might even contain a ?2 for example. It could be a |
| 62 | // [?2] or [[?2]] for example. |
| 63 | if typ1.Uni != nil && typ2.Uni == nil { // aka && typ2.Kind != nil |
| 64 | root := typ1.Uni.Find() |
| 65 | |
| 66 | // We don't yet know anything about this unification variable. |
| 67 | if root.Data == nil { |
| 68 | if err := OccursCheck(root, typ2); err != nil { |
| 69 | return err |
| 70 | } |
| 71 | |
| 72 | root.Data = typ2 // learn! |
| 73 | return nil |
| 74 | } |
| 75 | // otherwise, cmp root.Data with typ2 |
| 76 | |
| 77 | return Unify(root.Data, typ2) |
| 78 | } |
| 79 | |
| 80 | // This is the same case as above, except it's the opposite scenario. |
| 81 | if typ1.Uni == nil && typ2.Uni != nil { |
| 82 | root := typ2.Uni.Find() |
| 83 | |
| 84 | // We don't yet know anything about this unification variable. |
| 85 | if root.Data == nil { |
| 86 | if err := OccursCheck(root, typ1); err != nil { |
| 87 | return err |
| 88 | } |
| 89 | |
| 90 | root.Data = typ1 // learn! |
| 91 | return nil |
| 92 | } |
| 93 | // otherwise, cmp root.Data with typ1 |
| 94 | |
| 95 | return Unify(root.Data, typ1) |
| 96 | } |
| 97 | |
| 98 | // Both of these are of the form ?1 and ?2 so we compare them directly. |
| 99 | if typ1.Uni != nil && typ2.Uni != nil { |
| 100 | root1 := typ1.Uni.Find() |
| 101 | root2 := typ2.Uni.Find() |
| 102 | |
| 103 | if root1.Data == nil && root2.Data == nil { |
| 104 | // We don't need a merge function to wrap the Union call |
| 105 | // because in this scenario, both data fields are empty! |