blob: 22defda3eb63daa51e415f5654537eeb7bf5f79f [file] [log] [blame]
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001// Copyright 2018 The CUE Authors
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
15package cue
16
Marcel van Lohuizen6c58f252019-04-24 23:08:16 +020017import (
18 "sort"
19)
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +010020
Marcel van Lohuizen6c58f252019-04-24 23:08:16 +020021// A mergedValues type merges structs without unifying their templates.
22// It evaluates structs in parallel and then creates a new mergedValues
23// for each duplicate arc. The mergedValues do not reappear once there is
24// only a single value per arc.
25//
26// This is used to merge different instances which may have incompatible
27// specializations, but have disjuncts objects that may otherwise be shared
28// in the same namespace.
29type mergedValues struct {
30 baseValue
31 values []value
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +010032}
33
Marcel van Lohuizen6c58f252019-04-24 23:08:16 +020034func (x *mergedValues) evalPartial(ctx *context) evaluated {
35 var structs []*structLit
36 for _, v := range x.values {
37 v = v.evalPartial(ctx)
38 o, ok := v.(*structLit)
39 if !ok {
40 v := x.values[0]
41 for _, w := range x.values[1:] {
42 v = mkBin(ctx, w.Pos(), opUnify, v, w)
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +010043 }
Marcel van Lohuizen6c58f252019-04-24 23:08:16 +020044 return v.evalPartial(ctx)
45 }
46 o = o.expandFields(ctx)
47 structs = append(structs, o)
48 }
49
50 // Pre-expand the arcs so that we can discard the templates.
51 obj := &structLit{
52 baseValue: structs[0].baseValue,
53 }
54 var arcs arcs
55 for _, v := range structs {
56 for i := 0; i < len(v.arcs); i++ {
57 w := v.iterAt(ctx, i)
58 arcs = append(arcs, w)
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +010059 }
60 }
Marcel van Lohuizen6c58f252019-04-24 23:08:16 +020061 obj.arcs = arcs
62 sort.Stable(obj)
63
64 values := []value{}
65 for _, v := range structs {
66 if v.emit != nil {
67 values = append(values, v.emit)
68 }
69 }
70 switch len(values) {
71 case 0:
72 case 1:
73 obj.emit = values[0]
74 default:
75 obj.emit = &mergedValues{values[0].base(), values}
76 }
77
78 // merge arcs
79 k := 0
80 for i := 0; i < len(arcs); k++ {
81 a := arcs[i]
82 // TODO: consider storing the evaluated value. This is a performance
83 // versus having more information tradeoff. It results in the same
84 // value.
85 values := []value{a.v}
86 for i++; i < len(arcs) && a.feature == arcs[i].feature; i++ {
87 values = append(values, arcs[i].v)
88 a.optional = a.optional && arcs[i].optional
89 var err evaluated
90 a.attrs, err = unifyAttrs(ctx, a.v, a.attrs, arcs[i].attrs)
91 if err != nil {
92 return err
93 }
94 }
95 if len(values) == 1 {
96 arcs[k] = a
97 continue
98 }
99 a.cache = nil
100 a.v = &mergedValues{a.v.base(), values}
101 arcs[k] = a
102 }
103 obj.arcs = arcs[:k]
104 return obj
105}
106
107func (x *mergedValues) kind() kind {
108 k := x.values[0].kind()
109 for _, v := range x.values {
110 k = unifyType(k, v.kind())
111 }
112 return k
113}
114
115func (x *mergedValues) rewrite(ctx *context, fn rewriteFunc) value {
116 vs := make([]value, len(x.values))
117 for i, v := range x.values {
118 vs[i] = rewrite(ctx, v, fn)
119 }
120 return &mergedValues{x.baseValue, vs}
121}
122
123func (x *mergedValues) subsumesImpl(ctx *context, v value, mode subsumeMode) bool {
124 return false
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100125}