{"action":"created","issue":{"url":"https://api.github.com/repos/dart-lang/sdk/issues/33932","repository_url":"https://api.github.com/repos/dart-lang/sdk","labels_url":"https://api.github.com/repos/dart-lang/sdk/issues/33932/labels{/name}","comments_url":"https://api.github.com/repos/dart-lang/sdk/issues/33932/comments","events_url":"https://api.github.com/repos/dart-lang/sdk/issues/33932/events","html_url":"https://github.com/dart-lang/sdk/issues/33932","id":343199176,"node_id":"MDU6SXNzdWUzNDMxOTkxNzY=","number":33932,"title":"promote locals without an upcast first","user":{"login":"matanlurey","id":168174,"node_id":"MDQ6VXNlcjE2ODE3NA==","avatar_url":"https://avatars2.githubusercontent.com/u/168174?v=4","gravatar_id":"","url":"https://api.github.com/users/matanlurey","html_url":"https://github.com/matanlurey","followers_url":"https://api.github.com/users/matanlurey/followers","following_url":"https://api.github.com/users/matanlurey/following{/other_user}","gists_url":"https://api.github.com/users/matanlurey/gists{/gist_id}","starred_url":"https://api.github.com/users/matanlurey/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/matanlurey/subscriptions","organizations_url":"https://api.github.com/users/matanlurey/orgs","repos_url":"https://api.github.com/users/matanlurey/repos","events_url":"https://api.github.com/users/matanlurey/events{/privacy}","received_events_url":"https://api.github.com/users/matanlurey/received_events","type":"User","site_admin":false},"labels":[{"id":219928175,"node_id":"MDU6TGFiZWwyMTk5MjgxNzU=","url":"https://api.github.com/repos/dart-lang/sdk/labels/area-language","name":"area-language","color":"c7def8","default":false}],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":7,"created_at":"2018-07-20T18:06:55Z","updated_at":"2018-07-26T15:57:16Z","closed_at":null,"author_association":"CONTRIBUTOR","body":"```dart\r\nclass Model<T> {}\r\n\r\nclass Interface<T> {\r\n  void hasMethod() {}\r\n}\r\n\r\nclass Service {\r\n  Model model;\r\n  \r\n  void tryThis() {\r\n    final model = this.model;\r\n    if (model is Interface) {\r\n      // ERROR: The method 'hasMethod' isn't defined for the class 'Model'.\r\n      model.hasMethod();\r\n    }\r\n  }\r\n}\r\n```\r\n\r\nNaming `final model` to `final modelX` works as expected."},"comment":{"url":"https://api.github.com/repos/dart-lang/sdk/issues/comments/408146427","html_url":"https://github.com/dart-lang/sdk/issues/33932#issuecomment-408146427","issue_url":"https://api.github.com/repos/dart-lang/sdk/issues/33932","id":408146427,"node_id":"MDEyOklzc3VlQ29tbWVudDQwODE0NjQyNw==","user":{"login":"matanlurey","id":168174,"node_id":"MDQ6VXNlcjE2ODE3NA==","avatar_url":"https://avatars2.githubusercontent.com/u/168174?v=4","gravatar_id":"","url":"https://api.github.com/users/matanlurey","html_url":"https://github.com/matanlurey","followers_url":"https://api.github.com/users/matanlurey/followers","following_url":"https://api.github.com/users/matanlurey/following{/other_user}","gists_url":"https://api.github.com/users/matanlurey/gists{/gist_id}","starred_url":"https://api.github.com/users/matanlurey/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/matanlurey/subscriptions","organizations_url":"https://api.github.com/users/matanlurey/orgs","repos_url":"https://api.github.com/users/matanlurey/repos","events_url":"https://api.github.com/users/matanlurey/events{/privacy}","received_events_url":"https://api.github.com/users/matanlurey/received_events","type":"User","site_admin":false},"created_at":"2018-07-26T15:57:16Z","updated_at":"2018-07-26T15:57:16Z","author_association":"CONTRIBUTOR","body":"> Losing information is most likely going to be very annoying in practice\r\n\r\nCould we do some actual investigation of this before claiming it? For example, we have a huge swath of both Flutter (/cc @Hixie) and internal code (/cc @davidmorgan) to look at, and we could see if indeed you are correct, or if the user _always_ expects the new type, and is OK with losing capabilities.\r\n\r\nIn the short term though, can we do something about the usability issue? \r\n\r\nMany users hit this and are very confused. A couple ideas:\r\n\r\n1. Easier: Issue a hint when `is` won't perform a type promotion: (/cc @bwilkerson)\r\n\r\n```dart\r\nclass A {}\r\nclass B {}\r\n\r\nvoid example(A a) {\r\n  // HINT: Variable \"a\" will not be promoted to type \"B\". Perform an upcast first.\r\n  if (a is B) {\r\n\r\n  }\r\n}\r\n```\r\n\r\n... and if analyzer could offer an auto-fix, it would write, for you:\r\n\r\n```dart\r\nclass A {}\r\nclass B {}\r\n\r\nvoid example(A a) {\r\n  final Object aUpcast = a;\r\n  if (aUpcast is B) {\r\n    // aUpcast is now a type of B\r\n  }\r\n}\r\n```\r\n\r\nIf we deem this too disruptive, then maybe we could detect the following pattern:\r\n\r\n```dart\r\nclass A {}\r\nclass B {}\r\n\r\nvoid example(A a) {\r\n  // HINT: Variable \"a\" will not be promoted to type \"B\". Perform an upcast first.\r\n  if (a is B) {\r\n    // This.\r\n    (a as B);\r\n    // Or this.\r\n    B b = a;\r\n  }\r\n}\r\n```\r\n\r\n2. Harder: Have a variant of `is` that allows losing information:\r\n\r\n```dart\r\nclass A {}\r\nclass B {}\r\n\r\nvoid example(A a) {\r\n  // I am not a language designer. But something that allows `is` to an unrelated type.\r\n  if (a is~ B) {\r\n\r\n  }\r\n}\r\n```"}}
{"actor":{"display_login":"matanlurey"}}