Chromium Code Reviews| Index: pkg/kernel/lib/ast.dart |
| diff --git a/pkg/kernel/lib/ast.dart b/pkg/kernel/lib/ast.dart |
| index d404cc92cbdb2feba735b4c4fd99f50d8c1396f5..db3fc0eca63a8931faaaf69f41085f6fa39e260f 100644 |
| --- a/pkg/kernel/lib/ast.dart |
| +++ b/pkg/kernel/lib/ast.dart |
| @@ -977,6 +977,17 @@ class Field extends Member { |
| /// The uri of the source file this field was loaded from. |
| String fileUri; |
| + /// Formal safety of the implicit setter's formal parameter (if there is one). |
| + /// |
| + /// See [FormalSafety] for details. |
| + FormalSafety setterFormalSafety = FormalSafety.unsafe; |
| + |
| + /// Interface safety of the implicit setter's formal parameter (if there is |
| + /// one). |
| + /// |
| + /// See [InterfaceSafety] for details. |
| + InterfaceSafety setterInterfaceSafety = InterfaceSafety.semiTyped; |
| + |
| Field(Name name, |
| {this.type: const DynamicType(), |
| this.initializer, |
| @@ -1747,6 +1758,7 @@ class VariableSet extends Expression { |
| class PropertyGet extends Expression { |
| Expression receiver; |
| Name name; |
| + DispatchCategory dispatchCategory = DispatchCategory.dynamicDispatch; |
| Reference interfaceTargetReference; |
| @@ -1855,6 +1867,7 @@ class PropertySet extends Expression { |
| class DirectPropertyGet extends Expression { |
| Expression receiver; |
| Reference targetReference; |
| + DispatchCategory dispatchCategory = DispatchCategory.dynamicDispatch; |
| DirectPropertyGet(Expression receiver, Member target) |
| : this.byReference(receiver, getMemberReference(target)); |
| @@ -1944,6 +1957,7 @@ class DirectMethodInvocation extends InvocationExpression { |
| Expression receiver; |
| Reference targetReference; |
| Arguments arguments; |
| + DispatchCategory dispatchCategory = DispatchCategory.dynamicDispatch; |
| DirectMethodInvocation( |
| Expression receiver, Procedure target, Arguments arguments) |
| @@ -2006,6 +2020,7 @@ class DirectMethodInvocation extends InvocationExpression { |
| class SuperPropertyGet extends Expression { |
| Name name; |
| Reference interfaceTargetReference; |
| + DispatchCategory get dispatchCategory => DispatchCategory.viaThis; |
| SuperPropertyGet(Name name, [Member interfaceTarget]) |
| : this.byReference(name, getMemberReference(interfaceTarget)); |
| @@ -2223,6 +2238,7 @@ class MethodInvocation extends InvocationExpression { |
| Expression receiver; |
| Name name; |
| Arguments arguments; |
| + DispatchCategory dispatchCategory = DispatchCategory.dynamicDispatch; |
| Reference interfaceTargetReference; |
| @@ -2310,6 +2326,7 @@ class MethodInvocation extends InvocationExpression { |
| class SuperMethodInvocation extends InvocationExpression { |
| Name name; |
| Arguments arguments; |
| + DispatchCategory get dispatchCategory => DispatchCategory.viaThis; |
| Reference interfaceTargetReference; |
| @@ -3769,6 +3786,151 @@ class YieldStatement extends Statement { |
| } |
| } |
| +/// Indication of when a runtime type check of a formal parameter (or type |
| +/// parameter) needs to be included in the code generated for a method. |
| +/// |
| +/// [FormalSafety] annotations are considered to be part of a method's body; |
| +/// they only apply to concrete methods, and they affect any calls that resolve |
| +/// to the annotated method at runtime. So for instance, in the following code, |
| +/// the "unsafe" annotation means that the type of `o` will have to be checked |
| +/// in the second call to `g` (when the runtime type of `c` is `D`), but not in |
| +/// the first. |
| +/// |
| +/// class C { |
| +/// void f(Object o /*safe*/) { ... } |
| +/// } |
| +/// class D { |
| +/// void f(covariant int o /*unsafe*/) { ... } |
| +/// } |
| +/// void g(C c) { |
| +/// c.f('hi'); |
| +/// } |
| +/// void main() { |
| +/// g(new C()); |
| +/// g(new D()); |
| +/// } |
| +enum FormalSafety { |
| + /// Full safety; a runtime check is only needed for dynamic invocations. |
| + /// |
| + /// For a [FormalParameterDeclaration], the type system can guarantee that the |
| + /// actual value that will be passed to the method at runtime will be an |
| + /// instance of the formal parameter's type |
| + /// ([FormalParameterDeclaration.type]), *provided that* the call site is not |
| + /// annotated as [DispatchCategory.dynamicDispatch]. |
| + /// |
| + /// For a [TypeParameter], the type system can guarantee that the actual type |
| + /// that will be used to instantiate the type parameter at runtime will be a |
| + /// subtype of the type parameter's bound ([TypeParameter.bound]), |
| + /// *provided that* the call site is not annotated as |
| + /// [DispatchCategory.dynamicDispatch]. |
| + /// |
| + /// This annotation is used for static and top level methods since they never |
| + /// require additional runtime checks due to covariance. |
| + safe, |
| + |
| + /// Partial safety; a runtime check is not needed for "typed" or "this" |
| + /// invocations. |
| + /// |
| + /// For a [FormalParameterDeclaration], the type system can guarantee that the |
| + /// actual value that will be passed to the method at runtime will be an |
| + /// instance of the formal parameter's type |
| + /// ([FormalParameterDeclaration.type]), *provided that* the invocation comes |
| + /// through an invocation target that marks the corresponding type parameter |
| + /// with [InterfaceSafety.typed], or the call site is annotated as |
| + /// [DispatchCategory.viaThis]. |
| + /// |
| + /// For a [TypeParameter], the type system can guarantee that the actual type |
| + /// that will be used to instantiate the type parameter at runtime will be a |
| + /// subtype of the type parameter's bound ([TypeParameter.bound]), |
| + /// *provided that* the invocation comes through an invocation target that |
| + /// marks the corresponding type parameter with [InterfaceSafety.typed], or |
| + /// the call site is annotated as [DispatchCategory.viaThis]. |
| + semiSafe, |
| + |
| + /// No safety; a runtime type check is always required. |
| + /// |
| + /// For a [FormalParameterDeclaration], the type system cannot guarantee that |
| + /// the actual value that will be passed to the method at runtime will be an |
| + /// instance of the formal parameter's type |
| + /// ([FormalParameterDeclaration.type]). Therefore, in the absence of |
| + /// additional information from whole program analysis, a runtime type check |
| + /// needs to be compiled into the body of the method. |
| + /// |
| + /// Not used for [TypeParameter]s. |
| + unsafe, |
| +} |
| + |
| +/// Indication of when a call site can skip a runtime type check that would have |
| +/// otherwise been required by [FormalSafety]. |
| +/// |
| +/// [InterfaceSafety] annotations are considered to be part of a class's API; |
| +/// they apply to both concrete and abstract methods, and they affect any calls |
| +/// that resolve to the annotated method statically. So for instance, in the |
| +/// following code, the "semi-typed" annotation means that the call site at g1 |
| +/// (which statically resolves to C.f) needs a runtime type check, but the call |
| +/// site at g2 (which statically resolves to D.f) does not. |
| +/// |
| +/// class C<T> { |
| +/// void f(T x /*semi-typed*/) { ... } |
| +/// } |
| +/// class D extends C<num> { |
|
Jennifer Messerly
2017/08/29 23:02:23
one thing that might be worth an example?
class C
Paul Berry
2017/08/29 23:24:24
Good idea. Done.
|
| +/// void f(num x /*typed*/); |
| +/// } |
| +/// void g1(C<num> c) { |
| +/// c.f(1.5); |
| +/// } |
| +/// void g2(D d) { |
| +/// d.f(1.5); |
| +/// } |
| +enum InterfaceSafety { |
| + /// Full type guarantee; a runtime check is only needed if the concrete |
| + /// parameter bound at runtime is "unsafe". |
| + /// |
| + /// This annotation is used for static and top level methods since they never |
| + /// require additional runtime checks due to covariance. |
| + /// |
| + /// See [FormalSafety] for details. |
| + typed, |
| + |
| + /// Partial type guarantee; a runtime check is needed if the concrete |
| + /// parameter bound at runtime is "unsafe" or "semiSafe". |
| + /// |
| + /// See [FormalSafety] for details. |
| + semiTyped, |
| +} |
| + |
| +/// Categorization of a call site indicating its effect on type guarantees. |
| +enum DispatchCategory { |
| + /// This call site binds to its callee through a specific interface. |
| + /// |
| + /// The front end guarantees that the target of the call exists, has the |
| + /// correct arity, and accepts all of the supplied named parameters. Further, |
| + /// it guarantees that the number of type parameters supplied matches the |
| + /// number of type parameters expected by the target of the call. |
| + interface, |
| + |
| + /// This call site binds to its callee via a call on `this`. |
| + /// |
| + /// Similar to [interface], however the target of the call is a method on |
| + /// `this` or `super`, therefore all of the class's type parameters are known |
| + /// to match exactly. |
| + viaThis, |
| + |
| + /// This call site is an invocation of a function object (formed either by a |
| + /// tear off or a function literal). |
| + /// |
| + /// Similar to [interface], however the interface target of the call is not |
| + /// known. |
| + closure, |
| + |
| + /// The call site is dynamic. |
| + /// |
| + /// The front end makes no guarantees that the target of the call will accept |
| + /// the actual runtime types of the parameters, nor that the target of the |
| + /// call even exists. Everything must be checked at runtime. |
| + dynamicDispatch, |
| +} |
| + |
| /// Declaration of a local variable. |
| /// |
| /// This may occur as a statement, but is also used in several non-statement |
| @@ -3803,6 +3965,18 @@ class VariableDeclaration extends Statement { |
| /// Should be null in other cases. |
| Expression initializer; // May be null. |
| + /// If this is a formal parameter of a concrete method, its formal safety. |
| + /// Otherwise ignored. |
| + /// |
| + /// See [FormalSafety] for details. |
| + FormalSafety formalSafety = FormalSafety.safe; |
| + |
| + /// If this is a formal parameter of a method, its interface safety. |
| + /// Otherwise ignored. |
| + /// |
| + /// See [InterfaceSafety] for details. |
| + InterfaceSafety interfaceSafety = InterfaceSafety.typed; |
| + |
| VariableDeclaration(this.name, |
| {this.initializer, |
| this.type: const DynamicType(), |
| @@ -4422,6 +4596,18 @@ class TypeParameter extends TreeNode { |
| /// be set to the root class for type parameters without an explicit bound. |
| DartType bound; |
| + /// If this is a type parameter of a concrete generic method, its formal |
| + /// safety. Otherwise ignored. |
| + /// |
| + /// See [FormalSafety] for details. |
| + FormalSafety formalSafety = FormalSafety.safe; |
| + |
| + /// If this is a type parameter of a generic method, its interface safety. |
| + /// Otherwise ignored. |
| + /// |
| + /// See [InterfaceSafety] for details. |
| + InterfaceSafety interfaceSafety = InterfaceSafety.typed; |
| + |
| TypeParameter([this.name, this.bound]); |
| accept(TreeVisitor v) => v.visitTypeParameter(this); |