cuelang.org/go@v0.13.0/internal/core/adt/conjunct.go (about)

     1  // Copyright 2023 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  
    15  package adt
    16  
    17  import (
    18  	"fmt"
    19  
    20  	"cuelang.org/go/cue/errors"
    21  	"cuelang.org/go/cue/token"
    22  )
    23  
    24  // This file contains functionality for processing conjuncts to insert the
    25  // corresponding values in the Vertex.
    26  //
    27  // Conjuncts are divided into two classes:
    28  // - literal values that need no evaluation: these are inserted directly into
    29  //   the Vertex.
    30  // - field or value expressions that need to be evaluated: these are inserted
    31  //   as a task into the Vertex' associated scheduler for later evaluation.
    32  //   The implementation of these tasks can be found in tasks.go.
    33  //
    34  // The main entrypoint is scheduleConjunct.
    35  
    36  // scheduleConjunct splits c into parts to be incrementally processed and queues
    37  // these parts up for processing. it will itself not cause recursive processing.
    38  func (n *nodeContext) scheduleConjunct(c Conjunct, id CloseInfo) {
    39  	n.assertInitialized()
    40  
    41  	if c.CloseInfo.FromDef {
    42  		n.node.ClosedRecursive = true
    43  	}
    44  
    45  	// TODO: consider setting this as a safety measure.
    46  	// if c.CloseInfo.CycleType > id.CycleType {
    47  	// 	id.CycleType = c.CloseInfo.CycleType
    48  	// }
    49  	// if c.CloseInfo.IsCyclic {
    50  	// 	id.IsCyclic = true
    51  	// }
    52  	// default:
    53  	// Note this subtlety: we MUST take the cycle info from c when this is
    54  	// an in place evaluated node, otherwise we must take that of id.
    55  
    56  	// TODO(evalv3): Why do we no longer need to do this?
    57  	// id.CycleInfo = c.CloseInfo.CycleInfo
    58  
    59  	env := c.Env
    60  
    61  	n.markNonCyclic(id)
    62  
    63  	switch x := c.Elem().(type) {
    64  	case *ConjunctGroup:
    65  		for _, c := range *x {
    66  			n.scheduleConjunct(c, id)
    67  		}
    68  
    69  	case *Vertex:
    70  		// TODO: move this logic to scheduleVertexConjuncts or at least ensure
    71  		// that we can also share data Vertices?
    72  		if x.IsData() {
    73  			n.unshare()
    74  			n.insertValueConjunct(env, x, id)
    75  		} else {
    76  			n.scheduleVertexConjuncts(c, x, id)
    77  		}
    78  
    79  	case Value:
    80  		// TODO: perhaps some values could be shared.
    81  		n.unshare()
    82  		n.insertValueConjunct(env, x, id)
    83  
    84  	case *BinaryExpr:
    85  		// NOTE: do not unshare: a conjunction could still allow structure
    86  		// sharing, such as in the case of `ref & ref`.
    87  		if x.Op == AndOp {
    88  			n.scheduleConjunct(MakeConjunct(env, x.X, id), id)
    89  			n.scheduleConjunct(MakeConjunct(env, x.Y, id), id)
    90  			return
    91  		}
    92  
    93  		n.unshare()
    94  		// Even though disjunctions and conjunctions are excluded, the result
    95  		// must may still be list in the case of list arithmetic. This could
    96  		// be a scalar value only once this is no longer supported.
    97  		n.scheduleTask(handleExpr, env, x, id)
    98  
    99  	case *StructLit:
   100  		n.unshare()
   101  		n.scheduleStruct(env, x, id)
   102  
   103  	case *ListLit:
   104  		n.unshare()
   105  
   106  		// At this point we known we have at least an empty list.
   107  		n.updateCyclicStatusV3(id)
   108  
   109  		env := &Environment{
   110  			Up:     env,
   111  			Vertex: n.node,
   112  		}
   113  		n.updateNodeType(ListKind, x, id)
   114  		n.scheduleTask(handleListLit, env, x, id)
   115  
   116  	case *DisjunctionExpr:
   117  		n.unshare()
   118  		id := id
   119  		id.setOptionalV3(n)
   120  
   121  		// TODO(perf): reuse envDisjunct values so that we can also reuse the
   122  		// disjunct slice.
   123  		n.ctx.holeID++
   124  		d := envDisjunct{
   125  			env:     env,
   126  			cloneID: id,
   127  			holeID:  n.ctx.holeID,
   128  			src:     x,
   129  			expr:    x,
   130  		}
   131  		for _, dv := range x.Values {
   132  			d.disjuncts = append(d.disjuncts, disjunct{
   133  				expr:      dv.Val,
   134  				isDefault: dv.Default,
   135  				mode:      mode(x.HasDefaults, dv.Default),
   136  			})
   137  		}
   138  		n.scheduleDisjunction(d)
   139  		n.updateConjunctInfo(TopKind, id, 0)
   140  
   141  	case *Comprehension:
   142  		// always a partial comprehension.
   143  		n.insertComprehension(env, x, id)
   144  
   145  	case Resolver:
   146  		n.scheduleTask(handleResolver, env, x, id)
   147  
   148  	case Evaluator:
   149  		n.unshare()
   150  
   151  		// Expressions that contain a call may end up in an infinite recursion
   152  		// here if we do not ensure that there is non-cyclic data to propagate
   153  		// the evaluation. We therefore postpone expressions until we have
   154  		// evidence that such non-cyclic conjuncts exist.
   155  		if id.CycleType == IsCyclic && !n.hasNonCycle && !n.hasNonCyclic {
   156  			n.hasAncestorCycle = true
   157  			n.cyclicConjuncts = append(n.cyclicConjuncts, cyclicConjunct{c: c})
   158  			return
   159  		}
   160  
   161  		// Interpolation, UnaryExpr, CallExpr
   162  		n.scheduleTask(handleExpr, env, x, id)
   163  
   164  	default:
   165  		panic("unreachable")
   166  	}
   167  
   168  	n.ctx.stats.Conjuncts++
   169  }
   170  
   171  // scheduleStruct records all elements of this conjunct in the structure and
   172  // then processes it. If an element needs to be inserted for evaluation,
   173  // it may be scheduled.
   174  func (n *nodeContext) scheduleStruct(env *Environment,
   175  	s *StructLit,
   176  	ci CloseInfo) {
   177  	n.updateCyclicStatusV3(ci)
   178  	n.updateConjunctInfo(StructKind, ci, cHasStruct)
   179  
   180  	// NOTE: This is a crucial point in the code:
   181  	// Unification dereferencing happens here. The child nodes are set to
   182  	// an Environment linked to the current node. Together with the De Bruijn
   183  	// indices, this determines to which Vertex a reference resolves.
   184  
   185  	childEnv := &Environment{
   186  		Up:     env,
   187  		Vertex: n.node,
   188  	}
   189  
   190  	hasEmbed := false
   191  	hasEllipsis := false
   192  
   193  	n.hasStruct = true
   194  
   195  	// TODO: do we still need this?
   196  	// shouldClose := ci.cc.isDef || ci.cc.isClosedOnce
   197  
   198  	s.Init(n.ctx)
   199  
   200  	// TODO: do we still need to AddStruct and do we still need to Disable?
   201  	parent := n.node.AddStruct(s, childEnv, ci)
   202  	parent.Disable = true // disable until processing is done.
   203  	ci.IsClosed = false
   204  
   205  	// TODO(perf): precompile whether struct has embedding.
   206  loop1:
   207  	for _, d := range s.Decls {
   208  		switch d.(type) {
   209  		case *Comprehension, Expr:
   210  			hasEmbed = true
   211  			break loop1
   212  		}
   213  	}
   214  
   215  	// TODO: if embed, add an "ignore" field.
   216  	// When inserting a replace that is a definition, flip the ignore.
   217  	if hasEmbed {
   218  		ci = n.splitStruct(s, ci)
   219  	}
   220  
   221  	// First add fixed fields and schedule expressions.
   222  	for _, d := range s.Decls {
   223  		switch x := d.(type) {
   224  		case *Field:
   225  			if x.Label.IsString() && x.ArcType == ArcMember {
   226  				n.aStruct = s
   227  				n.aStructID = ci
   228  			}
   229  			ci := n.ctx.subField(ci)
   230  			if x.ArcType == ArcOptional {
   231  				ci.setOptionalV3(n)
   232  			}
   233  
   234  			fc := MakeConjunct(childEnv, x, ci)
   235  			n.insertArc(x.Label, x.ArcType, fc, ci, true)
   236  
   237  		case *LetField:
   238  			ci := n.ctx.subField(ci)
   239  			lc := MakeConjunct(childEnv, x, ci)
   240  			n.insertArc(x.Label, ArcMember, lc, ci, true)
   241  
   242  		case *Comprehension:
   243  			ci := n.injectEmbedNode(x, ci)
   244  			n.insertComprehension(childEnv, x, ci)
   245  			hasEmbed = true
   246  
   247  		case *Ellipsis:
   248  			// Can be added unconditionally to patterns.
   249  			hasEllipsis = true
   250  
   251  		case *DynamicField:
   252  			ci := n.ctx.subField(ci)
   253  			if x.ArcType == ArcMember {
   254  				n.aStruct = s
   255  				n.aStructID = ci
   256  			}
   257  			n.scheduleTask(handleDynamic, childEnv, x, ci)
   258  
   259  		case *BulkOptionalField:
   260  			ci := n.ctx.subField(ci)
   261  			ci.setOptionalV3(n)
   262  
   263  			// All do not depend on each other, so can be added at once.
   264  			n.scheduleTask(handlePatternConstraint, childEnv, x, ci)
   265  
   266  		case Expr:
   267  			ci := n.injectEmbedNode(x, ci)
   268  			ec := MakeConjunct(childEnv, x, ci)
   269  			n.scheduleConjunct(ec, ci)
   270  			hasEmbed = true
   271  		}
   272  	}
   273  	if hasEllipsis {
   274  		n.node.HasEllipsis = true
   275  		n.updateConjunctInfo(TopKind, ci, cHasEllipsis)
   276  	}
   277  	if !hasEmbed {
   278  		n.aStruct = s
   279  		n.aStructID = ci
   280  	}
   281  
   282  	// TODO: probably no longer necessary.
   283  	parent.Disable = false
   284  }
   285  
   286  // scheduleVertexConjuncts injects the conjuncst of src n. If src was not fully
   287  // evaluated, it subscribes dst for future updates.
   288  func (n *nodeContext) scheduleVertexConjuncts(c Conjunct, arc *Vertex, closeInfo CloseInfo) {
   289  	// We should not "activate" an enclosing struct for typo checking if it is
   290  	// derived from an embedded, inlined value:
   291  	//
   292  	//    #Schema: foo: { {embed: embedded: "foo"}.embed }
   293  	//    #Schema: foo: { field: string }
   294  	//
   295  	// Even though the embedding is within a schema, it should not treat the
   296  	// struct as closed if it itself does not refer to a schema, as it may still
   297  	// be unified with another struct.
   298  	//
   299  	// We check this by checking if the result is not marked as Closed.
   300  	// Alternativley, we could always disable this for inlined structs.
   301  	//
   302  	// TODO(#A...): this code could go if we had explicitly opened values.
   303  	if !arc.ClosedRecursive &&
   304  		!arc.ClosedNonRecursive &&
   305  		closeInfo.enclosingEmbed != 0 {
   306  		closeInfo.FromDef = false
   307  	}
   308  
   309  	// disjunctions, we need to dereference he underlying node.
   310  	if deref(n.node) == deref(arc) {
   311  		if n.isShared {
   312  			n.addShared(closeInfo)
   313  		}
   314  		return
   315  	}
   316  
   317  	if n.shareIfPossible(c, arc, closeInfo) {
   318  		arc.getState(n.ctx)
   319  		return
   320  	}
   321  
   322  	// We need to ensure that each arc is only unified once (or at least) a
   323  	// bounded time, witch each conjunct. Comprehensions, for instance, may
   324  	// distribute a value across many values that get unified back into the
   325  	// same value. If such a value is a disjunction, than a disjunction of N
   326  	// disjuncts will result in a factor N more unifications for each
   327  	// occurrence of such value, resulting in exponential running time. This
   328  	// is especially common values that are used as a type.
   329  	//
   330  	// However, unification is idempotent, so each such conjunct only needs
   331  	// to be unified once. This cache checks for this and prevents an
   332  	// exponential blowup in such case.
   333  	//
   334  	// TODO(perf): this cache ensures the conjuncts of an arc at most once
   335  	// per ID. However, we really need to add the conjuncts of an arc only
   336  	// once total, and then add the close information once per close ID
   337  	// (pointer can probably be shared). Aside from being more performant,
   338  	// this is probably the best way to guarantee that conjunctions are
   339  	// linear in this case.
   340  
   341  	ciKey := closeInfo
   342  	ciKey.Refs = nil
   343  	ciKey.Inline = false
   344  	if n.ctx.isDevVersion() {
   345  		// No need to key on CloseInfo with evalv3.
   346  		ciKey = CloseInfo{}
   347  	}
   348  
   349  	// Also check arc.Label: definitions themselves do not have the FromDef to
   350  	// reflect their closedness. This means that if we are structure sharing, we
   351  	// may end up with a Vertex that is a definition without the reference
   352  	// reflecting that. We need to handle this case here. Note that if an
   353  	// intermediate node refers to a definition, things are evaluated at least
   354  	// once.
   355  	switch isDef, _ := IsDef(c.Expr()); {
   356  	case isDef || arc.Label.IsDef() || closeInfo.TopDef:
   357  		n.isDef = true
   358  		// n.node.ClosedRecursive = true // TODO: should we set this here?
   359  		closeInfo.FromDef = true
   360  		closeInfo.TopDef = false
   361  
   362  		closeInfo = n.addResolver(arc, closeInfo, false)
   363  	default:
   364  		closeInfo = n.addResolver(arc, closeInfo, true)
   365  	}
   366  	c.CloseInfo.defID = closeInfo.defID
   367  	c.CloseInfo.outerID = closeInfo.defID
   368  
   369  	key := arcKey{arc, ciKey}
   370  	for _, k := range n.arcMap {
   371  		if key == k {
   372  			return
   373  		}
   374  	}
   375  	n.arcMap = append(n.arcMap, key)
   376  
   377  	if !n.node.nonRooted || n.node.IsDynamic {
   378  		if state := arc.getBareState(n.ctx); state != nil {
   379  			state.addNotify2(n.node, closeInfo)
   380  		}
   381  	}
   382  
   383  	// Use explicit index in case Conjuncts grows during iteration.
   384  	for i := 0; i < len(arc.Conjuncts); i++ {
   385  		c := arc.Conjuncts[i]
   386  		n.scheduleConjunct(c, closeInfo)
   387  	}
   388  
   389  	if state := arc.getBareState(n.ctx); state != nil {
   390  		n.toComplete = true
   391  	}
   392  }
   393  
   394  func (n *nodeContext) addNotify2(v *Vertex, c CloseInfo) {
   395  	// No need to do the notification mechanism if we are already complete.
   396  	switch {
   397  	case n.node.isFinal():
   398  		return
   399  	case !n.node.isInProgress():
   400  	case n.meets(allAncestorsProcessed):
   401  		return
   402  	}
   403  
   404  	for _, r := range n.notify {
   405  		if r.v == v {
   406  			return
   407  		}
   408  	}
   409  
   410  	// TODO: it should not be necessary to register for notifications for
   411  	// let expressions, so we could also filter for !n.node.Label.IsLet().
   412  	// However, somehow this appears to result in slightly better error
   413  	// messages.
   414  
   415  	n.notify = append(n.notify, receiver{v})
   416  }
   417  
   418  // Literal conjuncts
   419  
   420  // NoSharingSentinel is a sentinel value that is used to disable sharing of
   421  // nodes. We make this an error to make it clear that we discard the value.
   422  var NoShareSentinel = &Bottom{
   423  	Err: errors.Newf(token.NoPos, "no sharing"),
   424  }
   425  
   426  func (n *nodeContext) insertValueConjunct(env *Environment, v Value, id CloseInfo) {
   427  	ctx := n.ctx
   428  
   429  	n.updateConjunctInfo(TopKind, id, 0)
   430  
   431  	switch x := v.(type) {
   432  	case *Vertex:
   433  		if x.ClosedNonRecursive {
   434  			n.node.ClosedNonRecursive = true
   435  
   436  			// If this is a definition, it will be repeated in the evaluation.
   437  			if !x.IsFromDisjunction() {
   438  				id = n.addResolver(x, id, false)
   439  			}
   440  		}
   441  		if _, ok := x.BaseValue.(*StructMarker); ok {
   442  			n.aStruct = x
   443  			n.aStructID = id
   444  		}
   445  
   446  		if !x.IsData() {
   447  			n.updateCyclicStatusV3(id)
   448  
   449  			c := MakeConjunct(env, x, id)
   450  			n.scheduleVertexConjuncts(c, x, id)
   451  			return
   452  		}
   453  
   454  		// TODO: evaluate value?
   455  		switch v := x.BaseValue.(type) {
   456  		default:
   457  			panic(fmt.Sprintf("invalid type %T", x.BaseValue))
   458  
   459  		case *ListMarker:
   460  			n.updateCyclicStatusV3(id)
   461  
   462  			// TODO: arguably we know now that the type _must_ be a list.
   463  			n.scheduleTask(handleListVertex, env, x, id)
   464  
   465  			return
   466  
   467  		case *StructMarker:
   468  			for _, a := range x.Arcs {
   469  				if a.ArcType != ArcMember {
   470  					continue
   471  				}
   472  				// TODO(errors): report error when this is a regular field.
   473  				c := MakeConjunct(nil, a, id)
   474  				n.insertArc(a.Label, a.ArcType, c, id, true)
   475  			}
   476  			n.node.Structs = append(n.node.Structs, x.Structs...)
   477  
   478  		case Value:
   479  			n.insertValueConjunct(env, v, id)
   480  		}
   481  
   482  		return
   483  
   484  	case *Bottom:
   485  		if x == NoShareSentinel {
   486  			n.unshare()
   487  			return
   488  		}
   489  		n.addBottom(x)
   490  		return
   491  
   492  	case *Builtin:
   493  		if v := x.BareValidator(); v != nil {
   494  			n.insertValueConjunct(env, v, id)
   495  			return
   496  		}
   497  	}
   498  
   499  	if !n.updateNodeType(v.Kind(), v, id) {
   500  		return
   501  	}
   502  
   503  	switch x := v.(type) {
   504  	case *Disjunction:
   505  		n.updateCyclicStatusV3(id)
   506  
   507  		// TODO(perf): reuse envDisjunct values so that we can also reuse the
   508  		// disjunct slice.
   509  		id := id
   510  		id.setOptionalV3(n)
   511  
   512  		n.ctx.holeID++
   513  		d := envDisjunct{
   514  			env:     env,
   515  			cloneID: id,
   516  			holeID:  n.ctx.holeID,
   517  			src:     x,
   518  			value:   x,
   519  		}
   520  		for i, dv := range x.Values {
   521  			d.disjuncts = append(d.disjuncts, disjunct{
   522  				expr:      dv,
   523  				isDefault: i < x.NumDefaults,
   524  				mode:      mode(x.HasDefaults, i < x.NumDefaults),
   525  			})
   526  		}
   527  		n.scheduleDisjunction(d)
   528  
   529  	case *Conjunction:
   530  		// TODO: consider sharing: conjunct could be `ref & ref`, for instance,
   531  		// in which case ref could still be shared.
   532  
   533  		for _, x := range x.Values {
   534  			n.insertValueConjunct(env, x, id)
   535  		}
   536  
   537  	case *Top:
   538  		n.updateCyclicStatusV3(id)
   539  
   540  		n.hasTop = true
   541  		n.updateConjunctInfo(TopKind, id, cHasTop)
   542  
   543  	case *BasicType:
   544  		n.updateCyclicStatusV3(id)
   545  		if x.K != TopKind {
   546  			n.updateConjunctInfo(TopKind, id, cHasTop)
   547  		}
   548  
   549  	case *BoundValue:
   550  		n.updateCyclicStatusV3(id)
   551  
   552  		switch x.Op {
   553  		case LessThanOp, LessEqualOp:
   554  			if y := n.upperBound; y != nil {
   555  				v := SimplifyBounds(ctx, n.kind, x, y)
   556  				if err := valueError(v); err != nil {
   557  					err.AddPosition(v)
   558  					err.AddPosition(n.upperBound)
   559  					err.AddClosedPositions(id)
   560  				}
   561  				n.upperBound = nil
   562  				n.insertValueConjunct(env, v, id)
   563  				return
   564  			}
   565  			n.upperBound = x
   566  
   567  		case GreaterThanOp, GreaterEqualOp:
   568  			if y := n.lowerBound; y != nil {
   569  				v := SimplifyBounds(ctx, n.kind, x, y)
   570  				if err := valueError(v); err != nil {
   571  					err.AddPosition(v)
   572  					err.AddPosition(n.lowerBound)
   573  					err.AddClosedPositions(id)
   574  				}
   575  				n.lowerBound = nil
   576  				n.insertValueConjunct(env, v, id)
   577  				return
   578  			}
   579  			n.lowerBound = x
   580  
   581  		case EqualOp, NotEqualOp, MatchOp, NotMatchOp:
   582  			// This check serves as simplifier, but also to remove duplicates.
   583  			k := 0
   584  			match := false
   585  			for _, c := range n.checks {
   586  				if y, ok := c.x.(*BoundValue); ok {
   587  					switch z := SimplifyBounds(ctx, n.kind, x, y); {
   588  					case z == y:
   589  						match = true
   590  					case z == x:
   591  						continue
   592  					}
   593  				}
   594  				n.checks[k] = c
   595  				k++
   596  			}
   597  			n.checks = n.checks[:k]
   598  			// TODO(perf): do an early check to be able to prune further
   599  			// processing.
   600  			if !match {
   601  				n.checks = append(n.checks, MakeConjunct(env, x, id))
   602  			}
   603  			return
   604  		}
   605  
   606  	case Validator:
   607  		// This check serves as simplifier, but also to remove duplicates.
   608  		cx := MakeConjunct(env, x, id)
   609  		kind := x.Kind()
   610  		// A validator that is inserted in a closeContext should behave like top
   611  		// in the sense that the closeContext should not be closed if no other
   612  		// value is present that would erase top (cc.hasNonTop): if a field is
   613  		// only associated with a validator, we leave it to the validator to
   614  		// decide what fields are allowed.
   615  		if kind&(ListKind|StructKind) != 0 {
   616  			if b, ok := x.(*BuiltinValidator); ok && b.Builtin.NonConcrete {
   617  				n.updateConjunctInfo(TopKind, id, cHasOpenValidator|cHasTop)
   618  			} else {
   619  				n.updateConjunctInfo(TopKind, id, cHasTop)
   620  			}
   621  		}
   622  
   623  		for i, y := range n.checks {
   624  			if b, ok := SimplifyValidator(ctx, cx, y); ok {
   625  				// It is possible that simplification process triggered further
   626  				// evaluation, finalizing this node and clearing the checks
   627  				// slice. In that case it is safe to ignore the result.
   628  				if len(n.checks) > 0 {
   629  					n.checks[i] = b
   630  				}
   631  				return
   632  			}
   633  		}
   634  
   635  		n.checks = append(n.checks, cx)
   636  
   637  		// We use set the type of the validator argument here to ensure that
   638  		// validation considers the ultimate value of embedded validators,
   639  		// rather than assuming that the struct in which an expression is
   640  		// embedded is always a struct.
   641  		// TODO(validatorType): get rid of setting n.hasTop here.
   642  		k := x.Kind()
   643  		if k == TopKind {
   644  			n.hasTop = true
   645  			// TODO: should we set this here? Does not seem necessary.
   646  			// n.updateConjunctInfo(TopKind, id, cHasTop)
   647  		}
   648  		n.updateNodeType(k, x, id)
   649  
   650  	case *Vertex:
   651  	// handled above.
   652  
   653  	case Value: // *NullLit, *BoolLit, *NumLit, *StringLit, *BytesLit, *Builtin
   654  		n.updateCyclicStatusV3(id)
   655  
   656  		if y := n.scalar; y != nil {
   657  			if b, ok := BinOp(ctx, EqualOp, x, y).(*Bool); !ok || !b.B {
   658  				n.reportConflict(x, y, x.Kind(), y.Kind(), n.scalarID, id)
   659  			}
   660  			break
   661  		}
   662  		n.scalar = x
   663  		n.scalarID = id
   664  		n.signal(scalarKnown)
   665  
   666  	default:
   667  		panic(fmt.Sprintf("unknown value type %T", x))
   668  	}
   669  
   670  	if n.lowerBound != nil && n.upperBound != nil {
   671  		if u := SimplifyBounds(ctx, n.kind, n.lowerBound, n.upperBound); u != nil {
   672  			if err := valueError(u); err != nil {
   673  				err.AddPosition(n.lowerBound)
   674  				err.AddPosition(n.upperBound)
   675  				err.AddClosedPositions(id)
   676  			}
   677  			n.lowerBound = nil
   678  			n.upperBound = nil
   679  			n.insertValueConjunct(env, u, id)
   680  		}
   681  	}
   682  }