{"action":"opened","issue":{"url":"https://api.github.com/repos/dart-lang/sdk/issues/24458","labels_url":"https://api.github.com/repos/dart-lang/sdk/issues/24458/labels{/name}","comments_url":"https://api.github.com/repos/dart-lang/sdk/issues/24458/comments","events_url":"https://api.github.com/repos/dart-lang/sdk/issues/24458/events","html_url":"https://github.com/dart-lang/sdk/issues/24458","id":108676604,"number":24458,"title":"dart2js: Unsafe propagation across method lookup","user":{"login":"asgerf","id":316427,"avatar_url":"https://avatars.githubusercontent.com/u/316427?v=3","gravatar_id":"","url":"https://api.github.com/users/asgerf","html_url":"https://github.com/asgerf","followers_url":"https://api.github.com/users/asgerf/followers","following_url":"https://api.github.com/users/asgerf/following{/other_user}","gists_url":"https://api.github.com/users/asgerf/gists{/gist_id}","starred_url":"https://api.github.com/users/asgerf/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/asgerf/subscriptions","organizations_url":"https://api.github.com/users/asgerf/orgs","repos_url":"https://api.github.com/users/asgerf/repos","events_url":"https://api.github.com/users/asgerf/events{/privacy}","received_events_url":"https://api.github.com/users/asgerf/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":0,"created_at":"2015-09-28T15:03:54Z","updated_at":"2015-09-28T15:03:54Z","closed_at":null,"body":"In JS the method lookup is evaluated before the arguments to a method call, which can prevent propagation. For example:\r\n\r\n```dart\r\ny = foo();\r\nx.bar(y); // not safe to propagate foo() if x can be null, because 'x.bar' throws\r\n```\r\n\r\nIn the CPS/Tree backend, this is currently handled by the flag `InvokeMethod.receiverIsNotNull`, which tells assignment propagation if it is safe to propagate non-constant expressions into the arguments.\r\n\r\nThis broke when type refinement was introduced:\r\n\r\n```dart\r\ny = x.foo(); // x cannot be null after call\r\nx.bar(y); // x is not null. Propagating y seems safe.\r\n\r\n=> x.bar(x.foo()); // Oops. Throws for 'x.bar' instead of 'x.foo'\r\n```\r\n\r\nBecause assignment propagation reorders expressions, the information based on type refinement may become invalid.\r\n\r\nThe SSA backend seems to fall into the same trap, probably for similar reasons, but I'm not sure.\r\n\r\nA potential solution in the CPS backend is to explicitly check for this in assignment propagation, but that pass is already too complicated, and it's sort of hack to check for \"something that may have promoted the type of x\".\r\n\r\nA alternative is to initially use Dart-style method lookup, i.e. where the method lookup evaluates after the arguments. That means propagation is always safe. Then there is a pass after assignment propagation that switches to JS-style method lookup, and the pass has to \"unpropagate\" arguments to preserve evaluation order. The semantics of the tree IR thus depends on where in the pipeline we are, like with the unsugaring pass in CPS.\r\n\r\n@kmillikin @rakudrama "}}