Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -265,3 +265,7 @@
- Typos in the error message shown when trying to install a non-existent package
have been fixed.
([Ioan Clarke](https://github.com/ioanclarke))

- Fixed a bug where the compiler would generate invalid Erlang and TypeScript
code for unused opaque types referencing private types.
([Surya Rose](https://github.com/GearsDatapacks))
7 changes: 0 additions & 7 deletions compiler-core/src/erlang.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,6 @@ fn module_document<'a>(
&mut type_defs,
&module.name,
&overridden_publicity,
&module.unused_definition_positions,
);
}

Expand Down Expand Up @@ -303,13 +302,7 @@ fn register_imports_and_exports(
type_defs: &mut Vec<Document<'_>>,
module_name: &str,
overridden_publicity: &im::HashSet<EcoString>,
unused_definition_positions: &HashSet<u32>,
) {
// Do not generate any code for unused items
if unused_definition_positions.contains(&definition.location().start) {
return;
}

match definition {
Definition::Function(Function {
publicity,
Expand Down
16 changes: 16 additions & 0 deletions compiler-core/src/erlang/tests/custom_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,19 @@ pub fn get(dict: Dict(key, value), key: key) -> Result(value, Nil)
"#
);
}

// https://github.com/gleam-lang/gleam/issues/5127
#[test]
fn unused_opaque_constructor_is_generated_correctly() {
assert_erl!(
"
type Wibble {
Wibble
}
pub opaque type Wobble {
Wobble(Wibble)
}
"
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
source: compiler-core/src/erlang/tests/custom_types.rs
expression: "\ntype Wibble {\n Wibble\n}\n\npub opaque type Wobble {\n Wobble(Wibble)\n}\n"
---
----- SOURCE CODE

type Wibble {
Wibble
}

pub opaque type Wobble {
Wobble(Wibble)
}


----- COMPILED ERLANG
-module(my@mod).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "project/test/my/mod.gleam").
-export_type([wibble/0, wobble/0]).

-type wibble() :: wibble.

-opaque wobble() :: {wobble, wibble()}.
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,14 @@ pub fn main(x: Int) -> Int {
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "project/test/my/mod.gleam").
-export([main/1]).
-export_type([a/0]).
-export_type([a/0, b/0, c/0]).

-type a() :: {a, integer()}.

-type b() :: {b, binary()}.

-type c() :: {c, integer()}.

-file("project/test/my/mod.gleam", 5).
-spec main(integer()) -> integer().
main(X) ->
Expand Down
16 changes: 16 additions & 0 deletions compiler-core/src/javascript/tests/custom_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -960,3 +960,19 @@ pub fn get(dict: Dict(key, value), key: key) -> Result(value, Nil)
"#
);
}

// https://github.com/gleam-lang/gleam/issues/5127
#[test]
fn unused_opaque_constructor_is_generated_correctly() {
assert_ts_def!(
"
type Wibble {
Wibble
}
pub opaque type Wobble {
Wobble(Wibble)
}
"
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
source: compiler-core/src/javascript/tests/custom_types.rs
expression: "\ntype Wibble {\n Wibble\n}\n\npub opaque type Wobble {\n Wobble(Wibble)\n}\n"
---
----- SOURCE CODE

type Wibble {
Wibble
}

pub opaque type Wobble {
Wobble(Wibble)
}


----- TYPESCRIPT DEFINITIONS
import type * as _ from "../gleam.d.mts";

declare class Wibble extends _.CustomType {}

type Wibble$ = Wibble;

declare class Wobble extends _.CustomType {
/** @deprecated */
constructor(argument$0: Wibble$);
/** @deprecated */
0: Wibble$;
}

export type Wobble$ = Wobble;
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ pub opaque type OpaqueType {
----- TYPESCRIPT DEFINITIONS
import type * as _ from "../gleam.d.mts";

declare class PrivateType extends _.CustomType {}

type PrivateType$ = PrivateType;

declare class OpaqueType extends _.CustomType {
/** @deprecated */
constructor(argument$0: PrivateType$);
Expand Down
54 changes: 22 additions & 32 deletions compiler-core/src/javascript/typescript.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
//! <https://www.typescriptlang.org/>
//! <https://www.typescriptlang.org/docs/handbook/declaration-files/introduction.html>

use crate::ast::{AssignName, Publicity, SrcSpan};
use crate::ast::{AssignName, Publicity, TypedCustomType};
use crate::javascript::import::Member;
use crate::type_::{PRELUDE_MODULE_NAME, RecordAccessor, is_prelude_module};
use crate::{
Expand Down Expand Up @@ -380,23 +380,7 @@ impl<'a> TypeScriptGenerator<'a> {

Definition::Import(Import { .. }) => vec![],

Definition::CustomType(CustomType {
publicity,
constructors,
opaque,
name,
typed_parameters,
external_javascript,
..
}) if publicity.is_importable() => self.custom_type_definition(
name,
typed_parameters,
constructors,
*opaque,
external_javascript,
imports,
),
Definition::CustomType(CustomType { .. }) => vec![],
Definition::CustomType(type_) => self.custom_type_definition(type_, imports),

Definition::ModuleConstant(ModuleConstant {
publicity,
Expand Down Expand Up @@ -439,15 +423,21 @@ impl<'a> TypeScriptGenerator<'a> {
///
fn custom_type_definition(
&mut self,
name: &'a str,
typed_parameters: &'a [Arc<Type>],
constructors: &'a [TypedRecordConstructor],
opaque: bool,
external: &'a Option<(EcoString, EcoString, SrcSpan)>,
type_: &'a TypedCustomType,
imports: &mut Imports<'_>,
) -> Vec<Document<'a>> {
let CustomType {
publicity,
constructors,
opaque,
name,
typed_parameters,
external_javascript,
..
} = type_;

// Constructors for opaque and private types are not exported
let constructor_publicity = if opaque {
let constructor_publicity = if publicity.is_private() || *opaque {
Publicity::Private
} else {
Publicity::Public
Expand All @@ -469,7 +459,7 @@ impl<'a> TypeScriptGenerator<'a> {
.collect_vec();

let definition = if constructors.is_empty() {
if let Some((module, external_name, _location)) = external {
if let Some((module, external_name, _location)) = external_javascript {
let member = Member {
name: external_name.to_doc(),
alias: Some(eco_format!("{name}$").to_doc()),
Expand All @@ -491,13 +481,13 @@ impl<'a> TypeScriptGenerator<'a> {
join(constructors, break_("| ", " | "))
};

definitions.push(docvec![
"export type ",
type_name.clone(),
" = ",
definition,
";",
]);
let head = if publicity.is_private() {
"type "
} else {
"export type "
};

definitions.push(docvec![head, type_name.clone(), " = ", definition, ";",]);

// Generate getters for fields shared between variants
if let Some(accessors_map) = self.module.type_info.accessors.get(name)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ expression: "./cases/import_shadowed_name_warning"
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/two.gleam").
-export([use_type/1]).
-export_type([shadowing/0]).

-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
Expand All @@ -47,6 +48,8 @@ expression: "./cases/import_shadowed_name_warning"

?MODULEDOC(" https://github.com/gleam-lang/otp/pull/22\n").

-type shadowing() :: port.

-file("src/two.gleam", 14).
-spec use_type(one:port_()) -> nil.
use_type(Port) ->
Expand Down
Loading