Skip to content

Commit

Permalink
Ban import=require and export= under erasableSyntaxOnly (#61175)
Browse files Browse the repository at this point in the history
  • Loading branch information
jakebailey authored Feb 14, 2025
1 parent 6af21a4 commit 0f4737e
Show file tree
Hide file tree
Showing 10 changed files with 341 additions and 89 deletions.
8 changes: 5 additions & 3 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47830,11 +47830,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}

checkGrammarModifiers(node);
const isImportEquals = isInternalModuleImportEqualsDeclaration(node);
if (compilerOptions.erasableSyntaxOnly && isImportEquals && !(node.flags & NodeFlags.Ambient)) {
if (compilerOptions.erasableSyntaxOnly && !(node.flags & NodeFlags.Ambient)) {
error(node, Diagnostics.This_syntax_is_not_allowed_when_erasableSyntaxOnly_is_enabled);
}
if (isImportEquals || checkExternalImportOrExportDeclaration(node)) {
if (isInternalModuleImportEqualsDeclaration(node) || checkExternalImportOrExportDeclaration(node)) {
checkImportBinding(node);
markLinkedReferences(node, ReferenceHint.ExportImportEquals);
if (node.moduleReference.kind !== SyntaxKind.ExternalModuleReference) {
Expand Down Expand Up @@ -47975,6 +47974,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return;
}

if (compilerOptions.erasableSyntaxOnly && !(node.flags & NodeFlags.Ambient)) {
error(node, Diagnostics.This_syntax_is_not_allowed_when_erasableSyntaxOnly_is_enabled);
}
const container = node.parent.kind === SyntaxKind.SourceFile ? node.parent : node.parent.parent as ModuleDeclaration;
if (container.kind === SyntaxKind.ModuleDeclaration && !isAmbientModule(container)) {
if (node.isExportEquals) {
Expand Down
33 changes: 24 additions & 9 deletions tests/baselines/reference/erasableSyntaxOnly.errors.txt
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
erasableSyntaxOnly.ts(3,17): error TS1294: This syntax is not allowed when 'erasableSyntaxOnly' is enabled.
erasableSyntaxOnly.ts(6,11): error TS1294: This syntax is not allowed when 'erasableSyntaxOnly' is enabled.
erasableSyntaxOnly.ts(10,11): error TS1294: This syntax is not allowed when 'erasableSyntaxOnly' is enabled.
erasableSyntaxOnly.ts(16,11): error TS1294: This syntax is not allowed when 'erasableSyntaxOnly' is enabled.
erasableSyntaxOnly.ts(17,15): error TS1294: This syntax is not allowed when 'erasableSyntaxOnly' is enabled.
erasableSyntaxOnly.ts(22,6): error TS1294: This syntax is not allowed when 'erasableSyntaxOnly' is enabled.
erasableSyntaxOnly.ts(26,1): error TS1294: This syntax is not allowed when 'erasableSyntaxOnly' is enabled.
erasableSyntaxOnly.ts(28,12): error TS1294: This syntax is not allowed when 'erasableSyntaxOnly' is enabled.
commonjs.cts(1,1): error TS1294: This syntax is not allowed when 'erasableSyntaxOnly' is enabled.
commonjs.cts(2,1): error TS1294: This syntax is not allowed when 'erasableSyntaxOnly' is enabled.
index.ts(3,17): error TS1294: This syntax is not allowed when 'erasableSyntaxOnly' is enabled.
index.ts(6,11): error TS1294: This syntax is not allowed when 'erasableSyntaxOnly' is enabled.
index.ts(10,11): error TS1294: This syntax is not allowed when 'erasableSyntaxOnly' is enabled.
index.ts(16,11): error TS1294: This syntax is not allowed when 'erasableSyntaxOnly' is enabled.
index.ts(17,15): error TS1294: This syntax is not allowed when 'erasableSyntaxOnly' is enabled.
index.ts(22,6): error TS1294: This syntax is not allowed when 'erasableSyntaxOnly' is enabled.
index.ts(26,1): error TS1294: This syntax is not allowed when 'erasableSyntaxOnly' is enabled.
index.ts(28,12): error TS1294: This syntax is not allowed when 'erasableSyntaxOnly' is enabled.


==== erasableSyntaxOnly.ts (8 errors) ====
==== index.ts (8 errors) ====
class MyClassErr {
// No parameter properties
constructor(public foo: string) { }
Expand Down Expand Up @@ -89,4 +91,17 @@ erasableSyntaxOnly.ts(28,12): error TS1294: This syntax is not allowed when 'era

import FineAlias = EnumInAmbientContext.B;
}

==== commonjs.cts (2 errors) ====
import foo = require("./other.cjs");
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS1294: This syntax is not allowed when 'erasableSyntaxOnly' is enabled.
export = foo;
~~~~~~~~~~~~~
!!! error TS1294: This syntax is not allowed when 'erasableSyntaxOnly' is enabled.


==== other.d.cts (0 errors) ====
declare function foo(): void;
export = foo;

121 changes: 121 additions & 0 deletions tests/baselines/reference/erasableSyntaxOnly.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
//// [tests/cases/compiler/erasableSyntaxOnly.ts] ////

//// [index.ts]
class MyClassErr {
// No parameter properties
constructor(public foo: string) { }
}

namespace IllegalBecauseInstantiated {
export const m = 1;
}

namespace AlsoIllegalBecauseInstantiated {
class PrivateClass {

}
}

namespace IllegalBecauseNestedInstantiated {
namespace Nested {
export const m = 1;
}
}

enum NotLegalEnum {
B = 1
}

import NoGoodAlias = NotLegalEnum.B;

const enum NotLegalConstEnum {
C = 2
}

// No errors after this point
class MyClassOk {
// Not a parameter property, ok
constructor(foo: string) { }
}

// Note for implementors: This should not be an error
// as this entire namespace block is fully erased
namespace NotInstantiated {
export interface JustAType { }
export type ATypeInANamespace = {};
namespace Nested {
export type ATypeInANamespace = {};
}
}
declare namespace AmbientIsNotInstantiated {
export const stillOk = 12;
}

declare enum LegalEnum {
A = 1
}

declare namespace AmbientStuff {
namespace Nested {
export const stillOk = 12;
}
enum EnumInAmbientContext {
B = 1
}

import FineAlias = EnumInAmbientContext.B;
}

//// [commonjs.cts]
import foo = require("./other.cjs");
export = foo;


//// [other.d.cts]
declare function foo(): void;
export = foo;


//// [index.js]
var MyClassErr = /** @class */ (function () {
// No parameter properties
function MyClassErr(foo) {
this.foo = foo;
}
return MyClassErr;
}());
var IllegalBecauseInstantiated;
(function (IllegalBecauseInstantiated) {
IllegalBecauseInstantiated.m = 1;
})(IllegalBecauseInstantiated || (IllegalBecauseInstantiated = {}));
var AlsoIllegalBecauseInstantiated;
(function (AlsoIllegalBecauseInstantiated) {
var PrivateClass = /** @class */ (function () {
function PrivateClass() {
}
return PrivateClass;
}());
})(AlsoIllegalBecauseInstantiated || (AlsoIllegalBecauseInstantiated = {}));
var IllegalBecauseNestedInstantiated;
(function (IllegalBecauseNestedInstantiated) {
var Nested;
(function (Nested) {
Nested.m = 1;
})(Nested || (Nested = {}));
})(IllegalBecauseNestedInstantiated || (IllegalBecauseNestedInstantiated = {}));
var NotLegalEnum;
(function (NotLegalEnum) {
NotLegalEnum[NotLegalEnum["B"] = 1] = "B";
})(NotLegalEnum || (NotLegalEnum = {}));
var NoGoodAlias = NotLegalEnum.B;
// No errors after this point
var MyClassOk = /** @class */ (function () {
// Not a parameter property, ok
function MyClassOk(foo) {
}
return MyClassOk;
}());
//// [commonjs.cjs]
"use strict";
var foo = require("./other.cjs");
module.exports = foo;
87 changes: 51 additions & 36 deletions tests/baselines/reference/erasableSyntaxOnly.symbols
Original file line number Diff line number Diff line change
@@ -1,120 +1,135 @@
//// [tests/cases/compiler/erasableSyntaxOnly.ts] ////

=== erasableSyntaxOnly.ts ===
=== index.ts ===
class MyClassErr {
>MyClassErr : Symbol(MyClassErr, Decl(erasableSyntaxOnly.ts, 0, 0))
>MyClassErr : Symbol(MyClassErr, Decl(index.ts, 0, 0))

// No parameter properties
constructor(public foo: string) { }
>foo : Symbol(MyClassErr.foo, Decl(erasableSyntaxOnly.ts, 2, 16))
>foo : Symbol(MyClassErr.foo, Decl(index.ts, 2, 16))
}

namespace IllegalBecauseInstantiated {
>IllegalBecauseInstantiated : Symbol(IllegalBecauseInstantiated, Decl(erasableSyntaxOnly.ts, 3, 1))
>IllegalBecauseInstantiated : Symbol(IllegalBecauseInstantiated, Decl(index.ts, 3, 1))

export const m = 1;
>m : Symbol(m, Decl(erasableSyntaxOnly.ts, 6, 16))
>m : Symbol(m, Decl(index.ts, 6, 16))
}

namespace AlsoIllegalBecauseInstantiated {
>AlsoIllegalBecauseInstantiated : Symbol(AlsoIllegalBecauseInstantiated, Decl(erasableSyntaxOnly.ts, 7, 1))
>AlsoIllegalBecauseInstantiated : Symbol(AlsoIllegalBecauseInstantiated, Decl(index.ts, 7, 1))

class PrivateClass {
>PrivateClass : Symbol(PrivateClass, Decl(erasableSyntaxOnly.ts, 9, 42))
>PrivateClass : Symbol(PrivateClass, Decl(index.ts, 9, 42))

}
}

namespace IllegalBecauseNestedInstantiated {
>IllegalBecauseNestedInstantiated : Symbol(IllegalBecauseNestedInstantiated, Decl(erasableSyntaxOnly.ts, 13, 1))
>IllegalBecauseNestedInstantiated : Symbol(IllegalBecauseNestedInstantiated, Decl(index.ts, 13, 1))

namespace Nested {
>Nested : Symbol(Nested, Decl(erasableSyntaxOnly.ts, 15, 44))
>Nested : Symbol(Nested, Decl(index.ts, 15, 44))

export const m = 1;
>m : Symbol(m, Decl(erasableSyntaxOnly.ts, 17, 20))
>m : Symbol(m, Decl(index.ts, 17, 20))
}
}

enum NotLegalEnum {
>NotLegalEnum : Symbol(NotLegalEnum, Decl(erasableSyntaxOnly.ts, 19, 1))
>NotLegalEnum : Symbol(NotLegalEnum, Decl(index.ts, 19, 1))

B = 1
>B : Symbol(NoGoodAlias, Decl(erasableSyntaxOnly.ts, 21, 19))
>B : Symbol(NoGoodAlias, Decl(index.ts, 21, 19))
}

import NoGoodAlias = NotLegalEnum.B;
>NoGoodAlias : Symbol(NoGoodAlias, Decl(erasableSyntaxOnly.ts, 23, 1))
>NotLegalEnum : Symbol(NotLegalEnum, Decl(erasableSyntaxOnly.ts, 19, 1))
>B : Symbol(NoGoodAlias, Decl(erasableSyntaxOnly.ts, 21, 19))
>NoGoodAlias : Symbol(NoGoodAlias, Decl(index.ts, 23, 1))
>NotLegalEnum : Symbol(NotLegalEnum, Decl(index.ts, 19, 1))
>B : Symbol(NoGoodAlias, Decl(index.ts, 21, 19))

const enum NotLegalConstEnum {
>NotLegalConstEnum : Symbol(NotLegalConstEnum, Decl(erasableSyntaxOnly.ts, 25, 36))
>NotLegalConstEnum : Symbol(NotLegalConstEnum, Decl(index.ts, 25, 36))

C = 2
>C : Symbol(NotLegalConstEnum.C, Decl(erasableSyntaxOnly.ts, 27, 30))
>C : Symbol(NotLegalConstEnum.C, Decl(index.ts, 27, 30))
}

// No errors after this point
class MyClassOk {
>MyClassOk : Symbol(MyClassOk, Decl(erasableSyntaxOnly.ts, 29, 1))
>MyClassOk : Symbol(MyClassOk, Decl(index.ts, 29, 1))

// Not a parameter property, ok
constructor(foo: string) { }
>foo : Symbol(foo, Decl(erasableSyntaxOnly.ts, 34, 16))
>foo : Symbol(foo, Decl(index.ts, 34, 16))
}

// Note for implementors: This should not be an error
// as this entire namespace block is fully erased
namespace NotInstantiated {
>NotInstantiated : Symbol(NotInstantiated, Decl(erasableSyntaxOnly.ts, 35, 1))
>NotInstantiated : Symbol(NotInstantiated, Decl(index.ts, 35, 1))

export interface JustAType { }
>JustAType : Symbol(JustAType, Decl(erasableSyntaxOnly.ts, 39, 27))
>JustAType : Symbol(JustAType, Decl(index.ts, 39, 27))

export type ATypeInANamespace = {};
>ATypeInANamespace : Symbol(ATypeInANamespace, Decl(erasableSyntaxOnly.ts, 40, 34))
>ATypeInANamespace : Symbol(ATypeInANamespace, Decl(index.ts, 40, 34))

namespace Nested {
>Nested : Symbol(Nested, Decl(erasableSyntaxOnly.ts, 41, 39))
>Nested : Symbol(Nested, Decl(index.ts, 41, 39))

export type ATypeInANamespace = {};
>ATypeInANamespace : Symbol(ATypeInANamespace, Decl(erasableSyntaxOnly.ts, 42, 22))
>ATypeInANamespace : Symbol(ATypeInANamespace, Decl(index.ts, 42, 22))
}
}
declare namespace AmbientIsNotInstantiated {
>AmbientIsNotInstantiated : Symbol(AmbientIsNotInstantiated, Decl(erasableSyntaxOnly.ts, 45, 1))
>AmbientIsNotInstantiated : Symbol(AmbientIsNotInstantiated, Decl(index.ts, 45, 1))

export const stillOk = 12;
>stillOk : Symbol(stillOk, Decl(erasableSyntaxOnly.ts, 47, 16))
>stillOk : Symbol(stillOk, Decl(index.ts, 47, 16))
}

declare enum LegalEnum {
>LegalEnum : Symbol(LegalEnum, Decl(erasableSyntaxOnly.ts, 48, 1))
>LegalEnum : Symbol(LegalEnum, Decl(index.ts, 48, 1))

A = 1
>A : Symbol(LegalEnum.A, Decl(erasableSyntaxOnly.ts, 50, 24))
>A : Symbol(LegalEnum.A, Decl(index.ts, 50, 24))
}

declare namespace AmbientStuff {
>AmbientStuff : Symbol(AmbientStuff, Decl(erasableSyntaxOnly.ts, 52, 1))
>AmbientStuff : Symbol(AmbientStuff, Decl(index.ts, 52, 1))

namespace Nested {
>Nested : Symbol(Nested, Decl(erasableSyntaxOnly.ts, 54, 32))
>Nested : Symbol(Nested, Decl(index.ts, 54, 32))

export const stillOk = 12;
>stillOk : Symbol(stillOk, Decl(erasableSyntaxOnly.ts, 56, 20))
>stillOk : Symbol(stillOk, Decl(index.ts, 56, 20))
}
enum EnumInAmbientContext {
>EnumInAmbientContext : Symbol(EnumInAmbientContext, Decl(erasableSyntaxOnly.ts, 57, 5))
>EnumInAmbientContext : Symbol(EnumInAmbientContext, Decl(index.ts, 57, 5))

B = 1
>B : Symbol(FineAlias, Decl(erasableSyntaxOnly.ts, 58, 31))
>B : Symbol(FineAlias, Decl(index.ts, 58, 31))
}

import FineAlias = EnumInAmbientContext.B;
>FineAlias : Symbol(FineAlias, Decl(erasableSyntaxOnly.ts, 60, 5))
>EnumInAmbientContext : Symbol(EnumInAmbientContext, Decl(erasableSyntaxOnly.ts, 57, 5))
>B : Symbol(FineAlias, Decl(erasableSyntaxOnly.ts, 58, 31))
>FineAlias : Symbol(FineAlias, Decl(index.ts, 60, 5))
>EnumInAmbientContext : Symbol(EnumInAmbientContext, Decl(index.ts, 57, 5))
>B : Symbol(FineAlias, Decl(index.ts, 58, 31))
}

=== commonjs.cts ===
import foo = require("./other.cjs");
>foo : Symbol(foo, Decl(commonjs.cts, 0, 0))

export = foo;
>foo : Symbol(foo, Decl(commonjs.cts, 0, 0))


=== other.d.cts ===
declare function foo(): void;
>foo : Symbol(foo, Decl(other.d.cts, 0, 0))

export = foo;
>foo : Symbol(foo, Decl(other.d.cts, 0, 0))

21 changes: 20 additions & 1 deletion tests/baselines/reference/erasableSyntaxOnly.types
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//// [tests/cases/compiler/erasableSyntaxOnly.ts] ////

=== erasableSyntaxOnly.ts ===
=== index.ts ===
class MyClassErr {
>MyClassErr : MyClassErr
> : ^^^^^^^^^^
Expand Down Expand Up @@ -160,3 +160,22 @@ declare namespace AmbientStuff {
> : ^^^^^^^^^^^^^^^^^^^^^^
}

=== commonjs.cts ===
import foo = require("./other.cjs");
>foo : () => void
> : ^^^^^^

export = foo;
>foo : () => void
> : ^^^^^^


=== other.d.cts ===
declare function foo(): void;
>foo : () => void
> : ^^^^^^

export = foo;
>foo : () => void
> : ^^^^^^

Loading

0 comments on commit 0f4737e

Please sign in to comment.