Skip to content

Commit

Permalink
Do not allow freshness to move errors out of the current file, ensure…
Browse files Browse the repository at this point in the history
… json documents are deeply unfreshened and fully widened (microsoft#35048)
  • Loading branch information
weswigham authored Nov 12, 2019
1 parent f334476 commit aa39080
Show file tree
Hide file tree
Showing 6 changed files with 158 additions and 8 deletions.
10 changes: 3 additions & 7 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7310,11 +7310,7 @@ namespace ts {
if (!declaration.statements.length) {
return emptyObjectType;
}
const type = getWidenedLiteralType(checkExpression(declaration.statements[0].expression));
if (type.flags & TypeFlags.Object) {
return getRegularTypeOfObjectLiteral(type);
}
return type;
return getWidenedType(getWidenedLiteralType(checkExpression(declaration.statements[0].expression)));
}

// Handle variable, parameter or property
Expand Down Expand Up @@ -14807,7 +14803,7 @@ namespace ts {
// JsxAttributes has an object-literal flag and undergo same type-assignablity check as normal object-literal.
// However, using an object-literal error message will be very confusing to the users so we give different a message.
// TODO: Spelling suggestions for excess jsx attributes (needs new diagnostic messages)
if (prop.valueDeclaration && isJsxAttribute(prop.valueDeclaration)) {
if (prop.valueDeclaration && isJsxAttribute(prop.valueDeclaration) && getSourceFileOfNode(errorNode) === getSourceFileOfNode(prop.valueDeclaration.name)) {
// Note that extraneous children (as in `<NoChild>extra</NoChild>`) don't pass this check,
// since `children` is a SyntaxKind.PropertySignature instead of a SyntaxKind.JsxAttribute.
errorNode = prop.valueDeclaration.name;
Expand All @@ -14818,7 +14814,7 @@ namespace ts {
// use the property's value declaration if the property is assigned inside the literal itself
const objectLiteralDeclaration = source.symbol && firstOrUndefined(source.symbol.declarations);
let suggestion;
if (prop.valueDeclaration && findAncestor(prop.valueDeclaration, d => d === objectLiteralDeclaration)) {
if (prop.valueDeclaration && findAncestor(prop.valueDeclaration, d => d === objectLiteralDeclaration) && getSourceFileOfNode(objectLiteralDeclaration) === getSourceFileOfNode(errorNode)) {
const propDeclaration = prop.valueDeclaration as ObjectLiteralElementLike;
Debug.assertNode(propDeclaration, isObjectLiteralElementLike);

Expand Down
2 changes: 1 addition & 1 deletion tests/baselines/reference/jsDeclarationsJson.types
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
=== tests/cases/conformance/jsdoc/declarations/index.js ===
const j = require("./obj.json");
>j : { x: number; y: number; obj: { items: ({ x: number; y?: undefined; err?: undefined; } | { x: number; y: number; err?: undefined; } | { x: number; err: boolean; y?: undefined; })[]; }; }
>require("./obj.json") : { x: number; y: number; obj: { items: ({ x: number; } | { x: number; y: number; } | { x: number; err: boolean; })[]; }; }
>require("./obj.json") : { x: number; y: number; obj: { items: ({ x: number; y?: undefined; err?: undefined; } | { x: number; y: number; err?: undefined; } | { x: number; err: boolean; y?: undefined; })[]; }; }
>require : any
>"./obj.json" : "./obj.json"

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//// [tests/cases/compiler/jsonFileImportChecksCallCorrectlyTwice.ts] ////

//// [index.ts]
import data from "./data.json";

interface Foo {
str: string;
}

fn(data.foo);
fn(data.foo); // <-- shouldn't error!

function fn(arg: Foo[]) { }
//// [data.json]
{
"foo": [
{
"bool": true,
"str": "123"
}
]
}

//// [data.json]
{
"foo": [
{
"bool": true,
"str": "123"
}
]
}
//// [index.js]
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
exports.__esModule = true;
var data_json_1 = __importDefault(require("./data.json"));
fn(data_json_1["default"].foo);
fn(data_json_1["default"].foo); // <-- shouldn't error!
function fn(arg) { }
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
=== tests/cases/compiler/index.ts ===
import data from "./data.json";
>data : Symbol(data, Decl(index.ts, 0, 6))

interface Foo {
>Foo : Symbol(Foo, Decl(index.ts, 0, 31))

str: string;
>str : Symbol(Foo.str, Decl(index.ts, 2, 15))
}

fn(data.foo);
>fn : Symbol(fn, Decl(index.ts, 7, 13))
>data.foo : Symbol("foo", Decl(data.json, 0, 1))
>data : Symbol(data, Decl(index.ts, 0, 6))
>foo : Symbol("foo", Decl(data.json, 0, 1))

fn(data.foo); // <-- shouldn't error!
>fn : Symbol(fn, Decl(index.ts, 7, 13))
>data.foo : Symbol("foo", Decl(data.json, 0, 1))
>data : Symbol(data, Decl(index.ts, 0, 6))
>foo : Symbol("foo", Decl(data.json, 0, 1))

function fn(arg: Foo[]) { }
>fn : Symbol(fn, Decl(index.ts, 7, 13))
>arg : Symbol(arg, Decl(index.ts, 9, 12))
>Foo : Symbol(Foo, Decl(index.ts, 0, 31))

=== tests/cases/compiler/data.json ===
{
"foo": [
>"foo" : Symbol("foo", Decl(data.json, 0, 1))
{
"bool": true,
>"bool" : Symbol("bool", Decl(data.json, 2, 7))

"str": "123"
>"str" : Symbol("str", Decl(data.json, 3, 21))
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
=== tests/cases/compiler/index.ts ===
import data from "./data.json";
>data : { foo: { bool: boolean; str: string; }[]; }

interface Foo {
str: string;
>str : string
}

fn(data.foo);
>fn(data.foo) : void
>fn : (arg: Foo[]) => void
>data.foo : { bool: boolean; str: string; }[]
>data : { foo: { bool: boolean; str: string; }[]; }
>foo : { bool: boolean; str: string; }[]

fn(data.foo); // <-- shouldn't error!
>fn(data.foo) : void
>fn : (arg: Foo[]) => void
>data.foo : { bool: boolean; str: string; }[]
>data : { foo: { bool: boolean; str: string; }[]; }
>foo : { bool: boolean; str: string; }[]

function fn(arg: Foo[]) { }
>fn : (arg: Foo[]) => void
>arg : Foo[]

=== tests/cases/compiler/data.json ===
{
>{ "foo": [ { "bool": true, "str": "123" } ]} : { foo: { bool: boolean; str: string; }[]; }

"foo": [
>"foo" : { bool: boolean; str: string; }[]
>[ { "bool": true, "str": "123" } ] : { bool: boolean; str: string; }[]
{
>{ "bool": true, "str": "123" } : { bool: boolean; str: string; }

"bool": true,
>"bool" : boolean
>true : true

"str": "123"
>"str" : string
>"123" : "123"
}
]
}
24 changes: 24 additions & 0 deletions tests/cases/compiler/jsonFileImportChecksCallCorrectlyTwice.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// @esModuleInterop: true
// @resolveJsonModule: true
// @strict: true
// @outDir: dist
// @filename: index.ts
import data from "./data.json";

interface Foo {
str: string;
}

fn(data.foo);
fn(data.foo); // <-- shouldn't error!

function fn(arg: Foo[]) { }
// @filename: data.json
{
"foo": [
{
"bool": true,
"str": "123"
}
]
}

0 comments on commit aa39080

Please sign in to comment.