I think you are confusing how tidyverse selects variables with non-standard evaluation and the how base R's subsetting operator []. This operator takes an index or a character value, the column name. Please refer to AdvancedR for a much more thorough explanation.
Your example fails because the operator searches the global environment for an object names Species, not in the dataframe that is passed along. Using your example, lets see what happens when you supply the argument that it expects, and the issue of the .:
When you pass a character to the [] operator using the ., it does what you would "not" expect since you de-selected the Species column. That is because it references the original data frame.
> iris %>%
+ select(-Species) %>%
+ rename(Species_new = .[["Species"]]) %>% head()
Sepal.Length Sepal.Width Petal.Length Petal.Width
1 5.1 3.5 1.4 0.2
2 4.9 3.0 1.4 0.2
3 4.7 3.2 1.3 0.2
4 4.6 3.1 1.5 0.2
5 5.0 3.6 1.4 0.2
6 5.4 3.9 1.7 0.4
>
When you pass a character to the [] operator using the .data, it does what you "would" expect since you de-selected the Species column. That is because it references the piped data frame.
> iris %>%
+ select(-Species) %>%
+ rename(Species_new = .data[["Species"]]) %>% head()
Error: Column `Species` not found in `.data`
Run `rlang::last_error()` to see where the error occurred.
If we add an object named Species <- "Species", your code would then work even though you de-selected it in the pipeline. That can be quite dangerous if some of you objects have the same name as your column names.
> Species <- "Species"
> iris %>%
+ select(-Species) %>%
+ rename(Species_new = .[[Species]]) %>% head()
Sepal.Length Sepal.Width Petal.Length Petal.Width
1 5.1 3.5 1.4 0.2
2 4.9 3.0 1.4 0.2
3 4.7 3.2 1.3 0.2
4 4.6 3.1 1.5 0.2
5 5.0 3.6 1.4 0.2
6 5.4 3.9 1.7 0.4
I hope this helps. I know when I first started using R, I thought the same, that .data and . where the same thing. But then I started getting results that I did not expect and with further research and experience I discovered the above.