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

emit @implements on 'implements' of type+value #1073

Closed
wants to merge 1 commit into from
Closed

emit @implements on 'implements' of type+value #1073

wants to merge 1 commit into from

Conversation

evmar
Copy link
Contributor

@evmar evmar commented Sep 16, 2019

If tsickle gets input that contains a type-value conflict, e.g.
interface X { ... }
const X = 3;
then it drops the 'interface' declaration in the output because
at the Closure level, the definition of "X" clobbers the @record.

Because of this, if someone later attempts to use the interface, e.g.
class C implements X {}
tsickle would silently drop the '@implements' of that interface in
the Closure output.

But dropping @implements is dangerous in the presence of typed
optimzations; and this actually caused a real misoptimization in a
Google app.

The reason was that you actually can have legitimate type+value
interfaces in Closure:
/** @interface */ class I { ... }
I.someValue = 3;
and Clutz then dutifully converts this to the matching TypeScript,
and then if someone implements that interface, dropping the @implements
can cause a misoptimization.

In #1072 I convinced myself that we should instead never drop any
'implements' clause. If the user writes the above pattern with X
and C, we should just compile fail instead, because there is no
way we can safely emit it.

In the test case here I added some usage of 'export import', but it
turns out that was irrelevant to this bug; it's just that when Clutz
started using 'export import' it got better at correctly describing
the above 'class I' pattern, which cascaded into this tsickle failure.
The clutz 'export import' change is
angular/clutz@cc9c9e6

If tsickle gets input that contains a type-value conflict, e.g.
  interface X { ... }
  const X = 3;
then it drops the 'interface' declaration in the output because
at the Closure level, the definition of "X" clobbers the @record.

Because of this, if someone later attempts to *use* the interface, e.g.
  class C implements X {}
tsickle would silently drop the '@implements' of that interface in
the Closure output.

But dropping @implements is dangerous in the presence of typed
optimzations; and this actually caused a real misoptimization in a
Google app.

The reason was that you actually can have legitimate type+value
interfaces in Closure:
  /** @interface */ class I { ... }
  I.someValue = 3;
and Clutz then dutifully converts this to the matching TypeScript,
and then if someone implements that interface, dropping the @implements
can cause a misoptimization.

In #1072 I convinced myself that we should instead never drop any
'implements' clause.  If the user writes the above pattern with X
and C, we should just compile fail instead, because there is no
way we can safely emit it.

In the test case here I added some usage of 'export import', but it
turns out that was irrelevant to this bug; it's just that when Clutz
started using 'export import' it got better at correctly describing
the above 'class I' pattern, which cascaded into this tsickle failure.
The clutz 'export import' change is
  angular/clutz@cc9c9e6
@@ -0,0 +1,17 @@
/**
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I usually name these export_import/export_import.ts so that we don't end up with a million files called test.ts. The repetition sucks too, not sure if it's substantially better...

// Simple implementation of a type+value that is indirected through an
// 'export import' clause.
// We expect an @implements to show in the output.
class C2 implements export_import.Reexport.Reexported {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are you going to remove the export import stuff here before submission? It's distracting from what the test really tests, isn't it?

@@ -90,6 +90,10 @@ export function maybeAddHeritageClauses(
type: heritage.parentName,
});
}
// In the heritage==null case, we silently have dropped an @implements.
// In issue 1072 I advocate that we should never drop an @implements here,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand this comment. It sounds as if you advocate something, but then didn't act on it? Is that a follow up?

The way I read the code it suggests that we below fall through and do emit?

@@ -0,0 +1,18 @@
/**
* @fileoverview This file vaguely resembles the shape of the clutz output of
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you narrow this down to a test that just creates the type/value conflict?

// Because Zone is both a type and a value, the interface will be dropped
// when converting to Closure, so the "implements" should be ignored for
// both the direct use and the use via a typedef.
interface Zone {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're removing coverage here. Can we keep a test that shows what happens when we have a type/value conflict in a regular .ts file?

@mprobst
Copy link
Contributor

mprobst commented Sep 17, 2019

I think we should keep a test and show what happens for a type/value conflict in .ts code.

@evmar
Copy link
Contributor Author

evmar commented Oct 2, 2019

Abandoning this in favor of ef80516

@evmar evmar closed this Oct 2, 2019
@evmar evmar deleted the exp-imp branch October 2, 2019 17:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants