Repository: opentofu/opentofu
File: internal/tofu/evaluate.go (Go)

Code before:
		if !ok {
			instance = map[string]*plans.OutputChangeSrc{}
			changesMap[callInstance.Key] = instance
		}

		instance[change.Addr.OutputValue.Name] = change
	}

	// Build up all the module objects, creating a map of values for each
	// module instance.
	moduleInstances := map[addrs.InstanceKey]map[string]cty.Value{}

	// First, we need to determine which module instances actually exist.
	if d.Evaluator.InstanceExpander != nil {
		childModuleAddr := d.ModulePath.Module().Child(addr.Name)
		moduleInstanceAddrs := d.Evaluator.InstanceExpander.ExpandModule(childModuleAddr)

		for _, moduleInstanceAddr := range moduleInstanceAddrs {
			if len(moduleInstanceAddr) > 0 {
				lastStep := moduleInstanceAddr[len(moduleInstanceAddr)-1]
				key := lastStep.InstanceKey

				if _, exists := moduleInstances[key]; !exists {
					moduleInstances[key] = map[string]cty.Value{}
				}
			}
		}
	}

	// create a dummy object type for validation below
	unknownMap := map[string]cty.Type{}

	// the structure is based on the configuration, so iterate through all the
	// defined outputs, and add any instance state or changes we find.
	for _, cfg := range outputConfigs {
		// record the output names for validation
		unknownMap[cfg.Name] = cty.DynamicPseudoType

		// get all instance output for this path from the state
		for key, outputStates := range stateMap {
			outputState, ok := outputStates[cfg.Name]
			if !ok {
				continue
			}

			instance, ok := moduleInstances[key]
			if !ok {
				instance = map[string]cty.Value{}
				moduleInstances[key] = instance
			}


Review comment (suggestion):
```suggestion
			_, callInstance := moduleInstanceAddr.CallInstance()
			key := callInstance.Key

			if _, exists := moduleInstances[key]; !exists {
				moduleInstances[key] = map[string]cty.Value{}
			}
```

Let's use `CallInstance` as this is the pattern being used in this file.

Code after:
		if !ok {
			instance = map[string]*plans.OutputChangeSrc{}
			changesMap[callInstance.Key] = instance
		}

		instance[change.Addr.OutputValue.Name] = change
	}

	// Build up all the module objects, creating a map of values for each
	// module instance.
	moduleInstances := map[addrs.InstanceKey]map[string]cty.Value{}

	// Pre-populate moduleInstances using InstanceExpander to handle modules with no outputs.
	// This ensures that expressions like length(module.foo) work correctly even when a module
	// has no output values defined, by consulting the expansion state to determine which
	// module instances exist based on count/for_each.
	// We only do this during non-validation operations (plan, apply, etc.) because during
	// validation, the InstanceExpander may not be fully populated yet.
	if d.Evaluator.InstanceExpander != nil && d.Evaluator.Operation != walkValidate {
		childModuleAddr := d.ModulePath.Module().Child(addr.Name)
		moduleInstanceAddrs := d.Evaluator.InstanceExpander.ExpandModule(childModuleAddr)

		for _, moduleInstanceAddr := range moduleInstanceAddrs {
			_, callInstance := moduleInstanceAddr.CallInstance()
			key := callInstance.Key
			if _, exists := moduleInstances[key]; !exists {
				moduleInstances[key] = map[string]cty.Value{}
			}
		}
	}

	// create a dummy object type for validation below
	unknownMap := map[string]cty.Type{}

	// the structure is based on the configuration, so iterate through all the
	// defined outputs, and add any instance state or changes we find.
	for _, cfg := range outputConfigs {
		// record the output names for validation
		unknownMap[cfg.Name] = cty.DynamicPseudoType

		// get all instance output for this path from the state
		for key, outputStates := range stateMap {
			outputState, ok := outputStates[cfg.Name]
			if !ok {
				continue
			}

			instance, ok := moduleInstances[key]
			if !ok {
				instance = map[string]cty.Value{}
				moduleInstances[key] = instance