code: func RequiresReplace(attrs []string, ty cty.Type) ([]cty.Path, error) {
  	var paths []cty.Path
  
  	for _, attr := range attrs {
  		p, err := requiresReplacePath(attr, ty)
  		if err != nil {
  			return nil, err
  		}
  
  		paths = append(paths, p)
  	}
  
  	// now trim off any trailing paths that aren't GetAttrSteps, since only an
  	// attribute itself can require replacement
  	paths = trimPaths(paths)
  
  	// There may be redundant paths due to set elements or index attributes
  	// Do some ugly n^2 filtering, but these are always fairly small sets.
  	for i := 0; i < len(paths)-1; i++ {
  		for j := i + 1; j < len(paths); j++ {
  			if reflect.DeepEqual(paths[i], paths[j]) {
  				// swap the tail and slice it off
  				paths[j], paths[len(paths)-1] = paths[len(paths)-1], paths[j]
  				paths = paths[:len(paths)-1]
  				j--
  			}
  		}
  	}
  
  	return paths, nil
  }
docs: // RequiresReplace takes a list of flatmapped paths from a
  // InstanceDiff.Attributes along with the corresponding cty.Type, and returns
  // the list of the cty.Paths that are flagged as causing the resource
  // replacement (RequiresNew).
  // This will filter out redundant paths, paths that refer to flatmapped indexes
  // (e.g. "#", "%"), and will return any changes within a set as the path to the
  // set itself.