{"action":"created","issue":{"url":"https://api.github.com/repos/google/closure-compiler/issues/980","labels_url":"https://api.github.com/repos/google/closure-compiler/issues/980/labels{/name}","comments_url":"https://api.github.com/repos/google/closure-compiler/issues/980/comments","events_url":"https://api.github.com/repos/google/closure-compiler/issues/980/events","html_url":"https://github.com/google/closure-compiler/issues/980","id":82497384,"number":980,"title":"The current type checker fails to detect a type mismatch involving type interface","user":{"login":"JacksonGL","id":4462454,"avatar_url":"https://avatars.githubusercontent.com/u/4462454?v=3","gravatar_id":"","url":"https://api.github.com/users/JacksonGL","html_url":"https://github.com/JacksonGL","followers_url":"https://api.github.com/users/JacksonGL/followers","following_url":"https://api.github.com/users/JacksonGL/following{/other_user}","gists_url":"https://api.github.com/users/JacksonGL/gists{/gist_id}","starred_url":"https://api.github.com/users/JacksonGL/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/JacksonGL/subscriptions","organizations_url":"https://api.github.com/users/JacksonGL/orgs","repos_url":"https://api.github.com/users/JacksonGL/repos","events_url":"https://api.github.com/users/JacksonGL/events{/privacy}","received_events_url":"https://api.github.com/users/JacksonGL/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/google/closure-compiler/labels/OTI","name":"OTI","color":"f7c6c7"},{"url":"https://api.github.com/repos/google/closure-compiler/labels/Types","name":"Types","color":"5319e7"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":3,"created_at":"2015-05-29T16:37:33Z","updated_at":"2015-06-03T16:24:38Z","closed_at":null,"body":"The last two assignments in function ```f``` should trigger warnings in the current type system.\r\n```javascript\r\n/**\r\n * @interface\r\n * @template KEY1, VALUE1\r\n */\r\nvar IObject = function() {};\r\n\r\n/**\r\n * @interface\r\n * @extends {IObject<number, VALUE2>}\r\n * @template VALUE2\r\n */\r\nvar IArrayLike = function() {};\r\n\r\n/**\r\n * @constructor\r\n * @implements {IArrayLike<number>}\r\n */\r\nfunction Int8Array2() {}\r\n\r\nfunction f() {\r\n  /** @type {Int8Array2} */\r\n  var x = new Int8Array2();\r\n\r\n  /** @type {IArrayLike<string>} */\r\n  var y;\r\n  y = x;  // should have a warning here\r\n\r\n  /** @type {IObject<number, string>} */\r\n  var z;\r\n  z = x;  // should have a warning here\r\n}\r\n```"},"comment":{"url":"https://api.github.com/repos/google/closure-compiler/issues/comments/108510070","html_url":"https://github.com/google/closure-compiler/issues/980#issuecomment-108510070","issue_url":"https://api.github.com/repos/google/closure-compiler/issues/980","id":108510070,"user":{"login":"JacksonGL","id":4462454,"avatar_url":"https://avatars.githubusercontent.com/u/4462454?v=3","gravatar_id":"","url":"https://api.github.com/users/JacksonGL","html_url":"https://github.com/JacksonGL","followers_url":"https://api.github.com/users/JacksonGL/followers","following_url":"https://api.github.com/users/JacksonGL/following{/other_user}","gists_url":"https://api.github.com/users/JacksonGL/gists{/gist_id}","starred_url":"https://api.github.com/users/JacksonGL/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/JacksonGL/subscriptions","organizations_url":"https://api.github.com/users/JacksonGL/orgs","repos_url":"https://api.github.com/users/JacksonGL/repos","events_url":"https://api.github.com/users/JacksonGL/events{/privacy}","received_events_url":"https://api.github.com/users/JacksonGL/received_events","type":"User","site_admin":false},"created_at":"2015-06-03T16:24:38Z","updated_at":"2015-06-03T16:24:38Z","body":"I think I find the reason. It turns out that in the old type system, ```Int8Array2``` is a function literal and therefore hoisted. The hoisted function declaration is processed before ```IObject``` and ```IArrayLike```. Consequently, its template type map data is somehow incomplete. This leads to ```KEY_MISMATCH``` (for template type match) when doing the type equivalence check (in the type checking stage). Therefore the types are considered equivalent under ```INVARIANT``` match. Therefore the type check missed. Not sure if this should be considered as a bug. \r\n\r\nThe following example works fine:\r\n```javascript\r\n/**\r\n* @interface\r\n* @template KEY1, VALUE1\r\n*/\r\nfunction IObject() {}; // hoisted\r\n\r\n/**\r\n* @interface \r\n* @extends {IObject<number, VALUE2>}\r\n* @template VALUE2\r\n*/\r\nfunction IArrayLike() {}; // hoisted\r\n\r\n/**\r\n* @constructor \r\n* @implements {IArrayLike<number>}\r\n*/\r\nvar Int8Array2 = function() {}; // not hoisted\r\n\r\nfunction f() {\r\n  /** @type {Int8Array2} */\r\n  var x = new Int8Array2();\r\n\r\n  /** @type {IArrayLike<string>} */\r\n  var y;\r\n  y = x;  // warning generated\r\n\r\n  /** @type {IObject<number, string>} */\r\n  var z;\r\n  z = x;  // warning generated\r\n}\r\n```\r\n\r\nWhile in the following case, type checking partially works because of hoistering only one super class.\r\n```javascript\r\n/**\r\n* @interface\r\n* @template KEY1, VALUE1\r\n*/\r\nvar IObject = function() {};\r\n\r\n/**\r\n* @interface \r\n* @extends {IObject<number, VALUE2>}\r\n* @template VALUE2\r\n*/\r\nfunction IArrayLike() {}; // hoisted, processed before IObject, template information from IObject is incomplete\r\n\r\n/**\r\n* @constructor \r\n* @implements {IArrayLike<number>}\r\n*/\r\nvar Int8Array2 = function() {}\r\n\r\nfunction f() {\r\n  var x = new Int8Array2();\r\n\r\n  /** @type {IArrayLike<string>} */\r\n  var y;\r\n  y = x; // warning generated\r\n\r\n  /** @type {IObject<boolean, number>} */\r\n  var z;\r\n  z = x; // no warning, as KEY1 (from IObject) is incomplete\r\n}\r\n\r\n```\r\n"}}