func (t Traversal) IsRelative() bool {
	if len(t) == 0 {
		return true
	}
	if _, firstIsRoot := t[0].(TraverseRoot); firstIsRoot {
		return false
	}
	return true
}
IsRelative returns true if the receiver is a relative traversal, or false
otherwise.
package hcl
import (
	"fmt"
	"github.com/zclconf/go-cty/cty"
)
type Traversal []Traverser
func TraversalJoin(abs Traversal, rel Traversal) Traversal {
	if abs.IsRelative() {
		panic("first argument to TraversalJoin must be absolute")
	}
	if !rel.IsRelative() {
		panic("second argument to TraversalJoin must be relative")
	}
	ret := make(Traversal, len(abs)+len(rel))
	copy(ret, abs)
	copy(ret[len(abs):], rel)
	return ret
}
func (t Traversal) TraverseRel(val cty.Value) (cty.Value, Diagnostics) {
	if !t.IsRelative() {
		panic("can't use TraverseRel on an absolute traversal")
	}
	current := val
	var diags Diagnostics
	for _, tr := range t {
		var newDiags Diagnostics
		current, newDiags = tr.TraversalStep(current)
		diags = append(diags, newDiags...)
		if newDiags.HasErrors() {
			return cty.DynamicVal, diags
		}
	}
	return current, diags
}
func (t Traversal) TraverseAbs(ctx *EvalContext) (cty.Value, Diagnostics) {
	if t.IsRelative() {
		panic("can't use TraverseAbs on a relative traversal")
	}
	split := t.SimpleSplit()
	root := split.Abs[0].(TraverseRoot)
	name := root.Name
	thisCtx := ctx
	hasNonNil := false
	for thisCtx != nil {
		if thisCtx.Variables == nil {
			thisCtx = thisCtx.parent
			continue
		}
		hasNonNil = true
		val, exists := thisCtx.Variables[name]
		if exists {
			return split.Rel.TraverseRel(val)
		}
		thisCtx = thisCtx.parent
	}
	if !hasNonNil {
		return cty.DynamicVal, Diagnostics{
			{
				Severity: DiagError,
				Summary:  "Variables not allowed",
				Detail:   "Variables may not be used here.",
				Subject:  &root.SrcRange,
			},
		}
	}
	suggestions := make([]string, 0, len(ctx.Variables))
	thisCtx = ctx
	for thisCtx != nil {
		for k := range thisCtx.Variables {
			suggestions = append(suggestions, k)
		}
		thisCtx = thisCtx.parent
	}
	suggestion := nameSuggestion(name, suggestions)
	if suggestion != "" {
		suggestion = fmt.Sprintf(" Did you mean %q?", suggestion)
	}
	return cty.DynamicVal, Diagnostics{
		{
			Severity: DiagError,
			Summary:  "Unknown variable",
			Detail:   fmt.Sprintf("There is no variable named %q.%s", name, suggestion),
			Subject:  &root.SrcRange,
		},
	}
}