Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement(60881): Added detailed diagnostic for parent to child assignment #61145

Open
wants to merge 24 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
a010044
.
NamHaiBui Jan 31, 2025
3d632b3
new check
NamHaiBui Feb 3, 2025
ef0dd9d
new diagnostic message
NamHaiBui Feb 6, 2025
e16f35f
Merge branch 'main' of https://github.com/microsoft/TypeScript
NamHaiBui Feb 7, 2025
63e6b4c
#60881
NamHaiBui Feb 7, 2025
09022f3
#60881
NamHaiBui Feb 7, 2025
8def683
#60881 Minor typo change
NamHaiBui Feb 7, 2025
ce15fd8
Normalize line endings
NamHaiBui Feb 7, 2025
01e2bfc
Merge branch 'main' of https://github.com/microsoft/TypeScript into 6…
NamHaiBui Feb 7, 2025
85dc004
#60881 reformat
NamHaiBui Feb 7, 2025
47acf44
removed old comments
Alexandrialexie Feb 9, 2025
65fdfc1
generic check before hand
NamHaiBui Feb 10, 2025
4f8eeb6
Merge branch '60881' of https://github.com/SeniorSeminarGroup/TypeScr…
Alexandrialexie Feb 10, 2025
4db251b
new approach and all changed tests reviewed
NamHaiBui Feb 14, 2025
6505632
formatting
NamHaiBui Feb 14, 2025
c0b8e55
Merge branch 'main' of https://github.com/microsoft/TypeScript into 6…
NamHaiBui Feb 14, 2025
d62eed1
Merge branch '60881' of https://github.com/SeniorSeminarGroup/TypeScr…
Alexandrialexie Feb 14, 2025
753d8c1
Merge branch 'main' of https://github.com/microsoft/TypeScript into 6…
NamHaiBui Feb 14, 2025
694b893
Merge branch '60881' of https://github.com/SeniorSeminarGroup/TypeScr…
Alexandrialexie Feb 14, 2025
ef4e281
removed unnecessary comments
Alexandrialexie Feb 14, 2025
dd6ab9a
added more informative test language and extra test case.
RolandLocke Feb 17, 2025
2a56797
added diagnostic message to the 'semantic messages' area in diagnosti…
RolandLocke Feb 17, 2025
a697946
accepted baseline changes
RolandLocke Feb 17, 2025
c662343
Merge branch 'main' of https://github.com/microsoft/TypeScript into 6…
NamHaiBui Feb 19, 2025
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
63 changes: 35 additions & 28 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1331,8 +1331,8 @@ export const enum CheckMode {
SkipGenericFunctions = 1 << 3, // Skip single signature generic functions
IsForSignatureHelp = 1 << 4, // Call resolution for purposes of signature help
RestBindingElement = 1 << 5, // Checking a type that is going to be used to determine the type of a rest binding element
// e.g. in `const { a, ...rest } = foo`, when checking the type of `foo` to determine the type of `rest`,
// we need to preserve generic types instead of substituting them for constraints
// e.g. in `const { a, ...rest } = foo`, when checking the type of `foo` to determine the type of `rest`,
// we need to preserve generic types instead of substituting them for constraints
TypeOnly = 1 << 6, // Called from getTypeOfExpression, diagnostics may be omitted
}

Expand Down Expand Up @@ -3399,7 +3399,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (isEntityNameExpression((node as ExpressionWithTypeArguments).expression)) {
return (node as ExpressionWithTypeArguments).expression as EntityNameExpression;
}
// falls through
// falls through
default:
return undefined;
}
Expand Down Expand Up @@ -5527,7 +5527,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (!isExternalOrCommonJsModule(location as SourceFile)) {
break;
}
// falls through
// falls through
case SyntaxKind.ModuleDeclaration:
const sym = getSymbolOfDeclaration(location as ModuleDeclaration);
// `sym` may not have exports if this module declaration is backed by the symbol for a `const` that's being rewritten
Expand Down Expand Up @@ -9885,7 +9885,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
);
break;
}
// else fall through and treat commonjs require just like import=
// else fall through and treat commonjs require just like import=
case SyntaxKind.ImportEqualsDeclaration:
// This _specifically_ only exists to handle json declarations - where we make aliases, but since
// we emit no declarations for the json document, must not refer to it in the declarations
Expand Down Expand Up @@ -10683,7 +10683,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
// If the binding pattern is empty, this variable declaration is not visible
return false;
}
// falls through
// falls through
case SyntaxKind.ModuleDeclaration:
case SyntaxKind.ClassDeclaration:
case SyntaxKind.InterfaceDeclaration:
Expand Down Expand Up @@ -10716,8 +10716,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
// Private/protected properties/methods are not visible
return false;
}
// Public properties/methods are visible if its parents are visible, so:
// falls through
// Public properties/methods are visible if its parents are visible, so:
// falls through

case SyntaxKind.Constructor:
case SyntaxKind.ConstructSignature:
Expand Down Expand Up @@ -20699,7 +20699,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (!isConstAssertion(node)) {
break;
}
// fallthrough
// fallthrough
case SyntaxKind.JsxExpression:
case SyntaxKind.ParenthesizedExpression:
return elaborateError((node as AsExpression | ParenthesizedExpression | JsxExpression).expression, source, target, relation, headMessage, containingMessageChain, errorOutputContainer);
Expand Down Expand Up @@ -21965,6 +21965,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
typeToString(constraint),
);
}
else if ((source.flags & TypeFlags.TypeParameter) && (isTypeAssignableTo(target, getBaseConstraintOrType(generalizedSource)) || (needsOriginalSource = isTypeAssignableTo(target, getBaseConstraintOrType(source))))) {
reportError(
Diagnostics._1_is_constrained_to_be_a_subtype_of_0,
needsOriginalSource ? sourceType : generalizedSourceType,
targetType,
);
}
else {
errorInfo = undefined;
reportError(
Expand Down Expand Up @@ -27012,7 +27019,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (isCallExpression(node.parent)) {
return Diagnostics.Cannot_find_name_0_Did_you_mean_to_write_this_in_an_async_function;
}
// falls through
// falls through
default:
if (node.parent.kind === SyntaxKind.ShorthandPropertyAssignment) {
return Diagnostics.No_value_exists_in_scope_for_the_shorthand_property_0_Either_declare_one_or_provide_an_initializer;
Expand Down Expand Up @@ -27054,7 +27061,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
const symbol = getResolvedSymbol(node as Identifier);
return symbol !== unknownSymbol ? `${flowContainer ? getNodeId(flowContainer) : "-1"}|${getTypeId(declaredType)}|${getTypeId(initialType)}|${getSymbolId(symbol)}` : undefined;
}
// falls through
// falls through
case SyntaxKind.ThisKeyword:
return `0|${flowContainer ? getNodeId(flowContainer) : "-1"}|${getTypeId(declaredType)}|${getTypeId(initialType)}`;
case SyntaxKind.NonNullExpression:
Expand Down Expand Up @@ -29443,7 +29450,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
}
}
// falls through
// falls through
case SyntaxKind.ThisKeyword:
case SyntaxKind.SuperKeyword:
case SyntaxKind.PropertyAccessExpression:
Expand Down Expand Up @@ -39144,15 +39151,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
hasError = true;
break;
}
// fallthrough
// fallthrough
case ModuleKind.ES2022:
case ModuleKind.ESNext:
case ModuleKind.Preserve:
case ModuleKind.System:
if (languageVersion >= ScriptTarget.ES2017) {
break;
}
// fallthrough
// fallthrough
default:
span ??= getSpanOfTokenAtPosition(sourceFile, node.pos);
const message = isAwaitExpression(node) ? Diagnostics.Top_level_await_expressions_are_only_allowed_when_the_module_option_is_set_to_es2022_esnext_system_node16_node18_nodenext_or_preserve_and_the_target_option_is_set_to_es2017_or_higher :
Expand Down Expand Up @@ -41087,7 +41094,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if ((node as CallExpression).expression.kind === SyntaxKind.ImportKeyword) {
return checkImportCallExpression(node as ImportCall);
}
// falls through
// falls through
case SyntaxKind.NewExpression:
return checkCallExpression(node as CallExpression, checkMode);
case SyntaxKind.TaggedTemplateExpression:
Expand Down Expand Up @@ -41548,7 +41555,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (useDefineForClassFields) {
break;
}
// fall through
// fall through
case "prototype":
const message = Diagnostics.Static_property_0_conflicts_with_built_in_property_Function_0_of_constructor_function_1;
const className = getNameOfSymbolAsWritten(getSymbolOfDeclaration(node));
Expand Down Expand Up @@ -43154,7 +43161,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
headMessage = Diagnostics.Decorator_function_return_type_0_is_not_assignable_to_type_1;
break;
}
// falls through
// falls through

case SyntaxKind.Parameter:
headMessage = Diagnostics.Decorator_function_return_type_is_0_but_is_expected_to_be_void_or_any;
Expand Down Expand Up @@ -47404,7 +47411,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
case SyntaxKind.ImportEqualsDeclaration:
// import a = e.x; in module augmentation is ok, but not import a = require('fs)
if (isInternalModuleImportEqualsDeclaration(node)) break;
// falls through
// falls through
case SyntaxKind.ImportDeclaration:
grammarErrorOnFirstToken(node, Diagnostics.Imports_are_not_permitted_in_module_augmentations_Consider_moving_them_to_the_enclosing_external_module);
break;
Expand All @@ -47418,7 +47425,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
break;
}
// falls through
// falls through
case SyntaxKind.ClassDeclaration:
case SyntaxKind.EnumDeclaration:
case SyntaxKind.FunctionDeclaration:
Expand Down Expand Up @@ -48290,7 +48297,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return checkJSDocPropertyTag(node as JSDocPropertyTag);
case SyntaxKind.JSDocFunctionType:
checkJSDocFunctionType(node as JSDocFunctionType);
// falls through
// falls through
case SyntaxKind.JSDocNonNullableType:
case SyntaxKind.JSDocNullableType:
case SyntaxKind.JSDocAllType:
Expand Down Expand Up @@ -48816,7 +48823,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
switch (location.kind) {
case SyntaxKind.SourceFile:
if (!isExternalModule(location as SourceFile)) break;
// falls through
// falls through
case SyntaxKind.ModuleDeclaration:
copyLocallyVisibleExportSymbols(getSymbolOfDeclaration(location as ModuleDeclaration | SourceFile).exports!, meaning & SymbolFlags.ModuleMember);
break;
Expand Down Expand Up @@ -48981,7 +48988,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (isPropertyAccessExpression(entityName.parent) && getLeftmostAccessExpression(entityName.parent) === entityName) {
return undefined;
}
// falls through
// falls through
case AssignmentDeclarationKind.ThisProperty:
case AssignmentDeclarationKind.ModuleExports:
return getSymbolOfDeclaration(entityName.parent.parent as BinaryExpression);
Expand Down Expand Up @@ -49280,7 +49287,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (!isThisInTypeQuery(node)) {
return getSymbolOfNameOrPropertyAccessExpression(node as EntityName | PrivateIdentifier | PropertyAccessExpression);
}
// falls through
// falls through

case SyntaxKind.ThisKeyword:
const container = getThisContainer(node, /*includeArrowFunctions*/ false, /*includeClassComputedPropertyName*/ false);
Expand All @@ -49293,7 +49300,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (isInExpressionContext(node)) {
return checkExpression(node as Expression).symbol;
}
// falls through
// falls through

case SyntaxKind.ThisType:
return getTypeFromThisTypeNode(node as ThisExpression | ThisTypeNode).symbol;
Expand Down Expand Up @@ -49327,7 +49334,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (isCallExpression(parent) && isBindableObjectDefinePropertyCall(parent) && parent.arguments[1] === node) {
return getSymbolOfDeclaration(parent);
}
// falls through
// falls through

case SyntaxKind.NumericLiteral:
// index access
Expand Down Expand Up @@ -49366,7 +49373,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
const symbol = getIntrinsicTagSymbol(node.parent as JsxOpeningLikeElement);
return symbol === unknownSymbol ? undefined : symbol;
}
// falls through
// falls through

default:
return undefined;
Expand Down Expand Up @@ -51794,15 +51801,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
);
break;
}
// fallthrough
// fallthrough
case ModuleKind.ES2022:
case ModuleKind.ESNext:
case ModuleKind.Preserve:
case ModuleKind.System:
if (languageVersion >= ScriptTarget.ES2017) {
break;
}
// fallthrough
// fallthrough
default:
diagnostics.add(
createDiagnosticForNode(forInOrOfStatement.awaitModifier, Diagnostics.Top_level_for_await_loops_are_only_allowed_when_the_module_option_is_set_to_es2022_esnext_system_node16_node18_nodenext_or_preserve_and_the_target_option_is_set_to_es2017_or_higher),
Expand Down
4 changes: 4 additions & 0 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -3987,6 +3987,10 @@
"category": "Error",
"code": 2880
},
"'{1}' is constrained to be a subtype of '{0}'.": {
"category": "Error",
"code": 2881
},

"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
better_subType_assignable_to_superType_error_messsage.ts(2,3): error TS2552: Cannot find name 'subtype'. Did you mean 'subType2'?
better_subType_assignable_to_superType_error_messsage.ts(5,3): error TS2322: Type 'SuperType' is not assignable to type 'SubType2'.
'SubType2' is constrained to be a subtype of 'SuperType'.


==== better_subType_assignable_to_superType_error_messsage.ts (2 errors) ====
function parameterExtendsOtherParameter<SuperType, SubType extends SuperType, SubType2 extends SubType>(superType: SuperType, subType2: SubType2) {
subtype = superType;//error
~~~~~~~
!!! error TS2552: Cannot find name 'subtype'. Did you mean 'subType2'?
!!! related TS2728 better_subType_assignable_to_superType_error_messsage.ts:1:127: 'subType2' is declared here.

//ensures that supertypes are not assignable to 'grandchild' subtypes
subType2 = superType;//error
~~~~~~~~
!!! error TS2322: Type 'SuperType' is not assignable to type 'SubType2'.
!!! error TS2322: 'SubType2' is constrained to be a subtype of 'SuperType'.
!!! related TS2208 better_subType_assignable_to_superType_error_messsage.ts:1:41: This type parameter might need an `extends SubType2` constraint.

superType = subType2;//ok
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//// [tests/cases/compiler/better_subType_assignable_to_superType_error_messsage.ts] ////

//// [better_subType_assignable_to_superType_error_messsage.ts]
function parameterExtendsOtherParameter<SuperType, SubType extends SuperType, SubType2 extends SubType>(superType: SuperType, subType2: SubType2) {
subtype = superType;//error

//ensures that supertypes are not assignable to 'grandchild' subtypes
subType2 = superType;//error

superType = subType2;//ok
}


//// [better_subType_assignable_to_superType_error_messsage.js]
function parameterExtendsOtherParameter(superType, subType2) {
subtype = superType; //error
//ensures that supertypes are not assignable to 'grandchild' subtypes
subType2 = superType; //error
superType = subType2; //ok
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//// [tests/cases/compiler/better_subType_assignable_to_superType_error_messsage.ts] ////

=== better_subType_assignable_to_superType_error_messsage.ts ===
function parameterExtendsOtherParameter<SuperType, SubType extends SuperType, SubType2 extends SubType>(superType: SuperType, subType2: SubType2) {
>parameterExtendsOtherParameter : Symbol(parameterExtendsOtherParameter, Decl(better_subType_assignable_to_superType_error_messsage.ts, 0, 0))
>SuperType : Symbol(SuperType, Decl(better_subType_assignable_to_superType_error_messsage.ts, 0, 40))
>SubType : Symbol(SubType, Decl(better_subType_assignable_to_superType_error_messsage.ts, 0, 50))
>SuperType : Symbol(SuperType, Decl(better_subType_assignable_to_superType_error_messsage.ts, 0, 40))
>SubType2 : Symbol(SubType2, Decl(better_subType_assignable_to_superType_error_messsage.ts, 0, 77))
>SubType : Symbol(SubType, Decl(better_subType_assignable_to_superType_error_messsage.ts, 0, 50))
>superType : Symbol(superType, Decl(better_subType_assignable_to_superType_error_messsage.ts, 0, 104))
>SuperType : Symbol(SuperType, Decl(better_subType_assignable_to_superType_error_messsage.ts, 0, 40))
>subType2 : Symbol(subType2, Decl(better_subType_assignable_to_superType_error_messsage.ts, 0, 125))
>SubType2 : Symbol(SubType2, Decl(better_subType_assignable_to_superType_error_messsage.ts, 0, 77))

subtype = superType;//error
>superType : Symbol(superType, Decl(better_subType_assignable_to_superType_error_messsage.ts, 0, 104))

//ensures that supertypes are not assignable to 'grandchild' subtypes
subType2 = superType;//error
>subType2 : Symbol(subType2, Decl(better_subType_assignable_to_superType_error_messsage.ts, 0, 125))
>superType : Symbol(superType, Decl(better_subType_assignable_to_superType_error_messsage.ts, 0, 104))

superType = subType2;//ok
>superType : Symbol(superType, Decl(better_subType_assignable_to_superType_error_messsage.ts, 0, 104))
>subType2 : Symbol(subType2, Decl(better_subType_assignable_to_superType_error_messsage.ts, 0, 125))
}

Loading