fix!: never leave folded constant interpolations as SQL text - #435
Merged
Conversation
The IR transformer splits constants the compiler folded into template text back into fragments and t()-wrapped values by re-reading the source. The splitter had four silent bail paths triggered by escape sequences, an unguarded substring that crashed the compiler on unicode escapes and adjacent constants, and no handling at all for templates that fold into a single constant or for folded const val references. In every silent case the interpolation stayed SQL text while the autoInterpolation() marker was still injected, so the runtime backstop believed the template was fully processed. The splitter is now a verified source parser. It decodes escape sequences, handles raw strings, multi-dollar markers, regions that start inside an interpolation, folded operator chains, and inner string, char, boolean, and integer literals. Parsing is driven purely by the source text and the reassembled text must equal the folded value, so a wrong split cannot go undetected. Templates that fold into a single constant are recovered through the lambda's result positions, and constants folded in place of a single interpolation, such as const val references, bind as values per the template contract. A folded constant that cannot be recovered, such as a float literal on Kotlin 2.0, is reported as a compiler error through the MessageCollector, naming the expression and the remedy. BREAKING CHANGE: interpolated const val references now bind as values instead of being concatenated as SQL text, and unsplittable folded constants fail compilation instead of silently becoming SQL text. Fixes #393
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #393
Problem
The compiler plugin's IR transformer re-reads the source file to split constants the compiler already folded into template text. The splitter had three failure classes:
\n,\t,\",\$,\uXXXX) adjacent to a folded constant made the split bail, leaving the interpolation as SQL text while theautoInterpolation()marker was still injected, so the runtime backstop believed the template was fully processed. Foldedconst valreferences (${CONST},$CONST) and multi-dollar templates hit the same bails, and a template whose interpolations are all constant folds into a singleIrConstwith no concatenation at all, which the transformer never visited ("a\nb${"c"}d"was this case)."aé${"c"}"and"${"a"}${"b"}"threwStringIndexOutOfBoundsExceptionout of an unguardedsubstring, killing the compilation with no usable message.Fix
All three transformer variants are rebuilt around a verified source parser:
+chains, and inner string/char/boolean/integer literals.const valreferences, never merge with the surrounding text (verified across Kotlin 2.0.0-2.4.0), so they wrap int()and bind as values per the template contract.trimIndent()receivers), leaving incidental strings elsewhere in the lambda untouched.${1.5}on Kotlin 2.0 which folds floats whose rendering is not derived from source, is reported as a compiler error naming the expression and the remedy, wired through theMessageCollectorin both registrar variants.Breaking change
Interpolated
const valreferences now bind as values instead of being concatenated as SQL text, and unsplittable folded constants fail compilation instead of silently becoming SQL text. To contribute constant SQL text, put the text in the template itself or concatenate literals with+.Verification
storm-kotlinandstorm-kotlinx-serialization, which compile with the plugin, passes.docs/string-templates.mdgains a Constant Interpolations section describing the value semantics.