Integrated dynamic-members.md

Change-Id: Ic99a5def446c6d97d2e561f61c32f24bd80a9dd2
Reviewed-on: https://dart-review.googlesource.com/c/81640
Reviewed-by: Lasse R.H. Nielsen <lrn@google.com>
diff --git a/docs/language/dartLangSpec.tex b/docs/language/dartLangSpec.tex
index 5f20586..ecc249e 100644
--- a/docs/language/dartLangSpec.tex
+++ b/docs/language/dartLangSpec.tex
@@ -11624,7 +11624,7 @@
 of any type,
 without error.
 Note that the invocation will still cause a compile-time error
-if one or more arguments or other subterms has an error.
+if there is an error in one or more arguments or other subterms.
 }
 
 \LMHash{}%
@@ -11654,10 +11654,129 @@
 
 \commentary{
 This \code{Type} object must compare equal to the corresponding \code{Type}
-objects for \code{Object} and \VOID{}
+objects for \code{Object} and \VOID{} according to operator `\code{==}'
 (\ref{dynamicTypeSystem}).
 }
 
+\LMHash{}%
+To improve the precision of static types,
+member accesses on a receiver of type \DYNAMIC{} that refer to
+declarations of the built-in class \code{Object}
+are given the static type corresponding to those declarations
+whenever doing so is sound.
+
+\begin{itemize}
+\item
+  Let $e$ be an expression of the form \code{$d$.\id}, which is not followed by an
+  argument part, where the static type of $d$ is \DYNAMIC, and \id{} is the name of a
+  getter declared in \code{Object}; if the return type of \code{Object.\id} is $T$
+  then the static type of $e$ is $T$.
+  \commentary{
+  For instance, \code{d.hashCode} has type \code{int}
+  and \code{d.runtimeType} has type \code{Type}.
+  }
+
+\item
+  Let $e$ be an expression of the form \code{$d$.\id}, which is not followed by an
+  argument part, where the static type of $d$ is \DYNAMIC, and \id{} is the name of a
+  method declared in \code{Object} whose method signature has type $F$
+  (\commentary{which is a function type}). The static type of $e$ is then $F$.
+  \commentary{
+  For instance, \code{$d$.toString} has type \code{String \FUNCTION()}.
+  }
+
+\item
+  Let $e$ be an expression of the form \code{$d$.\id(\metavar{arguments})} or
+  \code{$d$.\id<\metavar{typeArguments}>(\metavar{arguments})}
+  where the static type of $d$ is \DYNAMIC,
+  \id{} is the name of a getter declared in \code{Object} with return type $F$,
+  \metavar{arguments} are derived from \synt{arguments}, and
+  \metavar{typeArguments} are derived from \synt{typeArguments}, if present.
+  Static analysis will then process $e$ as a function expression invocation
+  where an object of static type $F$ is applied to the given argument part.
+  \commentary{
+  So this is always a compile-time error.
+  For instance, \code{$d$.runtimeType(42)} is a compile-time error,
+  because it is checked as a
+  function expression invocation where an entity of static type \code{Type} is
+  invoked. Note that it could actually succeed: An overriding implementation
+  of \code{runtimeType} could return an instance whose dynamic type is a subtype
+  of \code{Type} that has a \code{call} method.
+  We decided to make it an error because it is likely to be a mistake,
+  especially in cases like \code{$d$.hashCode()}
+  where a developer might have forgotten that \code{hashCode} is a getter.
+  }
+
+\item
+  Let $e$ be an expression of the form \code{$d$.\id(\metavar{arguments})}
+  where the static type of $d$ is \DYNAMIC, \metavar{arguments} is
+  an actual argument list derived from \synt{arguments},
+  and \id{} is the name of a method declared in \code{Object}
+  whose method signature has type $F$.
+  If the number of positional actual arguments in \metavar{arguments} is less than the
+  number of required positional arguments of $F$ or greater than the number
+  of positional arguments in $F$, or if \metavar{arguments} includes any named
+  arguments with a name that is not declared in $F$, the type of $e$ is
+  \DYNAMIC. Otherwise, the type of $e$ is the return type in $F$.
+  \commentary{
+    So \code{$d$.toString(bazzle:\,42)} has type \DYNAMIC{} whereas
+    \code{$d$.toString()} has type \code{String}.
+    Note that invocations which "do not fit" the statically
+    known declaration are not errors, they just get return type \DYNAMIC.
+  }
+
+\item
+  Let $e$ be an expression of the form
+  \code{$d$.\id<\metavar{typeArguments}>(\metavar{arguments})} where
+  the static type of $d$ is \DYNAMIC, \metavar{typeArguments} is a list of actual
+  type arguments derived from \synt{typeArguments}, and
+  \metavar{arguments} is an actual argument list derived from \synt{arguments}.
+  It is a compile-time error if \id{} is the name of
+  a non-generic method declared in \code{Object}.
+  \commentary{
+  No generic methods are declared in \code{Object}.
+  Hence, we do not specify that there must be
+  the statically required number of actual type arguments, and
+  they must satisfy the bounds.
+  That would otherwise be the consistent approach,
+  because the invocation is guaranteed to fail when any of those
+  requirements are violated,
+  but generalizations of this mechanism would need to include such rules.
+  }
+
+\item
+  For an instance method invocation $e$ (including invocations of getters,
+  setters, and operators) where the receiver has static type \DYNAMIC{} and
+  $e$ does not match any of the above cases, the static type of $e$ is
+  \DYNAMIC.
+  When an expression derived from \synt{cascadeSection} performs
+  a getter or method invocation that corresponds to one of the cases above,
+  the corresponding static analysis and compile-time errors apply.
+  \commentary{
+  For instance, \code{$d$..foobar(16)..hashCode()} is an error.
+  }
+\end{itemize}
+
+\commentary{
+Note that only very few forms of instance method invocation with a
+receiver of type \DYNAMIC{} can be a compile-time error.
+Of course, some expressions like \code{x[1, 2]} are syntax errors
+even though they could also be considered "invocations",
+and subexpressions are checked separately so
+any given actual argument could be a compile-time error.
+But almost any given argument list shape could be handled via \code{noSuchMethod},
+and an argument of any type could be accepted because any
+formal parameter in an overriding declaration could have its type
+annotation contravariantly changed to \code{Object}.
+So it is a natural consequence of the principle of
+that
+a \DYNAMIC{} receiver admits almost all instance method invocations.
+The few cases where an instance method invocation with
+a receiver of type \DYNAMIC{} is an error
+are either guaranteed to fail at run time,
+or they are very, very likely to be developer mistakes.
+}
+
 
 \subsection{Type FutureOr}
 \LMLabel{typeFutureOr}
diff --git a/docs/language/informal/dynamic-members.md b/docs/language/informal/dynamic-members.md
index 07a8371..78c070d 100644
--- a/docs/language/informal/dynamic-members.md
+++ b/docs/language/informal/dynamic-members.md
@@ -4,7 +4,7 @@
 
 **Version**: 0.2 (2018-09-04)
 
-**Status**: Under implementation.
+**Status**: Background material. Normative text is now in dartLangSpec.tex.
 
 **This document** is a Dart 2 feature specification of the static typing
 of instance members of a receiver whose static type is `dynamic`.