Repository: goccy/go-yaml
Pull request #660 (2025-02-16 06:28:46)

Keep reference of anchor's value
SSIA

codecov-commenter: :warning: Please install the !['codecov app svg image'](https://github.com/codecov/engineering-team/assets/152432831/e90313f4-9d3a-4b63-8b54-cfe14e7ec20d) to ensure uploads and comments are reliably processed by Codecov.

## [Codecov](https://app.codecov.io/gh/goccy/go-yaml/pull/660?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Masaaki+Goshima) Report
Attention: Patch coverage is `79.61165%` with `21 lines` in your changes missing coverage. Please review.
> Project coverage is 77.58%. Comparing base [(`89a6600`)](https://app.codecov.io/gh/goccy/go-yaml/commit/89a66008de66549c8f39ae2a2324e2eff5be00cf?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Masaaki+Goshima) to head [(`4c241a5`)](https://app.codecov.io/gh/goccy/go-yaml/commit/4c241a55105d5fb946f3b7f195841f1517704617?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Masaaki+Goshima).

:exclamation: Your organization needs to install the [Codecov GitHub app](https://github.com/apps/codecov/installations/select_target) to enable full functionality.

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##           master     #660      +/-   ##
==========================================
- Coverage   77.59%   77.58%   -0.02%     
==========================================
  Files          22       22              
  Lines        7843     7861      +18     
==========================================
+ Hits         6086     6099      +13     
- Misses       1345     1348       +3     
- Partials      412      414       +2     
```

</details>

Patch:
diff --git a/context.go b/context.go
index aa17d3c..133f05e 100644
--- a/context.go
+++ b/context.go
@@ -2,7 +2,10 @@ package yaml
 
 import "context"
 
-type ctxMergeKey struct{}
+type (
+	ctxMergeKey  struct{}
+	ctxAnchorKey struct{}
+)
 
 func withMerge(ctx context.Context) context.Context {
 	return context.WithValue(ctx, ctxMergeKey{}, true)
@@ -15,3 +18,20 @@ func isMerge(ctx context.Context) bool {
 	}
 	return v
 }
+
+func withAnchor(ctx context.Context, name string) context.Context {
+	anchorMap := getAnchorMap(ctx)
+	if anchorMap == nil {
+		anchorMap = make(map[string]struct{})
+	}
+	anchorMap[name] = struct{}{}
+	return context.WithValue(ctx, ctxAnchorKey{}, anchorMap)
+}
+
+func getAnchorMap(ctx context.Context) map[string]struct{} {
+	v, ok := ctx.Value(ctxAnchorKey{}).(map[string]struct{})
+	if !ok {
+		return nil
+	}
+	return v
+}
diff --git a/decode.go b/decode.go
index dadb3e7..0b453bc 100644
--- a/decode.go
+++ b/decode.go
@@ -29,7 +29,6 @@ type Decoder struct {
 	reader               io.Reader
 	referenceReaders     []io.Reader
 	anchorNodeMap        map[string]ast.Node
-	aliasValueMap        map[*ast.AliasNode]any
 	anchorValueMap       map[string]reflect.Value
 	customUnmarshalerMap map[reflect.Type]func(interface{}, []byte) error
 	commentMaps          []CommentMap
@@ -54,7 +53,6 @@ func NewDecoder(r io.Reader, opts ...DecodeOption) *Decoder {
 	return &Decoder{
 		reader:               r,
 		anchorNodeMap:        map[string]ast.Node{},
-		aliasValueMap:        make(map[*ast.AliasNode]any),
 		anchorValueMap:       map[string]reflect.Value{},
 		customUnmarshalerMap: map[reflect.Type]func(interface{}, []byte) error{},
 		opts:                 opts,
@@ -117,8 +115,8 @@ func (d *Decoder) castToFloat(v interface{}) interface{} {
 	return 0
 }
 
-func (d *Decoder) mapKeyNodeToString(node ast.MapKeyNode) (string, error) {
-	key, err := d.nodeToValue(node)
+func (d *Decoder) mapKeyNodeToString(ctx context.Context, node ast.MapKeyNode) (string, error) {
+	key, err := d.nodeToValue(ctx, node)
 	if err != nil {
 		return "", err
 	}
@@ -131,7 +129,7 @@ func (d *Decoder) mapKeyNodeToString(node ast.MapKeyNode) (string, error) {
 	return fmt.Sprint(key), nil
 }
 
-func (d *Decoder) setToMapValue(node ast.Node, m map[string]interface{}) error {
+func (d *Decoder) setToMapValue(ctx context.Context, node ast.Node, m map[string]interface{}) error {
 	d.stepIn()
 	defer d.stepOut()
 	if d.isExceededMaxDepth() {
@@ -148,16 +146,16 @@ func (d *Decoder) setToMapValue(node ast.Node, m map[string]interface{}) error {
 			}
 			iter := value.MapRange()
 			for iter.Next() {
-				if err := d.setToMapValue(iter.KeyValue(), m); err != nil {
+				if err := d.setToMapValue(ctx, iter.KeyValue(), m); err != nil {
 					return err
 				}
 			}
 		} else {
-			key, err := d.mapKeyNodeToString(n.Key)
+			key, err := d.mapKeyNodeToString(ctx, n.Key)
 			if err != nil {
 				return err
 			}
-			v, err := d.nodeToValue(n.Value)
+			v, err := d.nodeToValue(ctx, n.Value)
 			if err != nil {
 				return err
 			}
@@ -165,7 +163,7 @@ func (d *Decoder) setToMapValue(node ast.Node, m map[string]interface{}) error {
 		}
 	case *ast.MappingNode:
 		for _, value := range n.Values {
-			if err := d.setToMapValue(value, m); err != nil {
+			if err := d.setToMapValue(ctx, value, m); err != nil {
 				return err
 			}
 		}
@@ -176,7 +174,7 @@ func (d *Decoder) setToMapValue(node ast.Node, m map[string]interface{}) error {
 	return nil
 }
 
-func (d *Decoder) setToOrderedMapValue(node ast.Node, m *MapSlice) error {
+func (d *Decoder) setToOrderedMapValue(ctx context.Context, node ast.Node, m *MapSlice) error {
 	d.stepIn()
 	defer d.stepOut()
 	if d.isExceededMaxDepth() {
@@ -193,16 +191,16 @@ func (d *Decoder) setToOrderedMapValue(node ast.Node, m *MapSlice) error {
 			}
 			iter := value.MapRange()
 			for iter.Next() {
-				if err := d.setToOrderedMapValue(iter.KeyValue(), m); err != nil {
+				if err := d.setToOrderedMapValue(ctx, iter.KeyValue(), m); err != nil {
 					return err
 				}
 			}
 		} else {
-			key, err := d.mapKeyNodeToString(n.Key)
+			key, err := d.mapKeyNodeToString(ctx, n.Key)
 			if err != nil {
 				return err
 			}
-			value, err := d.nodeToValue(n.Value)
+			value, err := d.nodeToValue(ctx, n.Value)
 			if err != nil {
 				return err
 			}
@@ -210,7 +208,7 @@ func (d *Decoder) setToOrderedMapValue(node ast.Node, m *MapSlice) error {
 		}
 	case *ast.MappingNode:
 		for _, value := range n.Values {
-			if err := d.setToOrderedMapValue(value, m); err != nil {
+			if err := d.setToOrderedMapValue(ctx, value, m); err != nil {
 				return err
 			}
 		}
@@ -341,7 +339,7 @@ func (d *Decoder) addCommentToMap(path string, comment *Comment) {
 	})
 }
 
-func (d *Decoder) nodeToValue(node ast.Node) (any, error) {
+func (d *Decoder) nodeToValue(ctx context.Context, node ast.Node) (any, error) {
 	d.stepIn()
 	defer d.stepOut()
 	if d.isExceededMaxDepth() {
@@ -366,7 +364,7 @@ func (d *Decoder) nodeToValue(node ast.Node) (any, error) {
 		return n.GetValue(), nil
 	case *ast.TagNode:
 		if n.Directive != nil {
-			v, err := d.nodeToValue(n.Value)
+			v, err := d.nodeToValue(ctx, n.Value)
 			if err != nil {
 				return nil, err
 			}
@@ -377,17 +375,17 @@ func (d *Decoder) nodeToValue(node ast.Node) (any, error) {
 		}
 		switch token.ReservedTagKeyword(n.Start.Value) {
 		case token.TimestampTag:
-			t, _ := d.castToTime(n.Value)
+			t, _ := d.castToTime(ctx, n.Value)
 			return t, nil
 		case token.IntegerTag:
-			v, err := d.nodeToValue(n.Value)
+			v, err := d.nodeToValue(ctx, n.Value)
 			if err != nil {
 				return nil, err
 			}
 			i, _ := strconv.Atoi(fmt.Sprint(v))
 			return i, nil
 		case token.FloatTag:
-			v, err := d.nodeToValue(n.Value)
+			v, err := d.nodeToValue(ctx, n.Value)
 			if err != nil {
 				return nil, err
 			}
@@ -395,7 +393,7 @@ func (d *Decoder) nodeToValue(node ast.Node) (any, error) {
 		case token.NullTag:
 			return nil, nil
 		case token.BinaryTag:
-			v, err := d.nodeToValue(n.Value)
+			v, err := d.nodeToValue(ctx, n.Value)
 			if err != nil {
 				return nil, err
 			}
@@ -409,7 +407,7 @@ func (d *Decoder) nodeToValue(node ast.Node) (any, error) {
 			b, _ := base64.StdEncoding.DecodeString(str)
 			return b, nil
 		case token.BooleanTag:
-			v, err := d.nodeToValue(n.Value)
+			v, err := d.nodeToValue(ctx, n.Value)
 			if err != nil {
 				return nil, err
 			}
@@ -426,7 +424,7 @@ func (d *Decoder) nodeToValue(node ast.Node) (any, error) {
 			}
 			return nil, errors.ErrSyntax(fmt.Sprintf("cannot convert %q to boolean", fmt.Sprint(v)), n.Value.GetToken())
 		case token.StringTag:
-			v, err := d.nodeToValue(n.Value)
+			v, err := d.nodeToValue(ctx, n.Value)
 			if err != nil {
 				return nil, err
 			}
@@ -435,45 +433,41 @@ func (d *Decoder) nodeToValue(node ast.Node) (any, error) {
 			}
 			return fmt.Sprint(v), nil
 		case token.MappingTag:
-			return d.nodeToValue(n.Value)
+			return d.nodeToValue(ctx, n.Value)
 		default:
-			return d.nodeToValue(n.Value)
+			return d.nodeToValue(ctx, n.Value)
 		}
 	case *ast.AnchorNode:
 		anchorName := n.Name.GetToken().Value
 
 		// To handle the case where alias is processed recursively, the result of alias can be set to nil in advance.
 		d.anchorNodeMap[anchorName] = nil
-		anchorValue, err := d.nodeToValue(n.Value)
+		anchorValue, err := d.nodeToValue(withAnchor(ctx, anchorName), n.Value)
 		if err != nil {
 			delete(d.anchorNodeMap, anchorName)
 			return nil, err
 		}
 		d.anchorNodeMap[anchorName] = n.Value
+		d.anchorValueMap[anchorName] = reflect.ValueOf(anchorValue)
 		return anchorValue, nil
 	case *ast.AliasNode:
-		if v, exists := d.aliasValueMap[n]; exists {
-			return v, nil
-		}
-		// To handle the case where alias is processed recursively, the result of alias can be set to nil in advance.
-		d.aliasValueMap[n] = nil
-
-		aliasName := n.Value.GetToken().Value
-		node, exists := d.anchorNodeMap[aliasName]
-		if !exists {
-			return nil, errors.ErrSyntax(fmt.Sprintf("could not find alias %q", aliasName), n.Value.GetToken())
+		text := n.Value.String()
+		if _, exists := getAnchorMap(ctx)[text]; exists {
+			// self recursion.
+			return nil, nil
 		}
-		aliasValue, err := d.nodeToValue(node)
-		if err != nil {
-			return nil, err
+		if v, exists := d.anchorValueMap[text]; exists {
+			if !v.IsValid() {
+				return nil, nil
+			}
+			return v.Interface(), nil
 		}
-		// once the correct alias value is obtained, overwrite with that value.
-		d.aliasValueMap[n] = aliasValue
-		return aliasValue, nil
+		aliasName := n.Value.GetToken().Value
+		return nil, errors.ErrSyntax(fmt.Sprintf("could not find alias %q", aliasName), n.Value.GetToken())
 	case *ast.LiteralNode:
 		return n.Value.GetValue(), nil
 	case *ast.MappingKeyNode:
-		return d.nodeToValue(n.Value)
+		return d.nodeToValue(ctx, n.Value)
 	case *ast.MappingValueNode:
 		if n.Key.IsMergeKey() {
 			value, err := d.getMapNode(n.Value, true)
@@ -484,7 +478,7 @@ func (d *Decoder) nodeToValue(node ast.Node) (any, error) {
 			if d.useOrderedMap {
 				m := MapSlice{}
 				for iter.Next() {
-					if err := d.setToOrderedMapValue(iter.KeyValue(), &m); err != nil {
+					if err := d.setToOrderedMapValue(ctx, iter.KeyValue(), &m); err != nil {
 						return nil, err
 					}
 				}
@@ -492,24 +486,24 @@ func (d *Decoder) nodeToValue(node ast.Node) (any, error) {
 			}
 			m := make(map[string]any)
 			for iter.Next() {
-				if err := d.setToMapValue(iter.KeyValue(), m); err != nil {
+				if err := d.setToMapValue(ctx, iter.KeyValue(), m); err != nil {
 					return nil, err
 				}
 			}
 			return m, nil
 		}
-		key, err := d.mapKeyNodeToString(n.Key)
+		key, err := d.mapKeyNodeToString(ctx, n.Key)
 		if err != nil {
 			return nil, err
 		}
 		if d.useOrderedMap {
-			v, err := d.nodeToValue(n.Value)
+			v, err := d.nodeToValue(ctx, n.Value)
 			if err != nil {
 				return nil, err
 			}
 			return MapSlice{{Key: key, Value: v}}, nil
 		}
-		v, err := d.nodeToValue(n.Value)
+		v, err := d.nodeToValue(ctx, n.Value)
 		if err != nil {
 			return nil, err
 		}
@@ -518,7 +512,7 @@ func (d *Decoder) nodeToValue(node ast.Node) (any, error) {
 		if d.useOrderedMap {
 			m := make(MapSlice, 0, len(n.Values))
 			for _, value := range n.Values {
-				if err := d.setToOrderedMapValue(value, &m); err != nil {
+				if err := d.setToOrderedMapValue(ctx, value, &m); err != nil {
 					return nil, err
 				}
 			}
@@ -526,7 +520,7 @@ func (d *Decoder) nodeToValue(node ast.Node) (any, error) {
 		}
 		m := make(map[string]interface{}, len(n.Values))
 		for _, value := range n.Values {
-			if err := d.setToMapValue(value, m); err != nil {
+			if err := d.setToMapValue(ctx, value, m); err != nil {
 				return nil, err
 			}
 		}
@@ -534,7 +528,7 @@ func (d *Decoder) nodeToValue(node ast.Node) (any, error) {
 	case *ast.SequenceNode:
 		v := make([]interface{}, 0, len(n.Values))
 		for _, value := range n.Values {
-			vv, err := d.nodeToValue(value)
+			vv, err := d.nodeToValue(ctx, value)
 			if err != nil {
 				return nil, err
 			}
@@ -878,10 +872,13 @@ func (d *Decoder) decodeValue(ctx context.Context, dst reflect.Value, src ast.No
 	}
 
 	if src.Type() == ast.AnchorType {
-		anchorName := src.(*ast.AnchorNode).Name.GetToken().Value
-		if _, exists := d.anchorValueMap[anchorName]; !exists {
-			d.anchorValueMap[anchorName] = dst
+		anchor, _ := src.(*ast.AnchorNode)
+		anchorName := anchor.Name.GetToken().Value
+		if err := d.decodeValue(withAnchor(ctx, anchorName), dst, anchor.Value); err != nil {
+			return err
 		}
+		d.anchorValueMap[anchorName] = dst
+		return nil
 	}
 	if d.canDecodeByUnmarshaler(dst) {
 		if err := d.decodeByUnmarshaler(ctx, dst, src); err != nil {
@@ -914,7 +911,7 @@ func (d *Decoder) decodeValue(ctx context.Context, dst reflect.Value, src ast.No
 			dst.Set(reflect.ValueOf(src))
 			return nil
 		}
-		srcVal, err := d.nodeToValue(src)
+		srcVal, err := d.nodeToValue(ctx, src)
 		if err != nil {
 			return err
 		}
@@ -937,7 +934,7 @@ func (d *Decoder) decodeValue(ctx context.Context, dst reflect.Value, src ast.No
 		}
 		return d.decodeStruct(ctx, dst, src)
 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-		v, err := d.nodeToValue(src)
+		v, err := d.nodeToValue(ctx, src)
 		if err != nil {
 			return err
 		}
@@ -971,7 +968,7 @@ func (d *Decoder) decodeValue(ctx context.Context, dst reflect.Value, src ast.No
 		}
 		return errors.ErrOverflow(valueType, fmt.Sprint(v), src.GetToken())
 	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
-		v, err := d.nodeToValue(src)
+		v, err := d.nodeToValue(ctx, src)
 		if err != nil {
 			return err
 		}
@@ -1006,7 +1003,7 @@ func (d *Decoder) decodeValue(ctx context.Context, dst reflect.Value, src ast.No
 		}
 		return errors.ErrOverflow(valueType, fmt.Sprint(v), src.GetToken())
 	}
-	srcVal, err := d.nodeToValue(src)
+	srcVal, err := d.nodeToValue(ctx, src)
 	if err != nil {
 		return err
 	}
@@ -1046,6 +1043,9 @@ func (d *Decoder) castToAssignableValue(value reflect.Value, target reflect.Type
 		if value.Type().AssignableTo(target) {
 			break
 		}
+		if !value.CanAddr() {
+			break
+		}
 		value = value.Addr()
 	}
 	if !value.Type().AssignableTo(target) {
@@ -1091,7 +1091,7 @@ func (d *Decoder) createDecodedNewValue(
 	return d.castToAssignableValue(newValue, typ, node)
 }
 
-func (d *Decoder) keyToNodeMap(node ast.Node, ignoreMergeKey bool, getKeyOrValueNode func(*ast.MapNodeIter) ast.Node) (map[string]ast.Node, error) {
+func (d *Decoder) keyToNodeMap(ctx context.Context, node ast.Node, ignoreMergeKey bool, getKeyOrValueNode func(*ast.MapNodeIter) ast.Node) (map[string]ast.Node, error) {
 	d.stepIn()
 	defer d.stepOut()
 	if d.isExceededMaxDepth() {
@@ -1111,7 +1111,7 @@ func (d *Decoder) keyToNodeMap(node ast.Node, ignoreMergeKey bool, getKeyOrValue
 			if ignoreMergeKey {
 				continue
 			}
-			mergeMap, err := d.keyToNodeMap(mapIter.Value(), ignoreMergeKey, getKeyOrValueNode)
+			mergeMap, err := d.keyToNodeMap(ctx, mapIter.Value(), ignoreMergeKey, getKeyOrValueNode)
 			if err != nil {
 				return nil, err
 			}
@@ -1122,7 +1122,7 @@ func (d *Decoder) keyToNodeMap(node ast.Node, ignoreMergeKey bool, getKeyOrValue
 				keyToNodeMap[k] = v
 			}
 		} else {
-			keyVal, err := d.nodeToValue(keyNode)
+			keyVal, err := d.nodeToValue(ctx, keyNode)
 			if err != nil {
 				return nil, err
 			}
@@ -1139,16 +1139,16 @@ func (d *Decoder) keyToNodeMap(node ast.Node, ignoreMergeKey bool, getKeyOrValue
 	return keyToNodeMap, nil
 }
 
-func (d *Decoder) keyToKeyNodeMap(node ast.Node, ignoreMergeKey bool) (map[string]ast.Node, error) {
-	m, err := d.keyToNodeMap(node, ignoreMergeKey, func(nodeMap *ast.MapNodeIter) ast.Node { return nodeMap.Key() })
+func (d *Decoder) keyToKeyNodeMap(ctx context.Context, node ast.Node, ignoreMergeKey bool) (map[string]ast.Node, error) {
+	m, err := d.keyToNodeMap(ctx, node, ignoreMergeKey, func(nodeMap *ast.MapNodeIter) ast.Node { return nodeMap.Key() })
 	if err != nil {
 		return nil, err
 	}
 	return m, nil
 }
 
-func (d *Decoder) keyToValueNodeMap(node ast.Node, ignoreMergeKey bool) (map[string]ast.Node, error) {
-	m, err := d.keyToNodeMap(node, ignoreMergeKey, func(nodeMap *ast.MapNodeIter) ast.Node { return nodeMap.Value() })
+func (d *Decoder) keyToValueNodeMap(ctx context.Context, node ast.Node, ignoreMergeKey bool) (map[string]ast.Node, error) {
+	m, err := d.keyToNodeMap(ctx, node, ignoreMergeKey, func(nodeMap *ast.MapNodeIter) ast.Node { return nodeMap.Value() })
 	if err != nil {
 		return nil, err
 	}
@@ -1194,11 +1194,11 @@ var allowedTimestampFormats = []string{
 	"2006-1-2",                        // date only
 }
 
-func (d *Decoder) castToTime(src ast.Node) (time.Time, error) {
+func (d *Decoder) castToTime(ctx context.Context, src ast.Node) (time.Time, error) {
 	if src == nil {
 		return time.Time{}, nil
 	}
-	v, err := d.nodeToValue(src)
+	v, err := d.nodeToValue(ctx, src)
 	if err != nil {
 		return time.Time{}, err
 	}
@@ -1221,7 +1221,7 @@ func (d *Decoder) castToTime(src ast.Node) (time.Time, error) {
 }
 
 func (d *Decoder) decodeTime(ctx context.Context, dst reflect.Value, src ast.Node) error {
-	t, err := d.castToTime(src)
+	t, err := d.castToTime(ctx, src)
 	if err != nil {
 		return err
 	}
@@ -1229,11 +1229,11 @@ func (d *Decoder) decodeTime(ctx context.Context, dst reflect.Value, src ast.Nod
 	return nil
 }
 
-func (d *Decoder) castToDuration(src ast.Node) (time.Duration, error) {
+func (d *Decoder) castToDuration(ctx context.Context, src ast.Node) (time.Duration, error) {
 	if src == nil {
 		return 0, nil
 	}
-	v, err := d.nodeToValue(src)
+	v, err := d.nodeToValue(ctx, src)
 	if err != nil {
 		return 0, err
 	}
@@ -1252,7 +1252,7 @@ func (d *Decoder) castToDuration(src ast.Node) (time.Duration, error) {
 }
 
 func (d *Decoder) decodeDuration(ctx context.Context, dst reflect.Value, src ast.Node) error {
-	t, err := d.castToDuration(src)
+	t, err := d.castToDuration(ctx, src)
 	if err != nil {
 		return err
 	}
@@ -1304,13 +1304,13 @@ func (d *Decoder) decodeStruct(ctx context.Context, dst reflect.Value, src ast.N
 		return err
 	}
 	ignoreMergeKey := structFieldMap.hasMergeProperty()
-	keyToNodeMap, err := d.keyToValueNodeMap(src, ignoreMergeKey)
+	keyToNodeMap, err := d.keyToValueNodeMap(ctx, src, ignoreMergeKey)
 	if err != nil {
 		return err
 	}
 	var unknownFields map[string]ast.Node
 	if d.disallowUnknownField {
-		unknownFields, err = d.keyToKeyNodeMap(src, ignoreMergeKey)
+		unknownFields, err = d.keyToKeyNodeMap(ctx, src, ignoreMergeKey)
 		if err != nil {
 			return err
 		}
@@ -1566,11 +1566,11 @@ func (d *Decoder) decodeMapItem(ctx context.Context, dst *MapItem, src ast.Node)
 		}
 		return nil
 	}
-	k, err := d.nodeToValue(key)
+	k, err := d.nodeToValue(ctx, key)
 	if err != nil {
 		return err
 	}
-	v, err := d.nodeToValue(value)
+	v, err := d.nodeToValue(ctx, value)
 	if err != nil {
 		return err
 	}
@@ -1622,14 +1622,14 @@ func (d *Decoder) decodeMapSlice(ctx context.Context, dst *MapSlice, src ast.Nod
 			}
 			continue
 		}
-		k, err := d.nodeToValue(key)
+		k, err := d.nodeToValue(ctx, key)
 		if err != nil {
 			return err
 		}
 		if err := d.validateDuplicateKey(keyMap, k, key); err != nil {
 			return err
 		}
-		v, err := d.nodeToValue(value)
+		v, err := d.nodeToValue(ctx, value)
 		if err != nil {
 			return err
 		}
@@ -1680,7 +1680,7 @@ func (d *Decoder) decodeMap(ctx context.Context, dst reflect.Value, src ast.Node
 				return err
 			}
 		} else {
-			keyVal, err := d.nodeToValue(key)
+			keyVal, err := d.nodeToValue(ctx, key)
 			if err != nil {
 				return err
 			}
@@ -1783,7 +1783,7 @@ func (d *Decoder) readersUnderDirRecursive(dir string) ([]io.Reader, error) {
 	return readers, nil
 }
 
-func (d *Decoder) resolveReference() error {
+func (d *Decoder) resolveReference(ctx context.Context) error {
 	for _, opt := range d.opts {
 		if err := opt(d); err != nil {
 			return err
@@ -1818,7 +1818,7 @@ func (d *Decoder) resolveReference() error {
 		}
 
 		// assign new anchor definition to anchorMap
-		if _, err := d.parse(bytes); err != nil {
+		if _, err := d.parse(ctx, bytes); err != nil {
 			return err
 		}
 	}
@@ -1826,7 +1826,7 @@ func (d *Decoder) resolveReference() error {
 	return nil
 }
 
-func (d *Decoder) parse(bytes []byte) (*ast.File, error) {
+func (d *Decoder) parse(ctx context.Context, bytes []byte) (*ast.File, error) {
 	var parseMode parser.Mode
 	if d.toCommentMap != nil {
 		parseMode = parser.ParseComments
@@ -1842,7 +1842,7 @@ func (d *Decoder) parse(bytes []byte) (*ast.File, error) {
 	normalizedFile := &ast.File{}
 	for _, doc := range f.Docs {
 		// try to decode ast.Node to value and map anchor value to anchorMap
-		v, err := d.nodeToValue(doc.Body)
+		v, err := d.nodeToValue(ctx, doc.Body)
 		if err != nil {
 			return nil, err
 		}
@@ -1863,9 +1863,9 @@ func (d *Decoder) isInitialized() bool {
 	return d.parsedFile != nil
 }
 
-func (d *Decoder) decodeInit() error {
+func (d *Decoder) decodeInit(ctx context.Context) error {
 	if !d.isResolvedReference {
-		if err := d.resolveReference(); err != nil {
+		if err := d.resolveReference(ctx); err != nil {
 			return err
 		}
 	}
@@ -1873,7 +1873,7 @@ func (d *Decoder) decodeInit() error {
 	if _, err := io.Copy(&buf, d.reader); err != nil {
 		return err
 	}
-	file, err := d.parse(buf.Bytes())
+	file, err := d.parse(ctx, buf.Bytes())
 	if err != nil {
 		return err
 	}
@@ -1883,6 +1883,7 @@ func (d *Decoder) decodeInit() error {
 
 func (d *Decoder) decode(ctx context.Context, v reflect.Value) error {
 	d.decodeDepth = 0
+	d.anchorValueMap = make(map[string]reflect.Value)
 	if len(d.parsedFile.Docs) <= d.streamIndex {
 		return io.EOF
 	}
@@ -1925,7 +1926,7 @@ func (d *Decoder) DecodeContext(ctx context.Context, v interface{}) error {
 		}
 		return nil
 	}
-	if err := d.decodeInit(); err != nil {
+	if err := d.decodeInit(ctx); err != nil {
 		return err
 	}
 	if err := d.decode(ctx, rv); err != nil {
@@ -1949,12 +1950,12 @@ func (d *Decoder) DecodeFromNodeContext(ctx context.Context, node ast.Node, v in
 		return ErrDecodeRequiredPointerType
 	}
 	if !d.isInitialized() {
-		if err := d.decodeInit(); err != nil {
+		if err := d.decodeInit(ctx); err != nil {
 			return err
 		}
 	}
 	// resolve references to the anchor on the same file
-	if _, err := d.nodeToValue(node); err != nil {
+	if _, err := d.nodeToValue(ctx, node); err != nil {
 		return err
 	}
 	if err := d.decodeValue(ctx, rv.Elem(), node); err != nil {


Test patch:
diff --git a/decode_test.go b/decode_test.go
index 15a1a73..ef2b68d 100644
--- a/decode_test.go
+++ b/decode_test.go
@@ -3058,6 +3058,28 @@ bar:
 	})
 }
 
+func TestDecodeWithSameAnchor(t *testing.T) {
+	yml := `
+a: &a 1
+b: &a 2
+c: &a 3
+d: *a
+`
+	type T struct {
+		A int
+		B int
+		C int
+		D int
+	}
+	var v T
+	if err := yaml.Unmarshal([]byte(yml), &v); err != nil {
+		t.Fatal(err)
+	}
+	if !reflect.DeepEqual(v, T{A: 1, B: 2, C: 3, D: 3}) {
+		t.Fatalf("failed to decode same anchor: %+v", v)
+	}
+}
+
 func TestUnmarshalMapSliceParallel(t *testing.T) {
 	content := `
 steps:
diff --git a/yaml_test.go b/yaml_test.go
index 560a93c..ae469f9 100644
--- a/yaml_test.go
+++ b/yaml_test.go
@@ -1,6 +1,7 @@
 package yaml_test
 
 import (
+	"fmt"
 	"io"
 	"reflect"
 	"strings"
@@ -72,3 +73,28 @@ foo: bar # comment
 		t.Fatalf("failed to get comment: %v", commentPathsWithDocIndex)
 	}
 }
+
+func TestDecodeKeepAddress(t *testing.T) {
+	var data = `
+a: &a [_]
+b: &b [*a,*a]
+c: &c [*b,*b]
+d: &d [*c,*c]
+`
+	var v map[string]any
+	if err := yaml.Unmarshal([]byte(data), &v); err != nil {
+		t.Fatal(err)
+	}
+	a := v["a"]
+	b := v["b"]
+	for _, vv := range v["b"].([]any) {
+		if fmt.Sprintf("%p", a) != fmt.Sprintf("%p", vv) {
+			t.Fatalf("failed to decode b element as keep address")
+		}
+	}
+	for _, vv := range v["c"].([]any) {
+		if fmt.Sprintf("%p", b) != fmt.Sprintf("%p", vv) {
+			t.Fatalf("failed to decode c element as keep address")
+		}
+	}
+}