Richard Feldman said:
we just make an "interpolated string" can IR node type
So I spent a bit of time thinking about this and trying different things. After a while I realised we could use a Expr.Span
here to represent both simple and complex interpolated strings, and only copy the bytes from our source into the module env string interner once.
Not sure if this is the best way to do it, but it seems to be working nicely. I've lumped the change in with my WIP Can PR if you want to see the snapshots and how it looks https://github.com/roc-lang/roc/pull/7820
Here is the Can IR representation.
// A single segment of a string literal
// a single string may be made up of a span sequential segments
// for example if it was split across multiple lines
str_segment: StringLiteral.Idx,
// A string is combined of one or more segments, some of which may be interpolated
// An interpolated string contains one or more non-string_segment's in the span
str: Expr.Span,
And here is a demo from one of the snapshots showing it in action.
~~~META
description=Simple string interpolation
type=expr
~~~SOURCE
"Hello ${name}!"
~~~PROBLEMS
CANONICALIZE: ident_not_in_scope
~~~TOKENS
StringStart(1:1-1:2),StringPart(1:2-1:8),OpenStringInterpolation(1:8-1:10),LowerIdent(1:10-1:14),CloseStringInterpolation(1:14-1:15),StringPart(1:15-1:16),StringEnd(1:16-1:17),EndOfFile(1:17-1:17),
~~~PARSE
(string (1:1-1:17)
(string_part (1:2-1:8) "Hello ")
(ident (1:10-1:14) "" "name")
(string_part (1:15-1:16) "!"))
~~~FORMATTED
NO CHANGE
~~~CANONICALIZE
(string
(literal "Hello ")
(runtime_error (1:4-1:4) "RUNTIME ERROR ident_not_in_scope")
(literal "!"))
~~~END
Never mind the Can region info, I haven't got that reporting correctly.
#7849 -- DRAFT PR to make a start on type declarations and annotations. I've left a few questions in there @Richard Feldman
I'll take a look!
the snapshot looks good to me!
To convince myself this is behaving correctly, I've continued to shave the yak. It's now another mammoth PR that implements most of can for type declarations, type annotations, and type aliases. :sweat_smile:
I'm just polishing it now, but will push the latest draft up soon.
I've pushed everything up to https://github.com/roc-lang/roc/pull/7849
I will review again tomorrow and aim to merge what is already there (instead of adding more).
Quick question: Currently the parsed AST put everything wrapped in ()
into a tuple node. In the event of a 1 element tuple, should canonicalization reinterpret that as just parenthesis and type the CIR node as the type of the single element?
Jared Ramirez said:
Quick question: Currently the parsed AST put everything wrapped in
()
into a tuple node. In the event of a 1 element tuple, should canonicalization reinterpret that as just parenthesis and type the CIR node as the type of the single element?
yes
a 1-tuple === parenthesized expr
and probably not needed in can strictly
Okay cool! Since Can is where we create/assign type vars, I think this makes sense to do there. But if anyone feels otherwise lmk!
a 1-tuple === parenthesized expr
this equality operator tells so much :grinning_face_with_smiling_eyes:
Similarly, ()
parses into an empty tuple, so I think this should this be a can error? Something along the lines of invalid blah, if you want to represent "nothing", use {}
?
yep :thumbs_up:
()
should only be used in the types of 0-argument fns
e.g. my_fn! : () => Str
Kiryl Dziamura said:
a 1-tuple === parenthesized expr
this equality operator tells so much :grinning_face_with_smiling_eyes:
I am a TC-39 Delegate :stuck_out_tongue:
@Anthony Bullard every time I hear you say that I can't help but imagine TC-39 is the name of a Star Wars droid, and your it's owner.
Like, hey guys I own this badass K-2 droid.
Last updated: Jul 06 2025 at 12:14 UTC