Rules of @reopen
annotation and lint
#2730
Labels
class-modifiers
Issues related to "base", "final", "interface", and "mixin" modifiers on classes and mixins.
The feature specifiction states, as a suggested lint/annotation (and the suggestion may be followed, q.v. dart-lang/linter#3920):
The rationale for
reopen
and@reopen
in the "Trust but verify" section seems to be that you should explicitly say when you grant a capability that was removed in a superclass, other than bysealed
. Or maybe it only applied if you didn't write any other modifier, it's not entirely clear.The rules here do not match that, since they do not allow a
final
class's subclass to be marked assealed
, but they do allow afinal
subtype (through implements) to have abase
subclass. That's removing a restriction, but not leaking the original implementation.There is (probably) a reason for this choice, but it's not made explicit in the proposal. I think it is:
Private implementation: If a type cannot be publicly subclassed in a way which inherits implementation, a library-local subtype which does inherit the implementation must also not allow that implementation to be publicly inherited.
(Still should allow a
sealed
subclass, so add ", orsealed
" to the first item.)Private interface: If a type's interface cannot be publicly implemented, a library local subtype must also not be able to have its interface publicly inherited.
If something is
final
, it must satisfy both and again befinal
orsealed
.This still doesn't prevent leaking things through a
sealed
class declaration, because being sealed does not impose restrictions on direct subclasses. Would we want to check transitively through superclasses, pastsealed
classes, to see if we are leaking something further up the supertype tree?(If we don't give the rationale behind the rules, it's impossible to see whether the rules/lint is working as intended.)
Another worry is that a
sealed
subtype can subtype any class, and it can have any subclasses without warning, so there is no transitive checking.If I have
final class Foo
,sealed class Bar extends Foo
, andclass Baz extends Bar
, then there is no requirement for an@open
annotation onBaz
, even though it exposes thefinal class Foo
implementation to other libraries.The issue is that
sealed
is not intended as inherited, the other restrictions are, and the rules here try to enforce the transitive restrictions through one-step rules. That chain of restriction breaks at asealed
class.So maybe say when a class declaration C needs an
@open
annotation by defining a function:We then say that a class or mixin declaration D needs an
@open
annotation if the declaration does not have asealed
(orfinal
) modifier, so it's modifier m is one ofbase
,interface
or none, and MUP(m, inheritedRestrictions(D)) ≠ m.(A
final
declaration cannot fail the requirement, so we can short-circuit the test.)The text was updated successfully, but these errors were encountered: