text: package cty
  
  import (
  	"fmt"
  )
  
  // anyUnknown is a helper to easily check if a set of values contains any
  // unknowns, for operations that short-circuit to return unknown in that case.
  func anyUnknown(values ...Value) bool {
  	for _, val := range values {
  		if val.v == unknown {
  			return true
  		}
  	}
  	return false
  }
  
  // typeCheck tests whether all of the given values belong to the given type.
  // If the given types are a mixture of the given type and the dynamic
  // pseudo-type then a short-circuit dynamic value is returned. If the given
  // values are all of the correct type but at least one is unknown then
  // a short-circuit unknown value is returned. If any other types appear then
  // an error is returned. Otherwise (finally!) the result is nil, nil.
  func typeCheck(required Type, ret Type, values ...Value) (shortCircuit *Value, err error) {
  	hasDynamic := false
  	hasUnknown := false
  
  	for i, val := range values {
  		if val.ty == DynamicPseudoType {
  			hasDynamic = true
  			continue
  		}
  
  		if !val.Type().Equals(required) {
  			return nil, fmt.Errorf(
  				"type mismatch: want %s but value %d is %s",
  				required.FriendlyName(),
  				i, val.ty.FriendlyName(),
  			)
  		}
  
  		if val.v == unknown {
  			hasUnknown = true
  		}
  	}
  
  	if hasDynamic {
  		return &DynamicVal, nil
  	}
  
  	if hasUnknown {
  		ret := UnknownVal(ret)
  		return &ret, nil
  	}
  
  	return nil, nil
  }
  
  // mustTypeCheck is a wrapper around typeCheck that immediately panics if
  // any error is returned.
  func mustTypeCheck(required Type, ret Type, values ...Value) *Value {
  	shortCircuit, err := typeCheck(required, ret, values...)
  	if err != nil {
  		panic(err)
  	}
  	return shortCircuit
  }
  
  // shortCircuitForceType takes the return value from mustTypeCheck and
  // replaces it with an unknown of the given type if the original value was
  // DynamicVal.
  //
  // This is useful for operations that are specified to always return a
  // particular type, since then a dynamic result can safely be "upgrade" to
  // a strongly-typed unknown, which then allows subsequent operations to
  // be actually type-checked.
  //
  // It is safe to use this only if the operation in question is defined as
  // returning either a value of the given type or panicking, since we know
  // then that subsequent operations won't run if the operation panics.
  //
  // If the given short-circuit value is *not* DynamicVal then it must be
  // of the given type, or this function will panic.
  func forceShortCircuitType(shortCircuit *Value, ty Type) *Value {
  	if shortCircuit == nil {
  		return nil
  	}
  
  	if shortCircuit.ty == DynamicPseudoType {
  		ret := UnknownVal(ty)
  		return &ret
  	}
  
  	if !shortCircuit.ty.Equals(ty) {
  		panic("forceShortCircuitType got value of wrong type")
  	}
  
  	return shortCircuit
  }
  