···174174 /// ```json
175175 /// {
176176 /// gleam: true,
177177+ /// can_run_on_erlang: true,
178178+ /// can_run_on_javascript: true,
177179 /// uses_erlang_externals: true,
178180 /// uses_javascript_externals: false,
179181 /// }
···181183 ///
182184 /// - `gleam: true` means that the function has a pure Gleam implementation
183185 /// and thus it can be used on all Gleam targets with no problems.
186186+ /// - `can_run_on_erlang: false` the function can be called on the Erlang
187187+ /// target.
188188+ /// - `can_run_on_javascript: true` the function can be called on the JavaScript
189189+ /// target.
184190 /// - `uses_erlang_externals: true` means that the function will use Erlang
185191 /// external code when compiled to the Erlang target.
186192 /// - `uses_javascript_externals: false` means that the function won't use
···208214 /// ```json
209215 /// {
210216 /// gleam: false,
217217+ /// can_run_on_erlang: false,
218218+ /// can_run_on_javascript: true,
211219 /// uses_erlang_externals: false,
212220 /// uses_javascript_externals: true,
213221 /// }
···216224 /// - `gleam: false` means that the function doesn't have a pure Gleam
217225 /// implementations. This means that the function is only defined using
218226 /// externals and can only be used on some targets.
227227+ /// - `can_run_on_erlang: false` the function cannot be called on the Erlang
228228+ /// target.
229229+ /// - `can_run_on_javascript: true` the function can be called on the JavaScript
230230+ /// target.
219231 /// - `uses_erlang_externals: false` the function is not using external
220220- /// Erlang code. So, since the function doesn't have a fallback pure Gleam
221221- /// implementation, you won't be able to compile it on this target.
232232+ /// Erlang code.
222233 /// - `uses_javascript_externals: true` the function is using JavaScript
223223- /// external code. This means that you will be able to use it on the
224224- /// JavaScript target with no problems.
234234+ /// external code.
225235 uses_javascript_externals: bool,
236236+ /// Whether the function can be called on the Erlang target, either due to a
237237+ /// pure Gleam implementation or an implementation that uses some Erlang
238238+ /// externals.
239239+ can_run_on_erlang: bool,
240240+ /// Whether the function can be called on the JavaScript target, either due
241241+ /// to a pure Gleam implementation or an implementation that uses some
242242+ /// JavaScript externals.
243243+ can_run_on_javascript: bool,
226244}
227245228246impl ImplementationsInterface {
···240258 gleam,
241259 uses_erlang_externals,
242260 uses_javascript_externals,
261261+262262+ can_run_on_erlang,
263263+ can_run_on_javascript,
243264 } = implementations;
244265245266 ImplementationsInterface {
246267 gleam: *gleam,
247268 uses_erlang_externals: *uses_erlang_externals,
248269 uses_javascript_externals: *uses_javascript_externals,
270270+ can_run_on_erlang: *can_run_on_erlang,
271271+ can_run_on_javascript: *can_run_on_javascript,
249272 }
250273 }
251274}
···3636 /// is added - say a WASM target - `func` wouldn't support it! On the other
3737 /// hand, a pure Gleam function will support all future targets.
3838 pub gleam: bool,
3939+ pub can_run_on_erlang: bool,
4040+ pub can_run_on_javascript: bool,
3941 /// Wether the function has an implementation that uses external erlang
4042 /// code.
4143 pub uses_erlang_externals: bool,
···4951/// This is used to determine whether an error should be raised in the case when
5052/// a value is used that does not have an implementation for the current target.
5153#[derive(Clone, Copy, Debug)]
5252-pub struct Externals {
5454+pub struct FunctionDefinition {
5555+ /// The function has { ... } after the function head
5656+ pub has_body: bool,
5357 /// The function has @external(erlang, "...", "...")
5454- pub erlang: bool,
5858+ pub has_erlang_external: bool,
5559 /// The function has @external(JavaScript, "...", "...")
5656- pub javascript: bool,
6060+ pub has_javascript_external: bool,
5761}
58625959-impl Externals {
6363+impl FunctionDefinition {
6064 pub fn exists(&self, target: Target) -> bool {
6165 match target {
6262- Target::Erlang => self.erlang,
6363- Target::JavaScript => self.javascript,
6666+ Target::Erlang => self.has_erlang_external,
6767+ Target::JavaScript => self.has_javascript_external,
6468 }
6569 }
6670}
···6973 /// Given the implementations of a function update those with taking into
7074 /// account the `implementations` of another function (or constant) used
7175 /// inside its body.
7272- pub fn update_from_use(&mut self, implementations: &Implementations) {
7676+ pub fn update_from_use(
7777+ &mut self,
7878+ implementations: &Implementations,
7979+ current_function_definition: &FunctionDefinition,
8080+ ) {
7381 // With this pattern matching we won't forget to deal with new targets
7482 // when those are added :)
7583 let Implementations {
7684 gleam,
7785 uses_erlang_externals,
7886 uses_javascript_externals,
8787+ can_run_on_erlang,
8888+ can_run_on_javascript,
7989 } = implementations;
9090+ let FunctionDefinition {
9191+ has_body: _,
9292+ has_erlang_external,
9393+ has_javascript_external,
9494+ } = current_function_definition;
80958196 // If a pure-Gleam function uses a function that doesn't have a pure
8297 // Gleam implementation, then it's no longer pure-Gleam.
8398 self.gleam = self.gleam && *gleam;
9999+100100+ // A function can run on a target if the code that it uses can run on on
101101+ // the same target,
102102+ self.can_run_on_erlang =
103103+ *has_erlang_external || (self.can_run_on_erlang && (*gleam || *can_run_on_erlang));
104104+ self.can_run_on_javascript = *has_javascript_external
105105+ || (self.can_run_on_javascript && (*gleam || *can_run_on_javascript));
8410685107 // If a function uses a function that relies on external code (be it
86108 // javascript or erlang) then it's considered as using external code as
···112134 pub fn supports(&self, target: Target) -> bool {
113135 self.gleam
114136 || match target {
115115- Target::Erlang => self.uses_erlang_externals,
116116- Target::JavaScript => self.uses_javascript_externals,
137137+ Target::Erlang => self.can_run_on_erlang,
138138+ Target::JavaScript => self.can_run_on_javascript,
117139 }
118140 }
119141}
···123145 pub(crate) environment: &'a mut Environment<'b>,
124146125147 pub(crate) implementations: Implementations,
126126- pub(crate) current_function_externals: Externals,
148148+ pub(crate) current_function_definition: FunctionDefinition,
127149128150 // Type hydrator for creating types from annotations
129151 pub(crate) hydrator: Hydrator,
130152}
131153132154impl<'a, 'b> ExprTyper<'a, 'b> {
133133- pub fn new(environment: &'a mut Environment<'b>, externals: Externals) -> Self {
155155+ pub fn new(environment: &'a mut Environment<'b>, definition: FunctionDefinition) -> Self {
134156 let mut hydrator = Hydrator::new();
135157136158 let implementations = Implementations {
137159 // We start assuming the function is pure Gleam and narrow it down
138160 // if we run into functions/constants that have only external
139161 // implementations for some of the targets.
140140- gleam: true,
141141- uses_erlang_externals: externals.erlang,
142142- uses_javascript_externals: externals.javascript,
162162+ gleam: definition.has_body,
163163+ can_run_on_erlang: definition.has_body || definition.has_erlang_external,
164164+ can_run_on_javascript: definition.has_body || definition.has_javascript_external,
165165+ uses_erlang_externals: definition.has_erlang_external,
166166+ uses_javascript_externals: definition.has_javascript_external,
143167 };
144168145169 hydrator.permit_holes(true);
···147171 hydrator,
148172 environment,
149173 implementations,
150150- current_function_externals: externals,
174174+ current_function_definition: definition,
151175 }
152176 }
153177···714738 };
715739716740 self.implementations
717717- .update_from_use(variant_implementations);
741741+ .update_from_use(variant_implementations, &self.current_function_definition);
718742719743 if self.environment.target_support.is_enforced()
720744 // If the value used doesn't have an implementation that can be used
···722746 && !variant_implementations.supports(self.environment.target)
723747 // ... and there is not an external implementation for it
724748 && !self
725725- .current_function_externals
749749+ .current_function_definition
726750 .exists(self.environment.target)
727751 {
728752 Err(Error::UnsupportedExpressionTarget {