diff --git a/accepted/future-releases/static-extension-methods/design-document.md b/accepted/future-releases/static-extension-methods/design-document.md
new file mode 100644
index 0000000000..7856f488ba
--- /dev/null
+++ b/accepted/future-releases/static-extension-methods/design-document.md
@@ -0,0 +1,612 @@
+# Dart Static Extension Methods Design
+
+lrn@google.com Version: 1.0 Status: Design Proposal
+
+This is a design document for *static extension methods* for Dart. This document describes the most basic variant of the feature, then lists a few possible variants or extensions.
+
+See [Problem Description](https://github.com/dart-lang/language/issues/40) and [Feature Request](https://github.com/dart-lang/language/issues/41) for background.
+
+The design of this feature is kept deliberately simple, while still attempting to make extension methods act similarly to instance methods in most cases.
+
+## What Are Static Extension Methods
+
+Dart classes have virtual methods. An invocation like `thing.doStuff()` will invoke the virtual `doStuff` method on the object denoted by `thing`. The only way to add methods to a class is to modify the class. If you are not the author of the class, you have to use static helper functions instead of methods, so `doMyStuff(thing)` instead of `thing.doMyStuff()`. That's acceptable for a single function, but in a larger chain of operations, it becomes overly cumbersome. Example:
+
+```dart
+doMyOtherStuff(doMyStuff(something.doStuff()).doOtherStuff())
+```
+
+That code is much less readable than:
+
+```dart
+something.doStuff().doMyStuff().doOtherStuff().doMyOtherStuff()
+```
+
+The code is also much less discoverable. An IDE can suggest `doMyStuff()` after `something.doStuff().`, but will be unlikely to suggest putting `doMyOtherStuff(…)` around the expression.
+
+For these discoverability and readability reasons, static extension methods will allow you to add "extension methods", which are really just static functions, to existing types, and allow you to discover and call those methods as if they were actual methods, using `.`-notation. It will not add any new abilities to the language which are not already available, they just require a more cumbersome and less discoverable syntax to reach.
+
+The extension methods are *static*, which means that we use the static type of an expression to figure out which method to call, and that also means that static extension methods are not virtual methods.
+
+The methods we allow you to add this way are normal methods, operators, getter and setters.
+
+## Declaring Static Extension Methods
+
+### Syntax
+
+A static extension of a type is declared using syntax like:
+
+```dart
+extension MyFancyList on List {
+ int get doubleLength => this.length * 2;
+ List operator-() => this.reversed.toList();
+ List> split(int at) =>
+ >[this.sublist(0, at), this.sublist(at)];
+ List mapToList(R Function(T) convert) => this.map(convert).toList();
+}
+```
+
+More precisely, an extension declaration is a top-level declaration with a grammar similar to:
+
+```ebnf
+ ::=
+ `extension' ? ? `on' `?'? `{'
+ memberDeclaration*
+ `}'
+```
+
+Such a declaration introduces its *name* (the identifier) into the surrounding scope. The name does not denote a type, but it can be used to denote the extension itself in various places. The name can be hidden or shown in `import` or `export` declarations.
+
+The *type* can be any valid Dart type, including a single type variable. It can refer to the type parameters of the extension. It can be followed by `?` which means that it allows `null` values. When Dart gets non-nullable types by default (NNBD), this `?` syntax is removed and subsumed by nullable types like `int?` being allowed in the `` position.
+
+The member declarations can be any non-abstract static or instance member declaration except for instance variables and constructors. Instance member declaration parameters must not be marked `covariant`. Abstract members are not allowed since the extension declaration does not introduce an interface, and constructors are not allowed because the extension declaration doesn't introduce any type that can be constructed. Instance variables are not allowed because there won't be any memory allocation per instance that the extension applies to. We could implement instance variables using an `Expando`, but it would necessarily be nullable, so it would still not be an actual instance variable.
+
+An extension declaration with a non-private name is included in the library's export scope, and a privately named extension is not. It is a compile-time error to export two declarations, including extensions, with the same name, whether they come from declarations in the library itself or from export declarations (with the usual exception when all but one declaration come from platform libraries). Extension *members* with private names are simply inaccessible in other libraries.
+
+### Omitting Names For Private Extensions
+
+If an extension declaration is only used locally in a library, there might be no need to worry about naming conflicts or overrides. In that case, then name identifier can be omitted (hence the `?` in the grammar above).
+
+Example:
+
+```dart
+extension on List {
+ void quadruple() { ... }
+}
+```
+
+This is equivalent to giving the extension a fresh private name.
+
+We may need to make `on` a built-in identifier, and not allow those as names of extensions, then there should not be any parsing issue. Even without that, the grammar should be unambiguous because `extension on on on { … }` and `extension on on { … }` are distinguishable, and the final type cannot be empty. It may be *harder* to parse, though.
+
+This is a simple feature, but with very low impact. It only allows you to omit a single private name for an extension that is only used in a single library.
+
+### Scope
+
+Dart's static extension methods are *scoped*. They only apply to code where the extension itself is *in scope*. Being in scope means that the extension is declared or imported into a scope which is a parent scope of the current lexical scope. The extension is not in scope if the extension declaration's library is not imported, if the library is imported and the extension is hidden, or the library is only imported with a prefix.
+
+An extension *is* in scope if the name is *shadowed* by another declaration (a class or local variable with the same name shadowing a top-level or imported declaration, a top-level declaration shadowing an imported extension, or a non-platform import shadowing a platform import).
+
+An extension *is* in scope if is imported, and the extension name conflicts with one or more other imported declarations.
+
+The usual rules applies to referencing the extension by name, which can be useful in some situations; the extension's *name* is only accessible if it is not shadowed and not conflicting with another imported declaration.
+
+If an extension conflicts with, or is shadowed by, another declaration, and you need to access it by name anyway, it can be imported with a prefix and the name referenced through that prefix.
+
+Example:
+
+```dart
+import "all.dart"; // exposes extensions `Foo`, `Bar` and `Baz`.
+import "bar.dart"; // exposes another extension named `Bar`.
+import "bar.dart" as b; // Also import with prefix.
+class Foo {}
+main() {
+ Foo(); // refers to class declartion.
+ Baz("ok").baz(); // Explicit reference to `Baz` extension.
+ Bar("ok").bar(); // *Compile-time error*, `Bar` name has conflict.
+ b.Bar("ok").bar(); // Valid explicit reference to `Bar` from bar.dart.
+}
+```
+
+*Rationale*: We want users to have control over which extensions are available. They control this through the imports and declarations used to include declarations into the import scope or declaration scope of the library. The typical ways to control the import scope is using `show` /`hide` in the imports or importing into a prefix scope. These features work exactly the same for extensions. On the other hand, we do not want extension writers to have to worry too much about name clashes for their extension names since most extension members are not accessed through that name anyway. In particular we do not want them to name-mangle their extensions in order to avoid hypothetical conflicts. So, all imported extensions are considered in scope, and choosing between the individual extensions is handled as described in the next section. You only run into problems with the extension name if you try to use the name itself. That way you can import two extensions with the same name and use the members without issue (as long as they don't conflict in an unresolvable way), even if you can only refer to *at most* one of them by name.
+
+You still cannot *export* two extensions with the same name.
+
+### Extension Member Resolution
+
+The declaration introduces an extension. The extension's `on` type defines which types are being extended.
+
+For any member access, `x.foo`, `x.bar()`, `x.baz = 42`, `x(42)`, `x[0] = 1` or `x + y`, including null-aware and cascade accesses which effectively desugar to one of those direct accesses, and including implicit member accesses on `this`, the language first checks whether the static type of `x` has a member with the same base name as the operation. That is, if it has a corresponding instance member, respectively, a `foo` method or getter or a `foo=` setter. a `bar` member or `bar=` setter, a `baz` member or `baz=` setter, a `call` method, a `[]=` operator or a `+` operator. If so, then the operation is unaffected by extensions. *This check does not care whether the invocation is otherwise correct, based on number or type of the arguments, it only checks whether there is a member at all.*
+
+(The types `dynamic` and `Never` are considered as having all members, the type `void` is always a compile-time error when used in a receiver position, so none of these can ever be affected by static extension methods. The type `Function` and all function types are considered as having a `call` member on top of any members inherited from `Object`. Methods declared on `Object` are available on all types and can therefore never be affected by extensions).
+
+If there is no such member, the operation is currently a compile-time error. In that case, all extensions in scope are checked for whether they apply. An extension applies to a member access if the static type of the receiver is a subtype of the `on` type of the extension *and* the extension has an instance member with the same base name as the operation.
+
+For generic extensions, standard type inference is used to infer the type arguments. As an example, take the following extension:
+
+```dart
+extension MyList> on List {
+ void quickSort() { ... }
+}
+```
+
+and a member access like:
+
+```dart
+List times = ...;
+times.quickSort();
+```
+
+Here we perform type inference equivalent to what we would do for:
+
+```dart
+class MyList> {
+ MyList(List argument);
+ void quickSort() { ... }
+}
+...
+List times = ...;
+... MyList(times).quickSort() ... // Infer type argument of MyList here.
+```
+
+or for:
+
+```dart
+void Function() MyList$quickSort>(List $this) =>
+ () { ... }
+...
+ MyList$quickSort(times)();
+```
+
+This is inference based on static types only. The inferred type argument becomes the value of `T` for the function invocation that follows. Notice that the context type of the invocation does not affect whether the extension applies, and neither the context type nor the method invocation affects the type inference, but if the extension method itself is generic, the context type may affect the member invocation.
+
+If the inference fails, or if the synthetic constructor invocation (`MyList(times)` in the above example) would not be statically valid for any other reason, then the extension does not apply. If an extension does not have an instance member with the base name `quickSort`, it does not apply.
+
+If exactly one extension applies to an otherwise failed member invocation, then that invocation becomes an invocation of the corresponding instance member of the extension, with `this` bound to the receiver object and extension type parameters bound to the inferred types.
+
+If the member is itself generic and has no type parameters supplied, normal static type inference applies again.
+
+It is *as if* the invocation `times.quickSort` was converted to `MyList(times).quickSort()`. The difference is that there is never an actual `MyList` object, and the `this` object inside `quickSort` is just the `times` list itself (although the extension methods apply to that code too).
+
+### Generic Parameter Inference
+
+If both the extension and the method is generic, then inference must infer the extension type parameters first, to figure out whether the extension applies, and only then start inferring method type parameters. As mentioned above, the inference is similar to other cases of chained inference.
+
+Example:
+
+```dart
+extension SuperList on List {
+ R foldRight(R base, R combine(T element, R accumulator)) {
+ for (int i = this.length - 1; i >= 0; i--) {
+ base = combine(this[i], base);
+ }
+ return base;
+ }
+}
+...
+ List strings = ...;
+ int count(String string, int length) => length + string.length;
+ ...
+ var length = strings.foldRight(0, count);
+```
+
+Here the inference occurs just as if the extension had been declared like:
+
+```dart
+class SuperList {
+ final List $this;
+ SuperList(this.$this);
+ R foldRight(R base, R Function(T, R) combine) { ... }
+}
+```
+
+and it was invoked as `SuperList(strings).foldRight(0, count)`.
+
+Or, alternatively, like the extension method had been declared like:
+
+```dart
+R Function(R, R Function(T, R)) SuperList$foldRight(List $this) =>
+ (R base, R Function(T, R) combine) { ... };
+```
+
+and it was invoked as `SuperList$foldRight(strings)(0, count)`.
+
+In either case, the invocation of the `foldRight` method does not contribute to the inference of `T` at all, but after `T` has been inferred.
+
+The extension type parameter can also occur as a parameter type for the method.
+
+Example:
+
+```dart
+extension TypedEquals {
+ bool equals(T value) => this == value;
+}
+```
+
+Using such an extension as:
+
+```dart
+Object o = ...;
+String s = ...;
+print(s.equals(o)); // Compile-time type error.
+```
+
+will fail. While we could make it work by inferring `T` as `Object`, we don't. We infer `T` *only* based on the receiver type, and therefore `T` is `String`, and `o` is not a valid argument (at least not when we remove implicit downcasts).
+
+### Extension Conflict Resolution
+
+If more than one extension applies to a specific member invocation, then we resort to a heuristic to choose one of the extensions to apply. If exactly one of them is "more specific" than all the others, that one is chosen. Otherwise it is a compile-time error.
+
+An extension with `on` type clause *T*1 is more specific than another extension with `on` type clause *T*2 iff
+
+1. The latter extension is declared in a platform library, and the former extension is not, or
+2. they are both declared in platform libraries or both declared in non-platform libraries, and
+3. the instantiated type (the type after applying type inference from the receiver) of *T*1 is a subtype of the instantiated type of *T*2 and either
+4. not vice versa, or
+5. the instantiate-to-bounds type of *T*1 is a subtype of the instantiate-to-bounds type of *T*2 and not vice versa.
+
+This definition is designed to ensure that the extension chosen is the one that has the most precise type information available, while ensuring that a platform library provided extension never conflicts with a user provided extension. We avoid this because it allows adding extensions to platform libraries without breaking existing code when the platform is upgraded.
+
+If an extension's `on` type has a trailing `?`, say `on String?`, then we do not use that for specificity pre-NNBD. Since all receivers are potentially nullable pre-NNBD, it does not provide any useful signal.
+
+Post-NNBD, any trailing `?` is part of the `on` type, and a nullable type like `int?` is a proper supertype of, and therefore less specific than, `int`.
+
+That is, the specificity of an extension wrt. an application depends of the type it is used at, and how specific the extension is itself (what its implementation can assume about the type).
+
+Example:
+
+```dart
+extension SmartIterable on Iterable {
+ void doTheSmartThing(void Function(T) smart) {
+ for (var e in this) smart(e);
+ }
+}
+extension SmartList on List {
+ void doTheSmartThing(void Function(T) smart) {
+ for (int i = 0; i < length; i++) smart(this[i]);
+ }
+}
+...
+ List x = ....;
+ x.doTheSmartThing(print);
+```
+
+Here both the extensions apply, but the `SmartList` extension is more specific than the `SmartIterable` extension because `List` <: `Iterable`.
+
+Example:
+
+```dart
+extension BestCom on Iterable { T best() {...} }
+extension BestList on List { T best() {...} }
+extension BestSpec on List { num best() {...} }
+...
+ List x = ...;
+ var v = x.best();
+ List y = ...;
+ var w = y.best();
+```
+
+Here all three extensions apply to both invocations.
+
+For `x.best()`, the most specific one is `BestList`. Because `List` is a proper subtype of both ` iterable` and ``, we expect `BestList` to be the best implementation. The return type causes `v` to have type `int`. If we had chosen `BestSpec` instead, the return type could only be `num`, which is one of the reasons why we choose the most specific instantiated type as the winner.
+
+For `y.best()`, the most specific extension is `BestSpec`. The instantiated `on` types that are compared are `Iterable` for `Best
+Com` and `List` for the two other. Using the instantiate-to-bounds types as tie-breaker, we find that `List