Skip to content

Commit

Permalink
Error if type node uses inaccessible type in isolated declarations (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
dragomirtitian committed May 22, 2024
1 parent f2aebff commit 8537bb7
Show file tree
Hide file tree
Showing 8 changed files with 190 additions and 17 deletions.
6 changes: 6 additions & 0 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6085,6 +6085,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return result;
}
}
context.tracker.reportInferenceFallback(existing);
return undefined;
}

Expand Down Expand Up @@ -8301,6 +8302,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
// If the symbol is found both in declaration scope and in current scope then it shoudl point to the same reference
(symAtLocation && sym && !getSymbolIfSameReference(getExportSymbolOfValueSymbolIfExported(symAtLocation), sym))
) {
// In isolated declaration we will not do rest parameter expansion so there is no need to report on these.
if (symAtLocation !== unknownSymbol) {
context.tracker.reportInferenceFallback(node);
}
introducesError = true;
return { introducesError, node, sym };
}
Expand All @@ -8321,6 +8326,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
!isDeclarationName(node) &&
isSymbolAccessible(sym, context.enclosingDeclaration, meaning, /*shouldComputeAliasesToMakeVisible*/ false).accessibility !== SymbolAccessibility.Accessible
) {
context.tracker.reportInferenceFallback(node);
introducesError = true;
}
else {
Expand Down
4 changes: 4 additions & 0 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -7018,6 +7018,10 @@
"category": "Error",
"code": 9038
},
"Type containing private name '{0}' can't be used with --isolatedDeclarations.": {
"category": "Error",
"code": 9039
},
"JSX attributes must only be assigned a non-empty 'expression'.": {
"category": "Error",
"code": 17000
Expand Down
52 changes: 36 additions & 16 deletions src/compiler/transformers/declarations/diagnostics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@ import {
DiagnosticWithLocation,
ElementAccessExpression,
EmitResolver,
EntityNameOrEntityNameExpression,
ExportAssignment,
Expression,
ExpressionWithTypeArguments,
findAncestor,
FunctionDeclaration,
FunctionExpression,
FunctionLikeDeclaration,
GetAccessorDeclaration,
getAllAccessorDeclarations,
getNameOfDeclaration,
Expand All @@ -40,9 +42,12 @@ import {
isConstructorDeclaration,
isConstructSignatureDeclaration,
isElementAccessExpression,
isEntityName,
isEntityNameExpression,
isExportAssignment,
isExpressionWithTypeArguments,
isFunctionDeclaration,
isFunctionLikeDeclaration,
isGetAccessor,
isHeritageClause,
isImportEqualsDeclaration,
Expand All @@ -53,15 +58,18 @@ import {
isParameter,
isParameterPropertyDeclaration,
isParenthesizedExpression,
isPartOfTypeNode,
isPropertyAccessExpression,
isPropertyDeclaration,
isPropertySignature,
isReturnStatement,
isSetAccessor,
isStatement,
isStatic,
isTypeAliasDeclaration,
isTypeAssertionExpression,
isTypeParameterDeclaration,
isTypeQueryNode,
isVariableDeclaration,
JSDocCallbackTag,
JSDocEnumTag,
Expand Down Expand Up @@ -658,6 +666,9 @@ export function createGetIsolatedDeclarationErrors(resolver: EmitResolver) {
if (heritageClause) {
return createDiagnosticForNode(node, Diagnostics.Extends_clause_can_t_contain_an_expression_with_isolatedDeclarations);
}
if ((isPartOfTypeNode(node) || isTypeQueryNode(node.parent)) && (isEntityName(node) || isEntityNameExpression(node))) {
return createEntityInTypeNodeError(node);
}
Debug.type<WithIsolatedDeclarationDiagnostic>(node);
switch (node.kind) {
case SyntaxKind.GetAccessor:
Expand Down Expand Up @@ -694,8 +705,15 @@ export function createGetIsolatedDeclarationErrors(resolver: EmitResolver) {
}

function findNearestDeclaration(node: Node) {
const result = findAncestor(node, n => isExportAssignment(n) || (isStatement(n) ? "quit" : isVariableDeclaration(n) || isPropertyDeclaration(n) || isParameter(n)));
return result as VariableDeclaration | PropertyDeclaration | ParameterDeclaration | ExportAssignment | undefined;
const result = findAncestor(node, n => isExportAssignment(n) || isStatement(n) || isVariableDeclaration(n) || isPropertyDeclaration(n) || isParameter(n));
if (!result) return undefined;

if (isExportAssignment(result)) return result;

if (isReturnStatement(result)) {
return findAncestor(result, (n): n is Exclude<FunctionLikeDeclaration, ConstructorDeclaration> => isFunctionLikeDeclaration(n) && !isConstructorDeclaration(n));
}
return (isStatement(result) ? undefined : result) as VariableDeclaration | PropertyDeclaration | ParameterDeclaration | ExportAssignment | undefined;
}

function createAccessorTypeError(node: GetAccessorDeclaration | SetAccessorDeclaration) {
Expand All @@ -712,31 +730,27 @@ export function createGetIsolatedDeclarationErrors(resolver: EmitResolver) {
}
return diag;
}
function createObjectLiteralError(node: ShorthandPropertyAssignment | SpreadAssignment | ComputedPropertyName) {
const diag = createDiagnosticForNode(node, errorByDeclarationKind[node.kind]);
function addParentDeclarationRelatedInfo(node: Node, diag: DiagnosticWithLocation) {
const parentDeclaration = findNearestDeclaration(node);
if (parentDeclaration) {
const targetStr = isExportAssignment(parentDeclaration) ? "" : getTextOfNode(parentDeclaration.name, /*includeTrivia*/ false);
const targetStr = isExportAssignment(parentDeclaration) || !parentDeclaration.name ? "" : getTextOfNode(parentDeclaration.name, /*includeTrivia*/ false);
addRelatedInfo(diag, createDiagnosticForNode(parentDeclaration, relatedSuggestionByDeclarationKind[parentDeclaration.kind], targetStr));
}
return diag;
}
function createObjectLiteralError(node: ShorthandPropertyAssignment | SpreadAssignment | ComputedPropertyName) {
const diag = createDiagnosticForNode(node, errorByDeclarationKind[node.kind]);
addParentDeclarationRelatedInfo(node, diag);
return diag;
}
function createArrayLiteralError(node: ArrayLiteralExpression | SpreadElement) {
const diag = createDiagnosticForNode(node, errorByDeclarationKind[node.kind]);
const parentDeclaration = findNearestDeclaration(node);
if (parentDeclaration) {
const targetStr = isExportAssignment(parentDeclaration) ? "" : getTextOfNode(parentDeclaration.name, /*includeTrivia*/ false);
addRelatedInfo(diag, createDiagnosticForNode(parentDeclaration, relatedSuggestionByDeclarationKind[parentDeclaration.kind], targetStr));
}
addParentDeclarationRelatedInfo(node, diag);
return diag;
}
function createReturnTypeError(node: FunctionDeclaration | FunctionExpression | ArrowFunction | MethodDeclaration | ConstructSignatureDeclaration) {
const diag = createDiagnosticForNode(node, errorByDeclarationKind[node.kind]);
const parentDeclaration = findNearestDeclaration(node);
if (parentDeclaration) {
const targetStr = isExportAssignment(parentDeclaration) ? "" : getTextOfNode(parentDeclaration.name, /*includeTrivia*/ false);
addRelatedInfo(diag, createDiagnosticForNode(parentDeclaration, relatedSuggestionByDeclarationKind[parentDeclaration.kind], targetStr));
}
addParentDeclarationRelatedInfo(node, diag);
addRelatedInfo(diag, createDiagnosticForNode(node, relatedSuggestionByDeclarationKind[node.kind]));
return diag;
}
Expand Down Expand Up @@ -768,12 +782,18 @@ export function createGetIsolatedDeclarationErrors(resolver: EmitResolver) {
function createClassExpressionError(node: Expression) {
return createExpressionError(node, Diagnostics.Inference_from_class_expressions_is_not_supported_with_isolatedDeclarations);
}
function createEntityInTypeNodeError(node: EntityNameOrEntityNameExpression) {
const diag = createDiagnosticForNode(node, Diagnostics.Type_containing_private_name_0_can_t_be_used_with_isolatedDeclarations, getTextOfNode(node, /*includeTrivia*/ false));
addParentDeclarationRelatedInfo(node, diag);
return diag;
}
function createExpressionError(node: Expression, diagnosticMessage?: DiagnosticMessage) {
const parentDeclaration = findNearestDeclaration(node);
let diag: DiagnosticWithLocation;
if (parentDeclaration) {
const targetStr = isExportAssignment(parentDeclaration) ? "" : getTextOfNode(parentDeclaration.name, /*includeTrivia*/ false);
const targetStr = isExportAssignment(parentDeclaration) || !parentDeclaration.name ? "" : getTextOfNode(parentDeclaration.name, /*includeTrivia*/ false);
const parent = findAncestor(node.parent, n => isExportAssignment(n) || (isStatement(n) ? "quit" : !isParenthesizedExpression(n) && !isTypeAssertionExpression(n) && !isAsExpression(n)));

if (parentDeclaration === parent) {
diag = createDiagnosticForNode(node, diagnosticMessage ?? errorByDeclarationKind[parentDeclaration.kind]);
addRelatedInfo(diag, createDiagnosticForNode(parentDeclaration, relatedSuggestionByDeclarationKind[parentDeclaration.kind], targetStr));
Expand Down
4 changes: 3 additions & 1 deletion src/services/codefixes/fixMissingTypeAnnotationOnExports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ import {
isSpreadAssignment,
isSpreadElement,
isStatement,
isTypeNode,
isValueSignatureDeclaration,
isVariableDeclaration,
ModifierFlags,
Expand Down Expand Up @@ -132,6 +133,7 @@ const errorCodes = [
Diagnostics.Only_const_arrays_can_be_inferred_with_isolatedDeclarations.code,
Diagnostics.Assigning_properties_to_functions_without_declaring_them_is_not_supported_with_isolatedDeclarations_Add_an_explicit_declaration_for_the_properties_assigned_to_this_function.code,
Diagnostics.Declaration_emit_for_this_parameter_requires_implicitly_adding_undefined_to_it_s_type_This_is_not_supported_with_isolatedDeclarations.code,
Diagnostics.Type_containing_private_name_0_can_t_be_used_with_isolatedDeclarations.code,
Diagnostics.Add_satisfies_and_a_type_assertion_to_this_expression_satisfies_T_as_T_to_make_the_type_explicit.code,
];

Expand Down Expand Up @@ -352,7 +354,7 @@ function withContext<T>(
return undefined;
}
// No support for typeof in extends clauses
if (isExpressionTarget && findAncestor(targetNode, isHeritageClause)) {
if (isExpressionTarget && (findAncestor(targetNode, isHeritageClause) || findAncestor(targetNode, isTypeNode))) {
return undefined;
}
// Can't inline type spread elements. Whatever you do isolated declarations will not infer from them
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//// [variables.ts] ////
const x = "";
export function one() {
return {} as typeof x;
}

export function two() {
const y = "";
return {} as typeof y;
}

export function three() {
type Z = string;
return {} as Z;
}
//// [variables.d.ts] ////
declare const x = "";
export declare function one(): typeof x;
export declare function two(): "";
export declare function three(): string;
export {};


//// [Diagnostics reported]
variables.ts(8,25): error TS9039: Type containing private name 'y' can't be used with --isolatedDeclarations.
variables.ts(13,18): error TS9039: Type containing private name 'Z' can't be used with --isolatedDeclarations.


==== variables.ts (2 errors) ====
const x = "";
export function one() {
return {} as typeof x;
}

export function two() {
const y = "";
return {} as typeof y;
~
!!! error TS9039: Type containing private name 'y' can't be used with --isolatedDeclarations.
!!! related TS9031 variables.ts:6:17: Add a return type to the function declaration.
}
export function three() {
type Z = string;
return {} as Z;
~
!!! error TS9039: Type containing private name 'Z' can't be used with --isolatedDeclarations.
!!! related TS9031 variables.ts:11:17: Add a return type to the function declaration.
}
27 changes: 27 additions & 0 deletions tests/baselines/reference/transpile/declarationNotInScopeTypes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//// [variables.ts] ////
const x = "";
export function one() {
return {} as typeof x;
}

export function two() {
const y = "";
return {} as typeof y;
}

export function three() {
type Z = string;
return {} as Z;
}
//// [variables.js] ////
const x = "";
export function one() {
return {};
}
export function two() {
const y = "";
return {};
}
export function three() {
return {};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/// <reference path='fourslash.ts'/>

// @isolatedDeclarations: true
// @declaration: true
// @moduleResolution: node
// @target: es2018
// @jsx: react-jsx

////export function two() {
//// const y = "";
//// return {} as typeof y;
////}
////
////export function three() {
//// type Z = string;
//// return {} as Z;
////}

verify.codeFix({
description: "Add return type '\"\"'",
index: 0,
newFileContent:
`export function two(): "" {
const y = "";
return {} as typeof y;
}
export function three() {
type Z = string;
return {} as Z;
}`,
});


verify.codeFix({
description: "Add return type 'string'",
index: 1,
newFileContent:
`export function two() {
const y = "";
return {} as typeof y;
}
export function three(): string {
type Z = string;
return {} as Z;
}`,
});
17 changes: 17 additions & 0 deletions tests/cases/transpile/declarationNotInScopeTypes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// @declaration: true
// @target: es6
// @filename: variables.ts
const x = "";
export function one() {
return {} as typeof x;
}

export function two() {
const y = "";
return {} as typeof y;
}

export function three() {
type Z = string;
return {} as Z;
}

0 comments on commit 8537bb7

Please sign in to comment.