# lm in non-full rank case [duplicate]

MATHEMATICALLY, how does lm deal with the case when the data is not full rank? Take the simple example :

set.seed(1234)

n <- 100
X1 <- rnorm(n)
X2 <- rnorm(n)
Y <- 2 + 3 * X1 + 4*X2 + rnorm(n, mean = 0, sd = 0.1)

model <- lm(Y ~ X1 + X2 + I(2*X1 + 3*X2))
mat <- model.matrix(model)
print(summary(model))


It gives the output :

Call:
lm(formula = Y ~ X1 + X2 + I(2 * X1 + 3 * X2))

Residuals:
Min       1Q   Median       3Q      Max
-0.31933 -0.06734  0.01060  0.05823  0.27650

Coefficients: (1 not defined because of singularities)
Estimate Std. Error t value Pr(>|t|)
(Intercept)        2.016358   0.009747   206.9   <2e-16 ***
X1                 3.008051   0.009633   312.3   <2e-16 ***
X2                 4.008832   0.009373   427.7   <2e-16 ***
I(2 * X1 + 3 * X2)       NA         NA      NA       NA
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.09624 on 97 degrees of freedom
Multiple R-squared:  0.9996,    Adjusted R-squared:  0.9996
F-statistic: 1.369e+05 on 2 and 97 DF,  p-value: < 2.2e-16


It seems lm finds a way to identify a column to be a linear combination of the other two! However, a change in the last formula :

model <- lm(Y ~ X1 + I(2*X1 + 3*X2) + X2)


With the rest of the code being the same, yields :

Call:
lm(formula = Y ~ X1 + I(2 * X1 + 3 * X2) + X2)

Residuals:
Min       1Q   Median       3Q      Max
-0.31933 -0.06734  0.01060  0.05823  0.27650

Coefficients: (1 not defined because of singularities)
Estimate Std. Error t value Pr(>|t|)
(Intercept)        2.016358   0.009747  206.86   <2e-16 ***
X1                 0.335497   0.011348   29.56   <2e-16 ***
I(2 * X1 + 3 * X2) 1.336277   0.003124  427.68   <2e-16 ***
X2                       NA         NA      NA       NA
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.09624 on 97 degrees of freedom
Multiple R-squared:  0.9996,    Adjusted R-squared:  0.9996
F-statistic: 1.369e+05 on 2 and 97 DF,  p-value: < 2.2e-16


So does R have some mechanism of detecting non-full rank data ? Does it check the data according to the formula before giving least squares ?