Version 2.16.0-129.0.dev
Merge commit '58749cfa756a8e461f62d37f7645636d8aef0fd9' into 'dev'
diff --git a/pkg/analyzer/lib/dart/element/element.dart b/pkg/analyzer/lib/dart/element/element.dart
index c1074b2..400e918 100644
--- a/pkg/analyzer/lib/dart/element/element.dart
+++ b/pkg/analyzer/lib/dart/element/element.dart
@@ -1050,6 +1050,8 @@
R? visitPropertyAccessorElement(PropertyAccessorElement element);
+ R? visitSuperFormalParameterElement(SuperFormalParameterElement element);
+
R? visitTopLevelVariableElement(TopLevelVariableElement element);
R? visitTypeAliasElement(TypeAliasElement element);
@@ -1575,6 +1577,9 @@
/// parameter.
bool get isRequiredPositional;
+ /// Return `true` if this parameter is a super formal parameter.
+ bool get isSuperFormal;
+
@override
String get name;
@@ -1731,6 +1736,19 @@
List<String> get shownNames;
}
+/// A super formal parameter defined within a constructor element.
+///
+/// Clients may not extend, implement or mix-in this class.
+abstract class SuperFormalParameterElement implements ParameterElement {
+ /// The associated super-constructor parameter, from the super-constructor
+ /// that is referenced by the implicit or explicit super-constructor
+ /// invocation.
+ ///
+ /// Can be `null` for erroneous code - not existing super-constructor,
+ /// no corresponding parameter in the super-constructor.
+ ParameterElement? get superConstructorParameter;
+}
+
/// A top-level variable.
///
/// Clients may not extend, implement or mix-in this class.
diff --git a/pkg/analyzer/lib/dart/element/visitor.dart b/pkg/analyzer/lib/dart/element/visitor.dart
index 0654527..aede2b6 100644
--- a/pkg/analyzer/lib/dart/element/visitor.dart
+++ b/pkg/analyzer/lib/dart/element/visitor.dart
@@ -169,6 +169,10 @@
visitVariableElement(element);
@override
+ R? visitSuperFormalParameterElement(SuperFormalParameterElement element) =>
+ visitParameterElement(element);
+
+ @override
R? visitTopLevelVariableElement(TopLevelVariableElement element) =>
visitPropertyInducingElement(element);
@@ -306,6 +310,12 @@
}
@override
+ R? visitSuperFormalParameterElement(SuperFormalParameterElement element) {
+ element.visitChildren(this);
+ return null;
+ }
+
+ @override
R? visitTopLevelVariableElement(TopLevelVariableElement element) {
element.visitChildren(this);
return null;
@@ -391,6 +401,10 @@
R? visitPropertyAccessorElement(PropertyAccessorElement element) => null;
@override
+ R? visitSuperFormalParameterElement(SuperFormalParameterElement element) =>
+ null;
+
+ @override
R? visitTopLevelVariableElement(TopLevelVariableElement element) => null;
@override
@@ -471,6 +485,10 @@
_throw(element);
@override
+ R? visitSuperFormalParameterElement(SuperFormalParameterElement element) =>
+ _throw(element);
+
+ @override
R? visitTopLevelVariableElement(TopLevelVariableElement element) =>
_throw(element);
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index a10310d..8b728b5 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -83,7 +83,7 @@
/// TODO(scheglov) Clean up the list of implicitly analyzed files.
class AnalysisDriver implements AnalysisDriverGeneric {
/// The version of data format, should be incremented on every format change.
- static const int DATA_VERSION = 192;
+ static const int DATA_VERSION = 193;
/// The number of exception contexts allowed to write. Once this field is
/// zero, we stop writing any new exception contexts in this process.
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index b3bc7a1..43e9949 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -43,6 +43,7 @@
import 'package:analyzer/src/summary2/bundle_reader.dart';
import 'package:analyzer/src/summary2/reference.dart';
import 'package:analyzer/src/task/inference_error.dart';
+import 'package:collection/collection.dart';
/// A concrete implementation of a [ClassElement].
abstract class AbstractClassElementImpl extends _ExistingElementImpl
@@ -1728,6 +1729,26 @@
}
}
+class DefaultSuperFormalParameterElementImpl
+ extends SuperFormalParameterElementImpl with ConstVariableElement {
+ /// Initialize a newly created parameter element to have the given [name] and
+ /// [nameOffset].
+ DefaultSuperFormalParameterElementImpl({
+ required String name,
+ required int nameOffset,
+ required ParameterKind parameterKind,
+ }) : super(
+ name: name,
+ nameOffset: nameOffset,
+ parameterKind: parameterKind,
+ );
+
+ @override
+ String? get defaultValueCode {
+ return constantInitializer?.toSource();
+ }
+}
+
/// The synthetic element representing the declaration of the type `dynamic`.
class DynamicElementImpl extends ElementImpl implements TypeDefiningElement {
/// Return the unique instance of this class.
@@ -4818,6 +4839,9 @@
bool get isLate => false;
@override
+ bool get isSuperFormal => false;
+
+ @override
ElementKind get kind => ElementKind.PARAMETER;
@override
@@ -5431,6 +5455,56 @@
}
}
+class SuperFormalParameterElementImpl extends ParameterElementImpl
+ implements SuperFormalParameterElement {
+ /// Initialize a newly created parameter element to have the given [name] and
+ /// [nameOffset].
+ SuperFormalParameterElementImpl({
+ required String name,
+ required int nameOffset,
+ required ParameterKind parameterKind,
+ }) : super(
+ name: name,
+ nameOffset: nameOffset,
+ parameterKind: parameterKind,
+ );
+
+ /// Super parameters are visible only in the initializer list scope,
+ /// and introduce final variables.
+ @override
+ bool get isFinal => true;
+
+ @override
+ bool get isSuperFormal => true;
+
+ @override
+ ParameterElement? get superConstructorParameter {
+ final enclosingElement = this.enclosingElement;
+ if (enclosingElement is ConstructorElementImpl) {
+ var superConstructor = enclosingElement.superConstructor;
+ if (superConstructor != null) {
+ var superParameters = superConstructor.parameters;
+ if (isNamed) {
+ return superParameters.firstWhereOrNull((e) => e.name == name);
+ } else {
+ var index = enclosingElement.parameters
+ .whereType<SuperFormalParameterElementImpl>()
+ .toList()
+ .indexOf(this);
+ if (index >= 0 && index < superParameters.length) {
+ return superParameters[index];
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ @override
+ T? accept<T>(ElementVisitor<T> visitor) =>
+ visitor.visitSuperFormalParameterElement(this);
+}
+
/// A concrete implementation of a [TopLevelVariableElement].
class TopLevelVariableElementImpl extends PropertyInducingElementImpl
implements TopLevelVariableElement {
diff --git a/pkg/analyzer/lib/src/dart/element/member.dart b/pkg/analyzer/lib/src/dart/element/member.dart
index adff225..f6195f1 100644
--- a/pkg/analyzer/lib/src/dart/element/member.dart
+++ b/pkg/analyzer/lib/src/dart/element/member.dart
@@ -842,6 +842,9 @@
bool get isInitializingFormal => declaration.isInitializingFormal;
@override
+ bool get isSuperFormal => declaration.isSuperFormal;
+
+ @override
String get name => declaration.name;
@deprecated
diff --git a/pkg/analyzer/lib/src/summary2/bundle_reader.dart b/pkg/analyzer/lib/src/summary2/bundle_reader.dart
index 3811175..14aa0a2 100644
--- a/pkg/analyzer/lib/src/summary2/bundle_reader.dart
+++ b/pkg/analyzer/lib/src/summary2/bundle_reader.dart
@@ -943,6 +943,7 @@
return List.generate(length, (_) {
var name = _reader.readStringReference();
var isInitializingFormal = _reader.readBool();
+ var isSuperFormal = _reader.readBool();
var reference = containerRef.getChild(name);
var kindIndex = _reader.readByte();
@@ -956,6 +957,12 @@
nameOffset: -1,
parameterKind: kind,
);
+ } else if (isSuperFormal) {
+ element = SuperFormalParameterElementImpl(
+ name: name,
+ nameOffset: -1,
+ parameterKind: kind,
+ );
} else {
element = ParameterElementImpl(
name: name,
@@ -970,6 +977,12 @@
nameOffset: -1,
parameterKind: kind,
);
+ } else if (isSuperFormal) {
+ element = DefaultSuperFormalParameterElementImpl(
+ name: name,
+ nameOffset: -1,
+ parameterKind: kind,
+ );
} else {
element = DefaultParameterElementImpl(
name: name,
diff --git a/pkg/analyzer/lib/src/summary2/bundle_writer.dart b/pkg/analyzer/lib/src/summary2/bundle_writer.dart
index 114e90b..946fd6e6 100644
--- a/pkg/analyzer/lib/src/summary2/bundle_writer.dart
+++ b/pkg/analyzer/lib/src/summary2/bundle_writer.dart
@@ -336,6 +336,7 @@
element as ParameterElementImpl;
_sink._writeStringReference(element.name);
_sink.writeBool(element.isInitializingFormal);
+ _sink.writeBool(element.isSuperFormal);
_sink._writeFormalParameterKind(element);
ParameterElementFlags.write(_sink, element);
diff --git a/pkg/analyzer/lib/src/summary2/element_builder.dart b/pkg/analyzer/lib/src/summary2/element_builder.dart
index af3cdb7..44de859 100644
--- a/pkg/analyzer/lib/src/summary2/element_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/element_builder.dart
@@ -352,6 +352,7 @@
_enclosingContext.addParameter(null, element);
}
element.hasImplicitType = node.type == null && node.parameters == null;
+ // TODO(scheglov) Do we need these two below?
element.isExplicitlyCovariant = node.covariantKeyword != null;
element.isFinal = node.isFinal;
element.metadata = _buildAnnotations(node.metadata);
@@ -359,6 +360,7 @@
nameNode.staticElement = element;
+ // TODO(scheglov) check that we don't set reference for parameters
var fakeReference = Reference.root();
var holder = _EnclosingContext(fakeReference, element);
_withEnclosing(holder, () {
@@ -794,6 +796,62 @@
}
@override
+ void visitSuperFormalParameter(
+ covariant SuperFormalParameterImpl node,
+ ) {
+ var nameNode = node.identifier;
+ var name = nameNode.name;
+ var nameOffset = nameNode.offset;
+
+ SuperFormalParameterElementImpl element;
+ var parent = node.parent;
+ if (parent is DefaultFormalParameter) {
+ element = DefaultSuperFormalParameterElementImpl(
+ name: name,
+ nameOffset: nameOffset,
+ parameterKind: node.kind,
+ )..constantInitializer = parent.defaultValue;
+ _linker.elementNodes[element] = parent;
+ _enclosingContext.addParameter(name, element);
+ } else {
+ element = SuperFormalParameterElementImpl(
+ name: name,
+ nameOffset: nameOffset,
+ parameterKind: node.kind,
+ );
+ _linker.elementNodes[element] = node;
+ _enclosingContext.addParameter(null, element);
+ }
+ element.hasImplicitType = node.type == null && node.parameters == null;
+ // TODO(scheglov) Do we need these two below?
+ // element.isExplicitlyCovariant = node.covariantKeyword != null;
+ // element.isFinal = node.isFinal;
+ element.metadata = _buildAnnotations(node.metadata);
+ _setCodeRange(element, node);
+
+ nameNode.staticElement = element;
+
+ // TODO(scheglov) check that we don't set reference for parameters
+ var fakeReference = Reference.root();
+ var holder = _EnclosingContext(fakeReference, element);
+ _withEnclosing(holder, () {
+ var formalParameters = node.parameters;
+ if (formalParameters != null) {
+ formalParameters.accept(this);
+ element.parameters = holder.parameters;
+ }
+
+ var typeParameters = node.typeParameters;
+ if (typeParameters != null) {
+ typeParameters.accept(this);
+ element.typeParameters = holder.typeParameters;
+ }
+ });
+
+ _buildType(node.type);
+ }
+
+ @override
void visitTopLevelVariableDeclaration(
covariant TopLevelVariableDeclarationImpl node,
) {
diff --git a/pkg/analyzer/lib/src/summary2/metadata_resolver.dart b/pkg/analyzer/lib/src/summary2/metadata_resolver.dart
index 3bf8d56..286730c 100644
--- a/pkg/analyzer/lib/src/summary2/metadata_resolver.dart
+++ b/pkg/analyzer/lib/src/summary2/metadata_resolver.dart
@@ -203,6 +203,12 @@
}
@override
+ void visitSuperFormalParameter(SuperFormalParameter node) {
+ node.metadata.accept(this);
+ node.parameters?.accept(this);
+ }
+
+ @override
void visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
node.metadata.accept(this);
}
diff --git a/pkg/analyzer/lib/src/summary2/reference_resolver.dart b/pkg/analyzer/lib/src/summary2/reference_resolver.dart
index 6e6cbe2..6589d31 100644
--- a/pkg/analyzer/lib/src/summary2/reference_resolver.dart
+++ b/pkg/analyzer/lib/src/summary2/reference_resolver.dart
@@ -376,6 +376,24 @@
}
@override
+ void visitSuperFormalParameter(SuperFormalParameter node) {
+ var outerScope = scope;
+
+ var element = node.declaredElement as SuperFormalParameterElementImpl;
+
+ scope = TypeParameterScope(scope, element.typeParameters);
+
+ // TODO(scheglov) More tests when the parse issue fixed.
+ // https://github.com/dart-lang/sdk/issues/47951
+ node.type?.accept(this);
+ node.typeParameters?.accept(this);
+ node.parameters?.accept(this);
+ nodesToBuildType.addDeclaration(node);
+
+ scope = outerScope;
+ }
+
+ @override
void visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
node.variables.accept(this);
}
diff --git a/pkg/analyzer/lib/src/summary2/top_level_inference.dart b/pkg/analyzer/lib/src/summary2/top_level_inference.dart
index 6640e26..714e348 100644
--- a/pkg/analyzer/lib/src/summary2/top_level_inference.dart
+++ b/pkg/analyzer/lib/src/summary2/top_level_inference.dart
@@ -141,7 +141,8 @@
class _ConstructorInferenceNode extends _InferenceNode {
final _InferenceWalker _walker;
final ConstructorElement _constructor;
- final List<_FieldFormalParameterWithField> _parameters = [];
+ final List<_FieldFormalParameter> _fieldParameters = [];
+ final List<_SuperFormalParameter> _superParameters = [];
/// If this node is a constructor of a mixin application, this field
/// is the corresponding constructor of the superclass.
@@ -156,8 +157,17 @@
if (parameter.hasImplicitType) {
var field = parameter.field;
if (field != null) {
- _parameters.add(
- _FieldFormalParameterWithField(parameter, field),
+ _fieldParameters.add(
+ _FieldFormalParameter(parameter, field),
+ );
+ }
+ }
+ } else if (parameter is SuperFormalParameterElementImpl) {
+ if (parameter.hasImplicitType) {
+ var superParameter = parameter.superConstructorParameter;
+ if (superParameter != null) {
+ _superParameters.add(
+ _SuperFormalParameter(parameter, superParameter),
);
}
}
@@ -187,10 +197,12 @@
@override
List<_InferenceNode> computeDependencies() {
- var dependencies = _parameters
- .map((e) => _walker.getNode(e.field))
- .whereNotNull()
- .toList();
+ var dependencies = [
+ ..._fieldParameters.map((e) => _walker.getNode(e.field)).whereNotNull(),
+ ..._superParameters
+ .map((e) => _walker.getNode(e.superParameter))
+ .whereNotNull(),
+ ];
dependencies.addIfNotNull(
_walker.getNode(_baseConstructor?.element),
@@ -201,9 +213,11 @@
@override
void evaluate() {
- for (var parameterWithField in _parameters) {
- var parameter = parameterWithField.parameter;
- parameter.type = parameterWithField.field.type;
+ for (var fieldParameter in _fieldParameters) {
+ fieldParameter.parameter.type = fieldParameter.field.type;
+ }
+ for (var superParameter in _superParameters) {
+ superParameter.parameter.type = superParameter.superParameter.type;
}
// We have inferred formal parameter types of the base constructor.
@@ -241,20 +255,22 @@
@override
void markCircular(List<_InferenceNode> cycle) {
- for (var parameterWithField in _parameters) {
- var parameter = parameterWithField.parameter;
- parameter.type = DynamicTypeImpl.instance;
+ for (var fieldParameter in _fieldParameters) {
+ fieldParameter.parameter.type = DynamicTypeImpl.instance;
+ }
+ for (var superParameter in _superParameters) {
+ superParameter.parameter.type = DynamicTypeImpl.instance;
}
isEvaluated = true;
}
}
/// A field formal parameter with a non-nullable field.
-class _FieldFormalParameterWithField {
+class _FieldFormalParameter {
final FieldFormalParameterElementImpl parameter;
final FieldElement field;
- _FieldFormalParameterWithField(this.parameter, this.field);
+ _FieldFormalParameter(this.parameter, this.field);
}
class _InferenceDependenciesCollector extends RecursiveAstVisitor<void> {
@@ -408,6 +424,14 @@
}
}
+/// A super formal parameter with a non-nullable super-constructor parameter.
+class _SuperFormalParameter {
+ final SuperFormalParameterElementImpl parameter;
+ final ParameterElement superParameter;
+
+ _SuperFormalParameter(this.parameter, this.superParameter);
+}
+
class _VariableInferenceNode extends _InferenceNode {
final _InferenceWalker _walker;
final CompilationUnitElementImpl _unitElement;
diff --git a/pkg/analyzer/lib/src/summary2/types_builder.dart b/pkg/analyzer/lib/src/summary2/types_builder.dart
index 9887d9c..fc19a52 100644
--- a/pkg/analyzer/lib/src/summary2/types_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/types_builder.dart
@@ -206,6 +206,8 @@
} else if (node is SimpleFormalParameter) {
var element = node.declaredElement as ParameterElementImpl;
element.type = node.type?.type ?? _dynamicType;
+ } else if (node is SuperFormalParameter) {
+ _superFormalParameter(node);
} else if (node is VariableDeclarationList) {
var type = node.type?.type;
if (type != null) {
@@ -310,6 +312,24 @@
}
}
+ void _superFormalParameter(SuperFormalParameter node) {
+ // TODO(scheglov) More tests when the parse issue fixed.
+ // https://github.com/dart-lang/sdk/issues/47951
+ var element = node.declaredElement as SuperFormalParameterElementImpl;
+ var parameterList = node.parameters;
+ if (parameterList != null) {
+ var type = _buildFunctionType(
+ node.typeParameters,
+ node.type,
+ parameterList,
+ _nullability(node, node.question != null),
+ );
+ element.type = type;
+ } else {
+ element.type = node.type?.type ?? _dynamicType;
+ }
+ }
+
List<TypeParameterElement> _typeParameters(TypeParameterList? node) {
if (node == null) {
return const <TypeParameterElement>[];
diff --git a/pkg/analyzer/test/src/summary/element_text.dart b/pkg/analyzer/test/src/summary/element_text.dart
index f95078a..197ed0d 100644
--- a/pkg/analyzer/test/src/summary/element_text.dart
+++ b/pkg/analyzer/test/src/summary/element_text.dart
@@ -643,6 +643,8 @@
if (e is FieldFormalParameterElement) {
buffer.write('this.');
+ } else if (e is SuperFormalParameterElement) {
+ buffer.write('super.');
}
_writeName(e);
@@ -656,6 +658,7 @@
_writeParameterElements(e.parameters);
_writeConstantInitializer(e);
_writeNonSyntheticElement(e);
+ _writeSuperConstructorParameter(e);
});
}
@@ -763,6 +766,17 @@
});
}
+ void _writeSuperConstructorParameter(ParameterElement e) {
+ if (e is SuperFormalParameterElement) {
+ var superParameter = e.superConstructorParameter;
+ if (superParameter != null) {
+ _writeElementReference('superConstructorParameter', superParameter);
+ } else {
+ _writelnWithIndent('superConstructorParameter: <null>');
+ }
+ }
+ }
+
void _writeType(DartType type, {String? name}) {
var typeStr = _typeStr(type);
if (name != null) {
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index f4ae652..0176996 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -97,9 +97,10 @@
);
static final FeatureSet latestWithExperiments = FeatureSet.fromEnableFlags2(
- sdkLanguageVersion: Version.parse('2.15.0'),
+ sdkLanguageVersion: Version.parse('2.16.0'),
flags: [
EnableString.constructor_tearoffs,
+ EnableString.super_parameters,
],
);
}
@@ -1452,6 +1453,234 @@
''');
}
+ test_class_constructor_parameters_super_optionalNamed() async {
+ var library = await checkLibrary('''
+class A {
+ A({required int a, required double b});
+}
+
+class B extends A {
+ B({String o1, super.a, String o2, super.b}) : super();
+}
+''');
+ checkElementText(library, r'''
+library
+ definingUnit
+ classes
+ class A @6
+ constructors
+ @12
+ parameters
+ requiredName a @28
+ type: int
+ requiredName b @47
+ type: double
+ class B @61
+ supertype: A
+ constructors
+ @77
+ parameters
+ optionalNamed o1 @87
+ type: String
+ optionalNamed final super.a @97
+ type: int
+ superConstructorParameter: self::@class::A::@constructor::•::@parameter::a
+ optionalNamed o2 @107
+ type: String
+ optionalNamed final super.b @117
+ type: double
+ superConstructorParameter: self::@class::A::@constructor::•::@parameter::b
+ superConstructor: self::@class::A::@constructor::•
+''');
+ }
+
+ test_class_constructor_parameters_super_optionalNamed_unresolved() async {
+ var library = await checkLibrary('''
+class A {
+ A({required int a});
+}
+
+class B extends A {
+ B({super.b});
+}
+''');
+ checkElementText(library, r'''
+library
+ definingUnit
+ classes
+ class A @6
+ constructors
+ @12
+ parameters
+ requiredName a @28
+ type: int
+ class B @42
+ supertype: A
+ constructors
+ @58
+ parameters
+ optionalNamed final super.b @67
+ type: dynamic
+ superConstructorParameter: <null>
+ superConstructor: self::@class::A::@constructor::•
+''');
+ }
+
+ test_class_constructor_parameters_super_optionalPositional() async {
+ var library = await checkLibrary('''
+class A {
+ A(int a, double b);
+}
+
+class B extends A {
+ B([String o1, super.a, String o2, super.b]) : super();
+}
+''');
+ checkElementText(library, r'''
+library
+ definingUnit
+ classes
+ class A @6
+ constructors
+ @12
+ parameters
+ requiredPositional a @18
+ type: int
+ requiredPositional b @28
+ type: double
+ class B @41
+ supertype: A
+ constructors
+ @57
+ parameters
+ optionalPositional o1 @67
+ type: String
+ optionalPositional final super.a @77
+ type: int
+ superConstructorParameter: a@18
+ optionalPositional o2 @87
+ type: String
+ optionalPositional final super.b @97
+ type: double
+ superConstructorParameter: b@28
+ superConstructor: self::@class::A::@constructor::•
+''');
+ }
+
+ test_class_constructor_parameters_super_requiredNamed() async {
+ var library = await checkLibrary('''
+class A {
+ A({required int a, required double b});
+}
+
+class B extends A {
+ B({
+ required String o1,
+ required super.a,
+ required String o2,
+ required super.b,
+ }) : super();
+}
+''');
+ checkElementText(library, r'''
+library
+ definingUnit
+ classes
+ class A @6
+ constructors
+ @12
+ parameters
+ requiredName a @28
+ type: int
+ requiredName b @47
+ type: double
+ class B @61
+ supertype: A
+ constructors
+ @77
+ parameters
+ requiredName o1 @101
+ type: String
+ requiredName final super.a @124
+ type: int
+ superConstructorParameter: self::@class::A::@constructor::•::@parameter::a
+ requiredName o2 @147
+ type: String
+ requiredName final super.b @170
+ type: double
+ superConstructorParameter: self::@class::A::@constructor::•::@parameter::b
+ superConstructor: self::@class::A::@constructor::•
+''');
+ }
+
+ test_class_constructor_parameters_super_requiredPositional() async {
+ var library = await checkLibrary('''
+class A {
+ A(int a, double b);
+}
+
+class B extends A {
+ B(String o1, super.a, String o2, super.b) : super();
+}
+''');
+ checkElementText(library, r'''
+library
+ definingUnit
+ classes
+ class A @6
+ constructors
+ @12
+ parameters
+ requiredPositional a @18
+ type: int
+ requiredPositional b @28
+ type: double
+ class B @41
+ supertype: A
+ constructors
+ @57
+ parameters
+ requiredPositional o1 @66
+ type: String
+ requiredPositional final super.a @76
+ type: int
+ superConstructorParameter: a@18
+ requiredPositional o2 @86
+ type: String
+ requiredPositional final super.b @96
+ type: double
+ superConstructorParameter: b@28
+ superConstructor: self::@class::A::@constructor::•
+''');
+ }
+
+ test_class_constructor_parameters_super_requiredPositional_unresolved() async {
+ var library = await checkLibrary('''
+class A {}
+
+class B extends A {
+ B(super.a);
+}
+''');
+ checkElementText(library, r'''
+library
+ definingUnit
+ classes
+ class A @6
+ constructors
+ synthetic @-1
+ class B @18
+ supertype: A
+ constructors
+ @34
+ parameters
+ requiredPositional final super.a @42
+ type: dynamic
+ superConstructorParameter: <null>
+ superConstructor: self::@class::A::@constructor::•
+''');
+ }
+
test_class_constructor_params() async {
var library = await checkLibrary('class C { C(x, int y); }');
checkElementText(library, r'''
@@ -26154,6 +26383,58 @@
''');
}
+ test_metadata_superFormalParameter() async {
+ var library = await checkLibrary('''
+const a = null;
+
+class A {
+ A(int x);
+}
+
+class B extends A {
+ B(@a super.x);
+}
+''');
+ checkElementText(library, r'''
+library
+ definingUnit
+ classes
+ class A @23
+ constructors
+ @29
+ parameters
+ requiredPositional x @35
+ type: int
+ class B @48
+ supertype: A
+ constructors
+ @64
+ parameters
+ requiredPositional final super.x @75
+ type: int
+ metadata
+ Annotation
+ atSign: @ @66
+ element: self::@getter::a
+ name: SimpleIdentifier
+ staticElement: self::@getter::a
+ staticType: null
+ token: a @67
+ superConstructorParameter: x@35
+ superConstructor: self::@class::A::@constructor::•
+ topLevelVariables
+ static const a @6
+ type: dynamic
+ constantInitializer
+ NullLiteral
+ literal: null @10
+ staticType: Null
+ accessors
+ synthetic static get a @-1
+ returnType: dynamic
+''');
+ }
+
test_metadata_topLevelVariableDeclaration() async {
var library = await checkLibrary('const a = null; @a int v;');
checkElementText(library, r'''
diff --git a/pkg/front_end/testcases/strong.status b/pkg/front_end/testcases/strong.status
index e35f2a1..2aef19d 100644
--- a/pkg/front_end/testcases/strong.status
+++ b/pkg/front_end/testcases/strong.status
@@ -6,6 +6,8 @@
# Kernel ASTs directly, that is, code in pkg/fasta/lib/src/kernel/ with
# strong-mode enabled.
+dart2js/flutter_issue94561/main: SemiFuzzFailure
+dart2js/flutter_issue94561/main.no_link: SemiFuzzFailure
dart2js/late_fields: SemiFuzzFailure
dart2js/late_from_dill/main: SemiFuzzFailure
dart2js/late_statics: SemiFuzzFailure
diff --git a/pkg/front_end/testcases/weak.status b/pkg/front_end/testcases/weak.status
index 9c9ea5e..ae8b870 100644
--- a/pkg/front_end/testcases/weak.status
+++ b/pkg/front_end/testcases/weak.status
@@ -4,6 +4,8 @@
# Status file for the weak_suite.dart test suite.
+dart2js/flutter_issue94561/main: SemiFuzzFailure
+dart2js/flutter_issue94561/main.no_link: SemiFuzzFailure
dart2js/late_fields: SemiFuzzFailure
dart2js/late_from_dill/main: SemiFuzzFailure
dart2js/late_statics: SemiFuzzFailure
@@ -12,7 +14,6 @@
general/error_recovery/issue_39058_prime.crash: SemiFuzzFailure
general/error_recovery/issue_39202.crash: SemiFuzzCrash
general/error_recovery/issue_39058.crash: SemiFuzzFailure
-general/issue47339: SemiFuzzCrash
general/platform_invalid_uris/main: SemiFuzzFailure
nnbd_mixed/mixin_from_opt_in/main: SemiFuzzFailure
nnbd_mixed/mixin_from_opt_in/main.no_link: SemiFuzzFailure
diff --git a/sdk/lib/async/stream_controller.dart b/sdk/lib/async/stream_controller.dart
index 6a21c59..cacc72c 100644
--- a/sdk/lib/async/stream_controller.dart
+++ b/sdk/lib/async/stream_controller.dart
@@ -18,12 +18,54 @@
///
/// This controller allows sending data, error and done events on
/// its [stream].
+///
/// This class can be used to create a simple stream that others
/// can listen on, and to push events to that stream.
///
/// It's possible to check whether the stream is paused or not, and whether
/// it has subscribers or not, as well as getting a callback when either of
/// these change.
+///
+/// Example:
+/// ```dart
+/// final streamController = StreamController(
+/// onPause: () => print('Paused'),
+/// onResume: () => print('Resumed'),
+/// onCancel: () => print('Cancelled'),
+/// onListen: () => print('Listens'),
+/// );
+///
+/// streamController.stream.listen(
+/// (event) => print('Event: $event'),
+/// onDone: () => print('Done'),
+/// onError: (error) => print(error),
+/// );
+/// ```
+/// To check whether there is a subscriber on the stream, use [hasListener].
+/// ```dart continued
+/// var hasListener = streamController.hasListener; // true
+/// ```
+/// To send data events to the stream, use [add] or [addStream].
+/// ```dart continued
+/// streamController.add(999);
+/// final stream = Stream<int>.periodic(
+/// const Duration(milliseconds: 200), (count) => count * count).take(4);
+/// await streamController.addStream(stream);
+/// ```
+/// To send an error event to the stream, use [addError] or [addStream].
+/// ```dart continued
+/// streamController.addError(Exception('Issue 101'));
+/// await streamController.addStream(Stream.error(Exception('Issue 404')));
+/// ```
+/// To check whether the stream is closed, use [isClosed].
+/// ```dart continued
+/// var isClosed = streamController.isClosed; // false
+/// ```
+/// To close the stream, use [close].
+/// ```dart continued
+/// await streamController.close();
+/// isClosed = streamController.isClosed; // true
+/// ```
abstract class StreamController<T> implements StreamSink<T> {
/// The stream that this controller is controlling.
Stream<T> get stream;
@@ -286,7 +328,7 @@
/// or microtask. This means that if it throws, the error will be reported as
/// uncaught as soon as possible.
/// This is one reason to add the event as the last thing in the original event
-/// handler - any action done after adding the event will delay the report of
+/// handler – any action done after adding the event will delay the report of
/// errors in the event listener callbacks.
///
/// If an event is added in a setting that isn't known to be another event,
diff --git a/sdk/lib/async/timer.dart b/sdk/lib/async/timer.dart
index 973a543..a77bdfa 100644
--- a/sdk/lib/async/timer.dart
+++ b/sdk/lib/async/timer.dart
@@ -4,7 +4,7 @@
part of dart.async;
-/// A count-down timer that can be configured to fire once or repeatedly.
+/// A countdown timer that can be configured to fire once or repeatedly.
///
/// The timer counts down from the specified duration to 0.
/// When the timer reaches 0, the timer invokes the specified callback function.
@@ -17,27 +17,33 @@
/// following example (taking advantage of the multiplication operator of
/// the [Duration] class):
/// ```dart
-/// const timeout = Duration(seconds: 3);
-/// const ms = Duration(milliseconds: 1);
-///
-/// Timer startTimeout([int? milliseconds]) {
-/// var duration = milliseconds == null ? timeout : ms * milliseconds;
-/// return Timer(duration, handleTimeout);
+/// void main() {
+/// scheduleTimeout(5 * 1000); // 5 seconds.
/// }
-/// ...
+///
+/// Timer scheduleTimeout([int milliseconds = 10000]) =>
+/// Timer(Duration(milliseconds: milliseconds), handleTimeout);
+///
/// void handleTimeout() { // callback function
-/// ...
+/// // Do some work.
/// }
/// ```
-/// Note: If Dart code using [Timer] is compiled to JavaScript, the finest
+/// **Note:** If Dart code using [Timer] is compiled to JavaScript, the finest
/// granularity available in the browser is 4 milliseconds.
///
-/// See [Stopwatch] for measuring elapsed time.
+/// See also:
+/// * [Stopwatch] for measuring elapsed time.
abstract class Timer {
/// Creates a new timer.
///
/// The [callback] function is invoked after the given [duration].
///
+ /// Example:
+ /// ```dart
+ /// final timer =
+ /// Timer(const Duration(seconds: 5), () => print('Timer finished'));
+ /// // Outputs after 5 seconds: "Timer finished".
+ /// ```
factory Timer(Duration duration, void Function() callback) {
if (Zone.current == Zone.root) {
// No need to bind the callback. We know that the root's timer will
@@ -64,6 +70,24 @@
/// scheduled for - even if the actual callback was delayed.
///
/// [duration] must a non-negative [Duration].
+ ///
+ /// Example:
+ /// ```dart
+ /// var counter = 3;
+ /// Timer.periodic(const Duration(seconds: 2), (timer) {
+ /// print(timer.tick);
+ /// counter--;
+ /// if (counter == 0) {
+ /// print('Cancel timer');
+ /// timer.cancel();
+ /// }
+ /// });
+ /// // Outputs:
+ /// // 1
+ /// // 2
+ /// // 3
+ /// // "Cancel timer"
+ /// ```
factory Timer.periodic(Duration duration, void callback(Timer timer)) {
if (Zone.current == Zone.root) {
// No need to bind the callback. We know that the root's timer will
@@ -77,6 +101,11 @@
/// Runs the given [callback] asynchronously as soon as possible.
///
/// This function is equivalent to `new Timer(Duration.zero, callback)`.
+ ///
+ /// Example:
+ /// ```dart
+ /// Timer.run(() => print('timer run'));
+ /// ```
static void run(void Function() callback) {
new Timer(Duration.zero, callback);
}
@@ -86,6 +115,14 @@
/// Once a [Timer] has been canceled, the callback function will not be called
/// by the timer. Calling [cancel] more than once on a [Timer] is allowed, and
/// will have no further effect.
+ ///
+ /// Example:
+ /// ```dart
+ /// final timer =
+ /// Timer(const Duration(seconds: 5), () => print('Timer finished'));
+ /// // Cancel timer, callback never called.
+ /// timer.cancel();
+ /// ```
void cancel();
/// The number of durations preceding the most recent timer event.
@@ -99,6 +136,25 @@
/// and no callback is invoked for them.
/// The [tick] count reflects the number of durations that have passed and
/// not the number of callback invocations that have happened.
+ ///
+ /// Example:
+ /// ```dart
+ /// final stopwatch = Stopwatch()..start();
+ /// Timer.periodic(const Duration(seconds: 1), (timer) {
+ /// print(timer.tick);
+ /// if (timer.tick == 1) {
+ /// while (stopwatch.elapsedMilliseconds < 4500) {
+ /// // Run uninterrupted for another 3.5 seconds!
+ /// // The latest due tick after that is the 4-second tick.
+ /// }
+ /// } else {
+ /// timer.cancel();
+ /// }
+ /// });
+ /// // Outputs:
+ /// // 1
+ /// // 4
+ /// ```
int get tick;
/// Returns whether the timer is still active.
diff --git a/sdk/lib/core/double.dart b/sdk/lib/core/double.dart
index 2bf8104..7c04f358 100644
--- a/sdk/lib/core/double.dart
+++ b/sdk/lib/core/double.dart
@@ -16,6 +16,11 @@
///
/// It is a compile-time error for a class to attempt to extend or implement
/// double.
+///
+/// **See also:**
+/// * [num] the super class for [double].
+/// * [Numbers](https://dart.dev/guides/language/numbers) in
+/// [A tour of the Dart language](https://dart.dev/guides/language/language-tour).
abstract class double extends num {
static const double nan = 0.0 / 0.0;
static const double infinity = 1.0 / 0.0;
@@ -54,7 +59,14 @@
/// `(3.5).round() == 4` and `(-3.5).round() == -4`.
///
/// Throws an [UnsupportedError] if this number is not finite
- /// (NaN or an infinity), .
+ /// (NaN or an infinity).
+ /// ```dart
+ /// print(3.0.round()); // 3
+ /// print(3.25.round()); // 3
+ /// print(3.5.round()); // 4
+ /// print(3.75.round()); // 4
+ /// print((-3.5).round()); // -4
+ /// ```
int round();
/// Returns the greatest integer no greater than this number.
@@ -62,15 +74,31 @@
/// Rounds the number towards negative infinity.
///
/// Throws an [UnsupportedError] if this number is not finite
- /// (NaN or infinity), .
+ /// (NaN or infinity).
+ /// ```dart
+ /// print(1.99999.floor()); // 1
+ /// print(2.0.floor()); // 2
+ /// print(2.99999.floor()); // 2
+ /// print((-1.99999).floor()); // -2
+ /// print((-2.0).floor()); // -2
+ /// print((-2.00001).floor()); // -3
+ /// ```
int floor();
- /// Returns the least integer which is not smaller than this number.
+ /// Returns the least integer that is not smaller than this number.
///
/// Rounds the number towards infinity.
///
/// Throws an [UnsupportedError] if this number is not finite
- /// (NaN or an infinity), .
+ /// (NaN or an infinity).
+ /// ```dart
+ /// print(1.99999.ceil()); // 2
+ /// print(2.0.ceil()); // 2
+ /// print(2.00001.ceil()); // 3
+ /// print((-1.99999).ceil()); // -1
+ /// print((-2.0).ceil()); // -2
+ /// print((-2.00001).ceil()); // -2
+ /// ```
int ceil();
/// Returns the integer obtained by discarding any fractional
@@ -79,7 +107,15 @@
/// Rounds the number towards zero.
///
/// Throws an [UnsupportedError] if this number is not finite
- /// (NaN or an infinity), .
+ /// (NaN or an infinity).
+ /// ```dart
+ /// print(2.00001.truncate()); // 2
+ /// print(1.99999.truncate()); // 1
+ /// print(0.5.truncate()); // 0
+ /// print((-0.5).truncate()); // 0
+ /// print((-1.5).truncate()); // -1
+ /// print((-2.5).truncate()); // -2
+ /// ```
int truncate();
/// Returns the integer double value closest to `this`.
@@ -92,8 +128,15 @@
///
/// For the purpose of rounding, `-0.0` is considered to be below `0.0`,
/// and `-0.0` is therefore considered closer to negative numbers than `0.0`.
- /// This means that for a value, `d` in the range `-0.5 < d < 0.0`,
+ /// This means that for a value `d` in the range `-0.5 < d < 0.0`,
/// the result is `-0.0`.
+ /// ```dart
+ /// print(3.0.roundToDouble()); // 3.0
+ /// print(3.25.roundToDouble()); // 3.0
+ /// print(3.5.roundToDouble()); // 4.0
+ /// print(3.75.roundToDouble()); // 4.0
+ /// print((-3.5).roundToDouble()); // -4.0
+ /// ```
double roundToDouble();
/// Returns the greatest integer double value no greater than `this`.
@@ -103,6 +146,14 @@
///
/// For the purpose of rounding, `-0.0` is considered to be below `0.0`.
/// A number `d` in the range `0.0 < d < 1.0` will return `0.0`.
+ /// ```dart
+ /// print(1.99999.floorToDouble()); // 1.0
+ /// print(2.0.floorToDouble()); // 2.0
+ /// print(2.99999.floorToDouble()); // 2.0
+ /// print((-1.99999).floorToDouble()); // -2.0
+ /// print((-2.0).floorToDouble()); // -2.0
+ /// print((-2.00001).floorToDouble()); // -3.0
+ /// ```
double floorToDouble();
/// Returns the least integer double value no smaller than `this`.
@@ -112,6 +163,14 @@
///
/// For the purpose of rounding, `-0.0` is considered to be below `0.0`.
/// A number `d` in the range `-1.0 < d < 0.0` will return `-0.0`.
+ /// ```dart
+ /// print(1.99999.ceilToDouble()); // 2.0
+ /// print(2.0.ceilToDouble()); // 2.0
+ /// print(2.00001.ceilToDouble()); // 3.0
+ /// print((-1.99999).ceilToDouble()); // -1.0
+ /// print((-2.0).ceilToDouble()); // -2.0
+ /// print((-2.00001).ceilToDouble()); // -2.0
+ /// ```
double ceilToDouble();
/// Returns the integer double value obtained by discarding any fractional
@@ -123,6 +182,15 @@
/// For the purpose of rounding, `-0.0` is considered to be below `0.0`.
/// A number `d` in the range `-1.0 < d < 0.0` will return `-0.0`, and
/// in the range `0.0 < d < 1.0` it will return 0.0.
+ /// ```dart
+ /// print(2.5.truncateToDouble()); // 2.0
+ /// print(2.00001.truncateToDouble()); // 2.0
+ /// print(1.99999.truncateToDouble()); // 1.0
+ /// print(0.5.truncateToDouble()); // 0.0
+ /// print((-0.5).truncateToDouble()); // -0.0
+ /// print((-1.5).truncateToDouble()); // -1.0
+ /// print((-2.5).truncateToDouble()); // -2.0
+ /// ```
double truncateToDouble();
/// Provide a representation of this [double] value.
@@ -139,7 +207,7 @@
/// `d` is NaN).
String toString();
- /// Parse [source] as an double literal and return its value.
+ /// Parse [source] as a double literal and return its value.
///
/// Accepts an optional sign (`+` or `-`) followed by either the characters
/// "Infinity", the characters "NaN" or a floating-point representation.
@@ -176,9 +244,23 @@
external static double parse(String source,
[@deprecated double onError(String source)?]);
- /// Parse [source] as an double literal and return its value.
+ /// Parse [source] as a double literal and return its value.
///
- /// Like [parse] except that this function returns `null` for invalid inputs
+ /// Like [parse], except that this function returns `null` for invalid inputs
/// instead of throwing.
+ ///
+ /// Example:
+ /// ```dart
+ /// var value = double.tryParse('3.14'); // 3.14
+ /// value = double.tryParse(' 3.14 \xA0'); // 3.14
+ /// value = double.tryParse('0.'); // 0.0
+ /// value = double.tryParse('.0'); // 0.0
+ /// value = double.tryParse('-1.e3'); // -1000.0
+ /// value = double.tryParse('1234E+7'); // 12340000000.0
+ /// value = double.tryParse('+.12e-9'); // 1.2e-10
+ /// value = double.tryParse('-NaN'); // NaN
+ /// value = double.tryParse('0xFF'); // null
+ /// value = double.tryParse(double.infinity.toString()); // Infinity
+ /// ```
external static double? tryParse(String source);
}
diff --git a/sdk/lib/core/duration.dart b/sdk/lib/core/duration.dart
index 1e6b729..11fc5c8 100644
--- a/sdk/lib/core/duration.dart
+++ b/sdk/lib/core/duration.dart
@@ -12,7 +12,7 @@
///
/// Durations are context independent. For example, a duration of 2 days is
/// always 48 hours, even when it is added to a `DateTime` just when the
-/// time zone is about to do a daylight-savings switch. (See [DateTime.add]).
+/// time zone is about to make a daylight-savings switch. (See [DateTime.add]).
///
/// Despite the same name, a `Duration` object does not implement "Durations"
/// as specified by ISO 8601. In particular, a duration object does not keep
@@ -20,34 +20,69 @@
/// only uses these arguments to compute the length of the corresponding time
/// interval.
///
-/// To create a new Duration object, use this class's single constructor
+/// To create a new `Duration` object, use this class's single constructor
/// giving the appropriate arguments:
/// ```dart
-/// var fastestMarathon = const Duration(hours: 2, minutes: 3, seconds: 2);
+/// const fastestMarathon = Duration(hours: 2, minutes: 3, seconds: 2);
/// ```
-/// The [Duration] is the sum of all individual parts.
-/// This means that individual parts can be larger than the next-bigger unit.
-/// For example, [inMinutes] can be greater than 59.
-/// ```dart
-/// const fastestMarathon = const Duration(hours: 2, minutes: 3, seconds: 2);
-/// assert(fastestMarathon.inMinutes == 123);
-/// ```
-/// All individual parts are allowed to be negative.
+/// The [Duration] represents a single number of microseconds,
+/// which is the sum of all the individual arguments to the constructor.
///
+/// Properties can access that single number in different ways.
+/// For example the [inMinutes] gives the number of whole minutes
+/// in the total duration, which includes the minutes that were provided
+/// as "hours" to the constructor, and can be larger than 59.
+///
+/// ```dart
+/// const fastestMarathon = Duration(hours: 2, minutes: 3, seconds: 2);
+/// print(fastestMarathon.inDays); // 0
+/// print(fastestMarathon.inHours); // 2
+/// print(fastestMarathon.inMinutes); // 123
+/// print(fastestMarathon.inSeconds); // 7382
+/// print(fastestMarathon.inMilliseconds); // 7382000
+/// ```
+/// The duration can be negative, in which case
+/// all the properties derived from the duration are also non-positive.
+/// ```dart
+/// const overDayAgo = Duration(days: -1, hours: -10);
+/// print(overDayAgo.inDays); // -1
+/// print(overDayAgo.inHours); // -34
+/// print(overDayAgo.inMinutes); // -2040
+/// ```
/// Use one of the properties, such as [inDays],
-/// to retrieve the integer value of the Duration in the specified time unit.
+/// to retrieve the integer value of the `Duration` in the specified time unit.
/// Note that the returned value is rounded down.
/// For example,
/// ```dart
-/// var aLongWeekend = const Duration(hours: 88);
-/// assert(aLongWeekend.inDays == 3);
+/// const aLongWeekend = Duration(hours: 88);
+/// print(aLongWeekend.inDays); // 3
/// ```
/// This class provides a collection of arithmetic
/// and comparison operators,
/// plus a set of constants useful for converting time units.
+/// ```dart
+/// const firstHalf = Duration(minutes: 45); // 00:45:00.000000
+/// const secondHalf = Duration(minutes: 45); // 00:45:00.000000
+/// const overTime = Duration(minutes: 30); // 00:30:00.000000
+/// final maxGameTime = firstHalf + secondHalf + overTime;
+/// print(maxGameTime.inMinutes); // 120
///
-/// See [DateTime] to represent a point in time.
-/// See [Stopwatch] to measure time-spans.
+/// // The duration of the firstHalf and secondHalf is the same, returns 0.
+/// var result = firstHalf.compareTo(secondHalf);
+/// print(result); // 0
+///
+/// // Duration of overTime is shorter than firstHalf, returns < 0.
+/// result = overTime.compareTo(firstHalf);
+/// print(result); // < 0
+///
+/// // Duration of secondHalf is longer than overTime, returns > 0.
+/// result = secondHalf.compareTo(overTime);
+/// print(result); // > 0
+/// ```
+///
+/// **See also:**
+/// * [DateTime] to represent a point in time.
+/// * [Stopwatch] to measure time-spans.
class Duration implements Comparable<Duration> {
/// The number of microseconds per millisecond.
static const int microsecondsPerMillisecond = 1000;
@@ -130,6 +165,11 @@
/// and it might lose precision.
///
/// All arguments are 0 by default.
+ /// ```dart
+ /// const duration = Duration(days: 1, hours: 8, minutes: 56, seconds: 59,
+ /// milliseconds: 30, microseconds: 10);
+ /// print(duration); // 32:56:59.030010
+ /// ```
const Duration(
{int days = 0,
int hours = 0,
@@ -193,41 +233,69 @@
bool operator >=(Duration other) => this._duration >= other._duration;
/// The number of entire days spanned by this [Duration].
+ ///
+ /// For example, a duration of four days and three hours
+ /// has four entire days.
+ /// ```dart
+ /// const duration = Duration(days: 4, hours: 3);
+ /// print(duration.inDays); // 4
+ /// ```
int get inDays => _duration ~/ Duration.microsecondsPerDay;
/// The number of entire hours spanned by this [Duration].
///
/// The returned value can be greater than 23.
- /// For example a duration of four days and three hours
+ /// For example, a duration of four days and three hours
/// has 99 entire hours.
+ /// ```dart
+ /// const duration = Duration(days: 4, hours: 3);
+ /// print(duration.inHours); // 99
+ /// ```
int get inHours => _duration ~/ Duration.microsecondsPerHour;
/// The number of whole minutes spanned by this [Duration].
///
/// The returned value can be greater than 59.
- /// For example a duration of three hours and 12 minutes
+ /// For example, a duration of three hours and 12 minutes
/// has 192 minutes.
+ /// ```dart
+ /// const duration = Duration(hours: 3, minutes: 12);
+ /// print(duration.inMinutes); // 192
+ /// ```
int get inMinutes => _duration ~/ Duration.microsecondsPerMinute;
/// The number of whole seconds spanned by this [Duration].
///
/// The returned value can be greater than 59.
- /// For example a duration of three minutes and 12 seconds
+ /// For example, a duration of three minutes and 12 seconds
/// has 192 seconds.
+ /// ```dart
+ /// const duration = Duration(minutes: 3, seconds: 12);
+ /// print(duration.inSeconds); // 192
+ /// ```
int get inSeconds => _duration ~/ Duration.microsecondsPerSecond;
/// The number of whole milliseconds spanned by this [Duration].
///
/// The returned value can be greater than 999.
- /// For example a duration of three seconds and 125 milliseconds
+ /// For example, a duration of three seconds and 125 milliseconds
/// has 3125 milliseconds.
+ /// ```dart
+ /// const duration = Duration(seconds: 3, milliseconds: 125);
+ /// print(duration.inMilliseconds); // 3125
+ /// ```
int get inMilliseconds => _duration ~/ Duration.microsecondsPerMillisecond;
/// The number of whole microseconds spanned by this [Duration].
///
/// The returned value can be greater than 999999.
- /// For example a duration of three seconds, 125 milliseconds and
+ /// For example, a duration of three seconds, 125 milliseconds and
/// 369 microseconds has 3125369 microseconds.
+ /// ```dart
+ /// const duration = Duration(seconds: 3, milliseconds: 125,
+ /// microseconds: 369);
+ /// print(duration.inMicroseconds); // 3125369
+ /// ```
int get inMicroseconds => _duration;
/// Whether this [Duration] has the same length as [other].
@@ -255,11 +323,11 @@
/// Returns a string with hours, minutes, seconds, and microseconds, in the
/// following format: `H:MM:SS.mmmmmm`. For example,
/// ```dart
- /// var d = Duration(days: 1, hours: 1, minutes: 33, microseconds: 500);
- /// d.toString(); // "25:33:00.000500"
+ /// var d = const Duration(days: 1, hours: 1, minutes: 33, microseconds: 500);
+ /// print(d.toString()); // 25:33:00.000500
///
- /// d = Duration(days: 0, hours: 1, minutes: 10, microseconds: 500);
- /// d.toString(); // "1:10:00.000500"
+ /// d = const Duration(hours: 1, minutes: 10, microseconds: 500);
+ /// print(d.toString()); // 1:10:00.000500
/// ```
String toString() {
var microseconds = inMicroseconds;
diff --git a/sdk/lib/core/int.dart b/sdk/lib/core/int.dart
index ccf2775..32c6682 100644
--- a/sdk/lib/core/int.dart
+++ b/sdk/lib/core/int.dart
@@ -20,6 +20,11 @@
/// operands to 32-bit integers when compiled to JavaScript.
///
/// Classes cannot extend, implement, or mix in `int`.
+///
+/// **See also:**
+/// * [num] the super class for [int].
+/// * [Numbers](https://dart.dev/guides/language/numbers) in
+/// [A tour of the Dart language](https://dart.dev/guides/language/language-tour).
abstract class int extends num {
/// Returns the integer value of the given environment declaration [name].
///
@@ -59,6 +64,11 @@
///
/// If both operands are negative, the result is negative, otherwise
/// the result is non-negative.
+ /// ```dart
+ /// print((2 & 1).toRadixString(2)); // 0010 & 0001 -> 0000
+ /// print((3 & 1).toRadixString(2)); // 0011 & 0001 -> 0001
+ /// print((10 & 2).toRadixString(2)); // 1010 & 0010 -> 0010
+ /// ```
int operator &(int other);
/// Bit-wise or operator.
@@ -69,6 +79,13 @@
///
/// If both operands are non-negative, the result is non-negative,
/// otherwise the result is negative.
+ ///
+ /// Example:
+ /// ```dart
+ /// print((2 | 1).toRadixString(2)); // 0010 | 0001 -> 0011
+ /// print((3 | 1).toRadixString(2)); // 0011 | 0001 -> 0011
+ /// print((10 | 2).toRadixString(2)); // 1010 | 0010 -> 1010
+ /// ```
int operator |(int other);
/// Bit-wise exclusive-or operator.
@@ -79,6 +96,13 @@
///
/// If the operands have the same sign, the result is non-negative,
/// otherwise the result is negative.
+ ///
+ /// Example:
+ /// ```dart
+ /// print((2 ^ 1).toRadixString(2)); // 0010 ^ 0001 -> 0011
+ /// print((3 ^ 1).toRadixString(2)); // 0011 ^ 0001 -> 0010
+ /// print((10 ^ 2).toRadixString(2)); // 1010 ^ 0010 -> 1000
+ /// ```
int operator ^(int other);
/// The bit-wise negate operator.
@@ -99,15 +123,31 @@
/// mask.
///
/// It is an error if [shiftAmount] is negative.
+ ///
+ /// Example:
+ /// ```dart
+ /// print((3 << 1).toRadixString(2)); // 0011 -> 0110
+ /// print((9 << 2).toRadixString(2)); // 1001 -> 100100
+ /// print((10 << 3).toRadixString(2)); // 1010 -> 1010000
+ /// ```
int operator <<(int shiftAmount);
/// Shift the bits of this integer to the right by [shiftAmount].
///
/// Shifting to the right makes the number smaller and drops the least
/// significant bits, effectively doing an integer division by
- ///`pow(2, shiftIndex)`.
+ /// `pow(2, shiftIndex)`.
///
/// It is an error if [shiftAmount] is negative.
+ ///
+ /// Example:
+ /// ```dart
+ /// print((3 >> 1).toRadixString(2)); // 0011 -> 0001
+ /// print((9 >> 2).toRadixString(2)); // 1001 -> 0010
+ /// print((10 >> 3).toRadixString(2)); // 1010 -> 0001
+ /// print((-6 >> 2).toRadixString); // 111...1010 -> 111...1110 == -2
+ /// print((-85 >> 3).toRadixString); // 111...10101011 -> 111...11110101 == -11
+ /// ```
int operator >>(int shiftAmount);
/// Bitwise unsigned right shift by [shiftAmount] bits.
@@ -117,6 +157,13 @@
/// and zero-bits are shifted in as the new most significant bits.
///
/// The [shiftAmount] must be non-negative.
+ ///
+ /// Example:
+ /// ```dart
+ /// print((3 >>> 1).toRadixString(2)); // 0011 -> 0001
+ /// print((9 >>> 2).toRadixString(2)); // 1001 -> 0010
+ /// print(((-9) >>> 2).toRadixString(2)); // 111...1011 -> 001...1110 (> 0)
+ /// ```
int operator >>>(int shiftAmount);
/// Returns this integer to the power of [exponent] modulo [modulus].
@@ -144,6 +191,15 @@
/// For any integer `x`, `x.gcd(x)` is `x.abs()`.
///
/// If both `this` and `other` is zero, the result is also zero.
+ ///
+ /// Example:
+ /// ```dart
+ /// print(4.gcd(2)); // 2
+ /// print(8.gcd(4)); // 4
+ /// print(10.gcd(12)); // 2
+ /// print(10.gcd(0)); // 10
+ /// print((-2).gcd(-3)); // 1
+ /// ```
int gcd(int other);
/// Returns true if and only if this integer is even.
@@ -196,8 +252,8 @@
int toUnsigned(int width);
/// Returns the least significant [width] bits of this integer, extending the
- /// highest retained bit to the sign. This is the same as truncating the value
- /// to fit in [width] bits using an signed 2-s complement representation. The
+ /// highest retained bit to the sign. This is the same as truncating the value
+ /// to fit in [width] bits using an signed 2-s complement representation. The
/// returned value has the same bit value in all positions higher than [width].
///
/// ```dart
@@ -276,9 +332,28 @@
/// Converts [this] to a string representation in the given [radix].
///
/// In the string representation, lower-case letters are used for digits above
- /// '9', with 'a' being 10 an 'z' being 35.
+ /// '9', with 'a' being 10 and 'z' being 35.
///
/// The [radix] argument must be an integer in the range 2 to 36.
+ ///
+ /// Example:
+ /// ```dart
+ /// // Binary (base 2).
+ /// print(12.toRadixString(2)); // 1100
+ /// print(31.toRadixString(2)); // 11111
+ /// print(2021.toRadixString(2)); // 11111100101
+ /// print((-12).toRadixString(2)); // -1100
+ /// // Octal (base 8).
+ /// print(12.toRadixString(8)); // 14
+ /// print(31.toRadixString(8)); // 37
+ /// print(2021.toRadixString(8)); // 3745
+ /// // Hexadecimal (base 16).
+ /// print(12.toRadixString(16)); // c
+ /// print(31.toRadixString(16)); // 1f
+ /// print(2021.toRadixString(16)); // 7e5
+ /// // Base 36.
+ /// print((35 * 36 + 1).toRadixString(36)); // z1
+ /// ```
String toRadixString(int radix);
/// Parse [source] as a, possibly signed, integer literal and return its value.
@@ -309,6 +384,7 @@
///
/// Instead of throwing and immediately catching the [FormatException],
/// instead use [tryParse] to handle a parsing error.
+ ///
/// Example:
/// ```dart
/// var value = int.tryParse(text);
@@ -333,5 +409,29 @@
///
/// Like [parse] except that this function returns `null` where a
/// similar call to [parse] would throw a [FormatException].
+ ///
+ /// Example:
+ /// ```dart
+ /// print(int.tryParse('2021')); // 2021
+ /// print(int.tryParse('1f')); // null
+ /// // From binary (base 2) value.
+ /// print(int.tryParse('1100', radix: 2)); // 12
+ /// print(int.tryParse('00011111', radix: 2)); // 31
+ /// print(int.tryParse('011111100101', radix: 2)); // 2021
+ /// // From octal (base 8) value.
+ /// print(int.tryParse('14', radix: 8)); // 12
+ /// print(int.tryParse('37', radix: 8)); // 31
+ /// print(int.tryParse('3745', radix: 8)); // 2021
+ /// // From hexadecimal (base 16) value.
+ /// print(int.tryParse('c', radix: 16)); // 12
+ /// print(int.tryParse('1f', radix: 16)); // 31
+ /// print(int.tryParse('7e5', radix: 16)); // 2021
+ /// // From base 35 value.
+ /// print(int.tryParse('y1', radix: 35)); // 1191 == 34 * 35 + 1
+ /// print(int.tryParse('z1', radix: 35)); // null
+ /// // From base 36 value.
+ /// print(int.tryParse('y1', radix: 36)); // 1225 == 34 * 36 + 1
+ /// print(int.tryParse('z1', radix: 36)); // 1261 == 35 * 36 + 1
+ /// ```
external static int? tryParse(String source, {int? radix});
}
diff --git a/sdk/lib/core/list.dart b/sdk/lib/core/list.dart
index 1c51340..bc3ac77 100644
--- a/sdk/lib/core/list.dart
+++ b/sdk/lib/core/list.dart
@@ -9,11 +9,14 @@
/// Subclasses of this class implement different kinds of lists.
/// The most common kinds of lists are:
///
-/// * Fixed-length list.
+/// * **Fixed-length list**
+///
/// An error occurs when attempting to use operations
/// that can change the length of the list.
///
-/// * Growable list. Full implementation of the API defined in this class.
+/// * **Growable list**
+///
+/// Full implementation of the API defined in this class.
///
/// The default growable list, as created by `[]`, keeps
/// an internal buffer, and grows that buffer when necessary. This guarantees
@@ -23,18 +26,78 @@
/// operation will need to immediately increase the buffer capacity.
/// Other list implementations may have different performance behavior.
///
-/// The following code illustrates that some List implementations support
-/// only a subset of the API.
+/// Example of fixed-length list:
/// ```dart
-/// var fixedLengthList = List<int>.filled(5, 0);
-/// fixedLengthList.length = 0; // Error
-/// fixedLengthList.add(499); // Error
+/// final fixedLengthList = List<int>.filled(5, 0); // Creates fixed-length list.
+/// print(fixedLengthList); // [0, 0, 0, 0, 0]
/// fixedLengthList[0] = 87;
-/// var growableList = [1, 2];
-/// growableList.length = 0;
-/// growableList.add(499);
-/// growableList[0] = 87;
+/// fixedLengthList.setAll(1, [1, 2, 3]);
+/// print(fixedLengthList); // [87, 1, 2, 3, 0]
+/// // Fixed length list length can't be changed or increased
+/// fixedLengthList.length = 0; // Throws
+/// fixedLengthList.add(499); // Throws
/// ```
+///
+/// Example of growable list:
+/// ```dart
+/// final growableList = <String>['A', 'B']; // Creates growable list.
+/// ```
+/// To add data to the growable list, use [operator[]=], [add] or [addAll].
+/// ```
+/// growableList[0] = 'G';
+/// print(growableList); // [G, B]
+/// growableList.add('X');
+/// growableList.addAll({'C', 'B'});
+/// print(growableList); // [G, B, X, C, B]
+/// ```
+/// To check whether, and where, the element is in the list, use [indexOf] or
+/// [lastIndexOf].
+/// ```
+/// final indexA = growableList.indexOf('A'); // -1 (not in the list)
+/// final firstIndexB = growableList.indexOf('B'); // 1
+/// final lastIndexB = growableList.lastIndexOf('B'); // 4
+/// ```
+/// To remove an element from the growable list, use [remove], [removeAt],
+/// [removeLast], [removeRange] or [removeWhere].
+/// ```
+/// growableList.remove('C');
+/// growableList.removeLast();
+/// print(growableList); // [G, B, X]
+/// ```
+/// To insert an element at position in the list, use [insert] or [insertAll].
+/// ```
+/// growableList.insert(1, 'New');
+/// print(growableList); // [G, New, B, X]
+/// ```
+/// To replace a range of elements in the list, use [fillRange], [replaceRange]
+/// or [setRange].
+/// ```
+/// growableList.replaceRange(0, 2, ['AB', 'A']);
+/// print(growableList); // [AB, A, B, X]
+/// growableList.fillRange(2, 4, 'F');
+/// print(growableList); // [AB, A, F, F]
+/// ```
+/// To sort the elements of the list, use [sort].
+/// ```
+/// growableList.sort((a, b) => a.compareTo(b));
+/// print(growableList); // [A, AB, F, F]
+/// ```
+/// To shuffle the elements of this list randomly, use [shuffle].
+/// ```
+/// growableList.shuffle();
+/// print(growableList); // e.g. [AB, F, A, F]
+/// ```
+/// To find the first element satisfying some predicate, or give a default
+/// value if none do, use [firstWhere].
+/// ```
+/// bool isVowel(String char) => char.length == 1 && "AEIOU".contains(char);
+/// final firstVowel = growableList.firstWhere(isVowel, orElse: () => ''); // ''
+/// ```
+/// There are similar [lastWhere] and [singleWhere] methods.
+///
+/// A list is an [Iterable] and supports all its methods, including
+/// [where], [map], [whereType] and [toList].
+///
/// Lists are [Iterable]. Iteration occurs over values in index order. Changing
/// the values does not affect iteration, but changing the valid
/// indices—that is, changing the list's length—between iteration
@@ -52,7 +115,7 @@
abstract class List<E> implements EfficientLengthIterable<E> {
/// Creates a list of the given length.
///
- /// **NOTICE**: This constructor cannot be used in null-safe code.
+ /// **NOTE**: This constructor cannot be used in null-safe code.
/// Use [List.filled] to create a non-empty list.
/// This requires a fill value to initialize the list elements with.
/// To create an empty list, use `[]` for a growable list or
@@ -93,7 +156,7 @@
///
/// Example:
/// ```dart
- /// List<int>.filled(3, 0, growable: true); // [0, 0, 0]
+ /// final zeroList = List<int>.filled(3, 0, growable: true); // [0, 0, 0]
/// ```
///
/// The created list is fixed-length if [growable] is false (the default)
@@ -106,16 +169,16 @@
///
/// All elements of the created list share the same [fill] value.
/// ```dart
- /// var shared = List.filled(3, []);
+ /// final shared = List.filled(3, []);
/// shared[0].add(499);
- /// print(shared); // => [[499], [499], [499]]
+ /// print(shared); // [[499], [499], [499]]
/// ```
/// You can use [List.generate] to create a list with a fixed length
/// and a new object at each position.
/// ```dart
- /// var unique = List.generate(3, (_) => []);
+ /// final unique = List.generate(3, (_) => []);
/// unique[0].add(499);
- /// print(unique); // => [[499], [], []]
+ /// print(unique); // [[499], [], []]
/// ```
external factory List.filled(int length, E fill, {bool growable = false});
@@ -124,6 +187,13 @@
/// If [growable] is `false`, which is the default,
/// the list is a fixed-length list of length zero.
/// If [growable] is `true`, the list is growable and equivalent to `<E>[]`.
+ /// ```dart
+ /// final growableList = List.empty(growable: true); // []
+ /// growableList.add(1); // [1]
+ ///
+ /// final fixedLengthList = List.empty(growable: false);
+ /// fixedLengthList.add(1); // error
+ /// ```
@Since("2.9")
external factory List.empty({bool growable = false});
@@ -132,12 +202,24 @@
/// The [Iterator] of [elements] provides the order of the elements.
///
/// All the [elements] should be instances of [E].
+ ///
+ /// Example:
+ /// ```dart
+ /// final numbers = <num>[1, 2, 3];
+ /// final listFrom = List<int>.from(numbers);
+ /// print(listFrom); // [1, 2, 3]
+ /// ```
/// The `elements` iterable itself may have any element type, so this
/// constructor can be used to down-cast a `List`, for example as:
- /// ```dart
- /// List<dynamic> dynList = ...some JSON value...;
- /// List<Map<String, dynamic>> fooList =
- /// List.from(dynList.where((x) => x is Map && x["kind"] == "foo"));
+ /// ```dart import:convert
+ /// const jsonArray = '''
+ /// [{"text": "foo", "value": 1, "status": true},
+ /// {"text": "bar", "value": 2, "status": false}]
+ /// ''';
+ /// final List<dynamic> dynamicList = jsonDecode(jsonArray);
+ /// final List<Map<String, dynamic>> fooData =
+ /// List.from(dynamicList.where((x) => x is Map && x['text'] == 'foo'));
+ /// print(fooData); // [{text: foo, value: 1, status: true}]
/// ```
///
/// This constructor creates a growable list when [growable] is true;
@@ -150,6 +232,11 @@
///
/// This constructor creates a growable list when [growable] is true;
/// otherwise, it returns a fixed-length list.
+ /// ```dart
+ /// final numbers = <int>[1, 2, 3];
+ /// final listOf = List<num>.of(numbers);
+ /// print(listOf); // [1, 2, 3]
+ /// ```
external factory List.of(Iterable<E> elements, {bool growable = true});
/// Generates a list of values.
@@ -158,7 +245,13 @@
/// calling [generator] for each index in the range `0` .. `length - 1`
/// in increasing order.
/// ```dart
- /// List<int>.generate(3, (int index) => index * index); // [0, 1, 4]
+ /// final growableList =
+ /// List<int>.generate(3, (int index) => index * index, growable: true);
+ /// print(growableList); // [0, 1, 4]
+ ///
+ /// final fixedLengthList =
+ /// List<int>.generate(3, (int index) => index * index, growable: false);
+ /// print(fixedLengthList); // [0, 1, 4]
/// ```
/// The created list is fixed-length if [growable] is set to false.
///
@@ -173,6 +266,11 @@
/// An unmodifiable list cannot have its length or elements changed.
/// If the elements are themselves immutable, then the resulting list
/// is also immutable.
+ /// ```dart
+ /// final numbers = <int>[1, 2, 3];
+ /// final unmodifiableList = List.unmodifiable(numbers); // [1, 2, 3]
+ /// unmodifiableList[1] = 87; // Throws.
+ /// ```
external factory List.unmodifiable(Iterable elements);
/// Adapts [source] to be a `List<T>`.
@@ -203,7 +301,7 @@
/// If [start] is omitted, it defaults to zero.
/// If [end] is omitted, it defaults to [source].length.
///
- /// If [source] and [target] is the same list, overlapping source and target
+ /// If [source] and [target] are the same list, overlapping source and target
/// ranges are respected so that the target range ends up containing the
/// initial content of the source range.
/// Otherwise the order of element copying is not guaranteed.
@@ -262,8 +360,8 @@
/// that is not an instance of [R], the access will throw instead.
///
/// Elements added to the list (e.g., by using [add] or [addAll])
- /// must be instance of [R] to be valid arguments to the adding function,
- /// and they must be instances of [E] as well to be accepted by
+ /// must be instances of [R] to be valid arguments to the adding function,
+ /// and they must also be instances of [E] to be accepted by
/// this list as well.
///
/// Methods which accept `Object?` as argument, like [contains] and [remove],
@@ -289,64 +387,120 @@
/// less than [length].
void operator []=(int index, E value);
- /// Updates the first position of the list to contain [value].
+ /// The first element of the list.
///
- /// Equivalent to `theList[0] = value;`.
+ /// The list must be non-empty when accessing its first element.
///
- /// The list must be non-empty.
+ /// The first element of a list can be modified, unlike an [Iterable].
+ /// A `list.first` is equivalent to `list[0]`,
+ /// both for getting and setting the value.
+ ///
+ /// ```dart
+ /// final numbers = <int>[1, 2, 3];
+ /// print(numbers.first); // 1
+ /// numbers.first = 10;
+ /// print(numbers.first); // 10
+ /// numbers.clear();
+ /// numbers.first; // Throws.
+ /// ```
void set first(E value);
- /// Updates the last position of the list to contain [value].
+ /// The last element of the list.
///
- /// Equivalent to `theList[theList.length - 1] = value;`.
+ /// The list must be non-empty when accessing its last element.
///
- /// The list must be non-empty.
+ /// The last element of a list can be modified, unlike an [Iterable].
+ /// A `list.last` is equivalent to `theList[theList.length - 1]`,
+ /// both for getting and setting the value.
+ ///
+ /// ```dart
+ /// final numbers = <int>[1, 2, 3];
+ /// print(numbers.last); // 3
+ /// numbers.last = 10;
+ /// print(numbers.last); // 10
+ /// numbers.clear();
+ /// numbers.last; // Throws.
+ /// ```
void set last(E value);
/// The number of objects in this list.
///
/// The valid indices for a list are `0` through `length - 1`.
+ /// ```dart
+ /// final numbers = <int>[1, 2, 3];
+ /// print(numbers.length); // 3
+ /// ```
int get length;
- /// Changes the length of this list.
+ /// Setting the `length` changes the number of elements in the list.
///
/// The list must be growable.
/// If [newLength] is greater than current length,
/// new entries are initialized to `null`,
/// so [newLength] must not be greater than the current length
/// if the element type [E] is non-nullable.
+ ///
+ /// ```dart
+ /// final maybeNumbers = <int?>[1, null, 3];
+ /// maybeNumbers.length = 5;
+ /// print(maybeNumbers); // [1, null, 3, null, null]
+ /// maybeNumbers.length = 2;
+ /// print(maybeNumbers); // [1, null]
+ ///
+ /// final numbers = <int>[1, 2, 3];
+ /// numbers.length = 1;
+ /// print(numbers); // [1]
+ /// numbers.length = 5; // Throws, cannot add `null`s.
+ /// ```
set length(int newLength);
/// Adds [value] to the end of this list,
/// extending the length by one.
///
/// The list must be growable.
+ ///
+ /// ```dart
+ /// final numbers = <int>[1, 2, 3];
+ /// numbers.add(4);
+ /// print(numbers); // [1, 2, 3, 4]
+ /// ```
void add(E value);
/// Appends all objects of [iterable] to the end of this list.
///
/// Extends the length of the list by the number of objects in [iterable].
/// The list must be growable.
+ ///
+ /// ```dart
+ /// final numbers = <int>[1, 2, 3];
+ /// numbers.addAll([4, 5, 6]);
+ /// print(numbers); // [1, 2, 3, 4, 5, 6]
+ /// ```
void addAll(Iterable<E> iterable);
/// An [Iterable] of the objects in this list in reverse order.
+ /// ```dart
+ /// final numbers = <String>['two', 'three', 'four'];
+ /// final reverseOrder = numbers.reversed;
+ /// print(reverseOrder.toList()); // [four, three, two]
+ /// ```
Iterable<E> get reversed;
/// Sorts this list according to the order specified by the [compare] function.
///
/// The [compare] function must act as a [Comparator].
/// ```dart
- /// var numbers = ['two', 'three', 'four'];
+ /// final numbers = <String>['two', 'three', 'four'];
/// // Sort from shortest to longest.
/// numbers.sort((a, b) => a.length.compareTo(b.length));
- /// print(numbers); // [two, four, three]
+ /// print(numbers); // [two, four, three]
/// ```
/// The default [List] implementations use [Comparable.compare] if
/// [compare] is omitted.
/// ```dart
- /// List<int> nums = [13, 2, -11];
- /// nums.sort();
- /// print(nums); // [-11, 2, 13]
+ /// final numbers = <int>[13, 2, -11, 0];
+ /// numbers.sort();
+ /// print(numbers); // [-11, 0, 2, 13]
/// ```
/// In that case, the elements of the list must be [Comparable] to
/// each other.
@@ -356,13 +510,18 @@
/// The sort function is not guaranteed to be stable, so distinct objects
/// that compare as equal may occur in any order in the result:
/// ```dart
- /// var numbers = ['one', 'two', 'three', 'four'];
+ /// final numbers = <String>['one', 'two', 'three', 'four'];
/// numbers.sort((a, b) => a.length.compareTo(b.length));
- /// print(numbers); // [one, two, four, three] OR [two, one, four, three]
+ /// print(numbers); // [one, two, four, three] OR [two, one, four, three]
/// ```
void sort([int compare(E a, E b)?]);
/// Shuffles the elements of this list randomly.
+ /// ```dart
+ /// final numbers = <int>[1, 2, 3, 4, 5];
+ /// numbers.shuffle();
+ /// print(numbers); // [1, 3, 4, 5, 2] OR some other random result.
+ /// ```
void shuffle([Random? random]);
/// The first index of [element] in this list.
@@ -371,13 +530,15 @@
/// The first time an object `o` is encountered so that `o == element`,
/// the index of `o` is returned.
/// ```dart
- /// var notes = ['do', 're', 'mi', 're'];
- /// notes.indexOf('re'); // 1
- /// notes.indexOf('re', 2); // 3
+ /// final notes = <String>['do', 're', 'mi', 're'];
+ /// print(notes.indexOf('re')); // 1
+ ///
+ /// final indexWithStart = notes.indexOf('re', 2); // 3
/// ```
/// Returns -1 if [element] is not found.
/// ```dart
- /// notes.indexOf('fa'); // -1
+ /// final notes = <String>['do', 're', 'mi', 're'];
+ /// final index = notes.indexOf('fa'); // -1
/// ```
int indexOf(E element, [int start = 0]);
@@ -388,14 +549,15 @@
/// the index of `o` is returned.
///
/// ```dart
- /// var notes = ['do', 're', 'mi', 're'];
- /// notes.indexWhere((note) => note.startsWith('r')); // 1
- /// notes.indexWhere((note) => note.startsWith('r'), 2); // 3
+ /// final notes = <String>['do', 're', 'mi', 're'];
+ /// final first = notes.indexWhere((note) => note.startsWith('r')); // 1
+ /// final second = notes.indexWhere((note) => note.startsWith('r'), 2); // 3
/// ```
///
/// Returns -1 if [element] is not found.
/// ```dart
- /// notes.indexWhere((note) => note.startsWith('k')); // -1
+ /// final notes = <String>['do', 're', 'mi', 're'];
+ /// final index = notes.indexWhere((note) => note.startsWith('k')); // -1
/// ```
int indexWhere(bool test(E element), [int start = 0]);
@@ -407,14 +569,17 @@
/// If [start] is omitted, it defaults to the [length] of the list.
///
/// ```dart
- /// var notes = ['do', 're', 'mi', 're'];
- /// notes.lastIndexWhere((note) => note.startsWith('r')); // 3
- /// notes.lastIndexWhere((note) => note.startsWith('r'), 2); // 1
+ /// final notes = <String>['do', 're', 'mi', 're'];
+ /// final first = notes.lastIndexWhere((note) => note.startsWith('r')); // 3
+ /// final second = notes.lastIndexWhere((note) => note.startsWith('r'),
+ /// 2); // 1
/// ```
///
/// Returns -1 if [element] is not found.
/// ```dart
- /// notes.lastIndexWhere((note) => note.startsWith('k')); // -1
+ /// final notes = <String>['do', 're', 'mi', 're'];
+ /// final index = notes.lastIndexWhere((note) => note.startsWith('k'));
+ /// print(index); // -1
/// ```
int lastIndexWhere(bool test(E element), [int? start]);
@@ -425,23 +590,33 @@
/// The first time an object `o` is encountered so that `o == element`,
/// the index of `o` is returned.
/// ```dart
- /// var notes = ['do', 're', 'mi', 're'];
- /// notes.lastIndexOf('re', 2); // 1
+ /// final notes = <String>['do', 're', 'mi', 're'];
+ /// const startIndex = 2;
+ /// final index = notes.lastIndexOf('re', startIndex); // 1
/// ```
/// If [start] is not provided, this method searches from the end of the
/// list.
/// ```dart
- /// notes.lastIndexOf('re'); // 3
+ /// final notes = <String>['do', 're', 'mi', 're'];
+ /// final index = notes.lastIndexOf('re'); // 3
/// ```
/// Returns -1 if [element] is not found.
/// ```dart
- /// notes.lastIndexOf('fa'); // -1
+ /// final notes = <String>['do', 're', 'mi', 're'];
+ /// final index = notes.lastIndexOf('fa'); // -1
/// ```
int lastIndexOf(E element, [int? start]);
/// Removes all objects from this list; the length of the list becomes zero.
///
/// The list must be growable.
+ ///
+ /// ```dart
+ /// final numbers = <int>[1, 2, 3];
+ /// numbers.clear();
+ /// print(numbers.length); // 0
+ /// print(numbers); // []
+ /// ```
void clear();
/// Inserts [element] at position [index] in this list.
@@ -451,6 +626,13 @@
///
/// The list must be growable.
/// The [index] value must be non-negative and no greater than [length].
+ ///
+ /// ```dart
+ /// final numbers = <int>[1, 2, 3, 4];
+ /// const index = 2;
+ /// numbers.insert(index, 10);
+ /// print(numbers); // [1, 2, 10, 3, 4]
+ /// ```
void insert(int index, E element);
/// Inserts all objects of [iterable] at position [index] in this list.
@@ -460,17 +642,18 @@
///
/// The list must be growable.
/// The [index] value must be non-negative and no greater than [length].
+ /// ```dart
+ /// final numbers = <int>[1, 2, 3, 4];
+ /// final insertItems = [10, 11];
+ /// numbers.insertAll(2, insertItems);
+ /// print(numbers); // [1, 2, 10, 11, 3, 4]
+ /// ```
void insertAll(int index, Iterable<E> iterable);
/// Overwrites elements with the objects of [iterable].
///
/// The elements of [iterable] are written into this list,
/// starting at position [index].
- /// ```dart
- /// var list = ['a', 'b', 'c', 'd'];
- /// list.setAll(1, ['bee', 'sea']);
- /// list.join(', '); // 'a, bee, sea, d'
- /// ```
/// This operation does not increase the length of the list.
///
/// The [index] must be non-negative and no greater than [length].
@@ -480,24 +663,30 @@
///
/// If `iterable` is based on this list, its values may change _during_ the
/// `setAll` operation.
+ /// ```dart
+ /// final list = <String>['a', 'b', 'c', 'd'];
+ /// list.setAll(1, ['bee', 'sea']);
+ /// print(list); // [a, bee, sea, d]
+ /// ```
void setAll(int index, Iterable<E> iterable);
/// Removes the first occurrence of [value] from this list.
///
/// Returns true if [value] was in the list, false otherwise.
+ /// The list must be growable.
+ ///
/// ```dart
- /// var parts = ['head', 'shoulders', 'knees', 'toes'];
- /// parts.remove('head'); // true
- /// parts.join(', '); // 'shoulders, knees, toes'
+ /// final parts = <String>['head', 'shoulders', 'knees', 'toes'];
+ /// final retVal = parts.remove('head'); // true
+ /// print(parts); // [shoulders, knees, toes]
/// ```
/// The method has no effect if [value] was not in the list.
/// ```dart
+ /// final parts = <String>['shoulders', 'knees', 'toes'];
/// // Note: 'head' has already been removed.
- /// parts.remove('head'); // false
- /// parts.join(', '); // 'shoulders, knees, toes'
+ /// final retVal = parts.remove('head'); // false
+ /// print(parts); // [shoulders, knees, toes]
/// ```
- ///
- /// The list must be growable.
bool remove(Object? value);
/// Removes the object at position [index] from this list.
@@ -508,22 +697,31 @@
/// Returns the removed value.
///
/// The [index] must be in the range `0 ≤ index < length`.
- ///
/// The list must be growable.
+ /// ```dart
+ /// final parts = <String>['head', 'shoulder', 'knees', 'toes'];
+ /// final retVal = parts.removeAt(2); // knees
+ /// print(parts); // [head, shoulder, toes]
+ /// ```
E removeAt(int index);
/// Removes and returns the last object in this list.
///
/// The list must be growable and non-empty.
+ /// ```dart
+ /// final parts = <String>['head', 'shoulder', 'knees', 'toes'];
+ /// final retVal = parts.removeLast(); // toes
+ /// print(parts); // [head, shoulder, knees]
+ /// ```
E removeLast();
/// Removes all objects from this list that satisfy [test].
///
/// An object `o` satisfies [test] if `test(o)` is true.
/// ```dart
- /// var numbers = ['one', 'two', 'three', 'four'];
+ /// final numbers = <String>['one', 'two', 'three', 'four'];
/// numbers.removeWhere((item) => item.length == 3);
- /// numbers.join(', '); // 'three, four'
+ /// print(numbers); // [three, four]
/// ```
/// The list must be growable.
void removeWhere(bool test(E element));
@@ -532,9 +730,9 @@
///
/// An object `o` satisfies [test] if `test(o)` is true.
/// ```dart
- /// var numbers = ['one', 'two', 'three', 'four'];
+ /// final numbers = <String>['one', 'two', 'three', 'four'];
/// numbers.retainWhere((item) => item.length == 3);
- /// numbers.join(', '); // 'one, two'
+ /// print(numbers); // [one, two]
/// ```
/// The list must be growable.
void retainWhere(bool test(E element));
@@ -556,18 +754,19 @@
/// order as they occur in this list.
///
/// ```dart
- /// var colors = ["red", "green", "blue", "orange", "pink"];
+ /// final colors = <String>['red', 'green', 'blue', 'orange', 'pink'];
/// print(colors.sublist(1, 3)); // [green, blue]
/// ```
///
/// If [end] is omitted, it defaults to the [length] of this list.
///
/// ```dart
- /// print(colors.sublist(1)); // [green, blue, orange, pink]
+ /// final colors = <String>['red', 'green', 'blue', 'orange', 'pink'];
+ /// print(colors.sublist(3)); // [orange, pink]
/// ```
///
/// The `start` and `end` positions must satisfy the relations
- /// 0 ≤ `start` ≤ `end` ≤ [length]
+ /// 0 ≤ `start` ≤ `end` ≤ [length].
/// If `end` is equal to `start`, then the returned list is empty.
List<E> sublist(int start, [int? end]);
@@ -586,11 +785,12 @@
/// ends early if it reaches the end of the list early
/// (if `end`, or even `start`, becomes greater than [length]).
/// ```dart
- /// List<String> colors = ['red', 'green', 'blue', 'orange', 'pink'];
- /// Iterable<String> range = colors.getRange(1, 4);
- /// range.join(', '); // 'green, blue, orange'
- /// colors.length = 3;
- /// range.join(', '); // 'green, blue'
+ /// final colors = <String>['red', 'green', 'blue', 'orange', 'pink'];
+ /// final firstRange = colors.getRange(0, 3);
+ /// print(firstRange.join(', ')); // red, green, blue
+ ///
+ /// final secondRange = colors.getRange(2, 5);
+ /// print(secondRange.join(', ')); // blue, orange, pink
/// ```
Iterable<E> getRange(int start, int end);
@@ -599,12 +799,13 @@
/// Copies the objects of [iterable], skipping [skipCount] objects first,
/// into the range from [start], inclusive, to [end], exclusive, of this list.
/// ```dart
- /// var list1 = [1, 2, 3, 4];
- /// var list2 = [5, 6, 7, 8, 9];
+ /// final list1 = <int>[1, 2, 3, 4];
+ /// final list2 = <int>[5, 6, 7, 8, 9];
/// // Copies the 4th and 5th items in list2 as the 2nd and 3rd items
/// // of list1.
- /// list1.setRange(1, 3, list2, 3);
- /// list1.join(', '); // '1, 8, 9, 4'
+ /// const skipCount = 3;
+ /// list1.setRange(1, 3, list2, skipCount);
+ /// print(list1); // [1, 8, 9, 4]
/// ```
/// The provided range, given by [start] and [end], must be valid.
/// A range from [start] to [end] is valid if 0 ≤ `start` ≤ `end` ≤ [length].
@@ -632,6 +833,11 @@
/// An empty range (with `end == start`) is valid.
///
/// The list must be growable.
+ /// ```dart
+ /// final numbers = <int>[1, 2, 3, 4, 5];
+ /// numbers.removeRange(1, 4);
+ /// print(numbers); // [1, 5]
+ /// ```
void removeRange(int start, int end);
/// Overwrites a range of elements with [fillValue].
@@ -643,16 +849,16 @@
/// A range from [start] to [end] is valid if 0 ≤ `start` ≤ `end` ≤ [length].
/// An empty range (with `end == start`) is valid.
///
- /// Example:
- /// ```dart
- /// var list = List.filled(5, -1);
- /// print(list); // [-1, -1, -1, -1, -1]
- /// list.fillRange(1, 3, 4);
- /// print(list); // [-1, 4, 4, -1, -1]
- /// ```
- ///
/// If the element type is not nullable, the [fillValue] must be provided and
/// must be non-`null`.
+ ///
+ /// Example:
+ /// ```dart
+ /// final words = List.filled(5, 'old');
+ /// print(words); // [old, old, old, old, old]
+ /// words.fillRange(1, 3, 'new');
+ /// print(words); // [old, new, new, old, old]
+ /// ```
void fillRange(int start, int end, [E? fillValue]);
/// Replaces a range of elements with the elements of [replacements].
@@ -660,9 +866,10 @@
/// Removes the objects in the range from [start] to [end],
/// then inserts the elements of [replacements] at [start].
/// ```dart
- /// var list = [1, 2, 3, 4, 5];
- /// list.replaceRange(1, 4, [6, 7]);
- /// list.join(', '); // '1, 6, 7, 5'
+ /// final numbers = <int>[1, 2, 3, 4, 5];
+ /// final replacements = [6, 7];
+ /// numbers.replaceRange(1, 4, replacements);
+ /// print(numbers); // [1, 6, 7, 5]
/// ```
/// The provided range, given by [start] and [end], must be valid.
/// A range from [start] to [end] is valid if 0 ≤ `start` ≤ `end` ≤ [length].
@@ -671,8 +878,11 @@
/// The operation `list.replaceRange(start, end, replacements)`
/// is roughly equivalent to:
/// ```dart
- /// list.removeRange(start, end);
- /// list.insertAll(start, replacements);
+ /// final numbers = <int>[1, 2, 3, 4, 5];
+ /// numbers.removeRange(1, 4);
+ /// final replacements = [6, 7];
+ /// numbers.insertAll(1, replacements);
+ /// print(numbers); // [1, 6, 7, 5]
/// ```
/// but may be more efficient.
///
@@ -688,7 +898,7 @@
/// as values. The `Map.keys` [Iterable] iterates the indices of this list
/// in numerical order.
/// ```dart
- /// var words = ['fee', 'fi', 'fo', 'fum'];
+ /// var words = <String>['fee', 'fi', 'fo', 'fum'];
/// var map = words.asMap(); // {0: fee, 1: fi, 2: fo, 3: fum}
/// map.keys.toList(); // [0, 1, 2, 3]
/// ```
diff --git a/sdk/lib/core/num.dart b/sdk/lib/core/num.dart
index eab5eb9..4da3b29 100644
--- a/sdk/lib/core/num.dart
+++ b/sdk/lib/core/num.dart
@@ -8,6 +8,13 @@
///
/// It is a compile-time error for any type other than [int] or [double]
/// to attempt to extend or implement `num`.
+///
+/// **See also:**
+/// * [int]: An integer number.
+/// * [double]: A double-precision floating point number.
+/// * [Numbers](https://dart.dev/guides/language/numbers) in
+/// [A tour of the Dart language](https://dart.dev/guides/language/language-tour).
+
abstract class num implements Comparable<num> {
/// Test whether this value is numerically equal to `other`.
///
@@ -65,7 +72,7 @@
/// NaN return false.
///
/// This function imposes a complete ordering for doubles. When using
- /// `compareTo` the following properties hold:
+ /// `compareTo`, the following properties hold:
///
/// - All NaN values are considered equal, and greater than any numeric value.
/// - -0.0 is less than 0.0 (and the integer 0), but greater than any non-zero
@@ -113,7 +120,7 @@
/// Multiplies this number by [other].
///
/// The result is an [int], as described by [int.*],
- /// if both this number and [other] is an integer,
+ /// if both this number and [other] are integers,
/// otherwise the result is a [double].
num operator *(num other);
@@ -125,7 +132,7 @@
/// `a == b * q + r` and `0 <= r < b.abs()`.
///
/// The Euclidean division is only defined for integers, but can be easily
- /// extended to work with doubles. In that case `q` is stil an integer,
+ /// extended to work with doubles. In that case, `q` is still an integer,
/// but `r` may have a non-integer value that still satisfies `0 <= r < |b|`.
///
/// The sign of the returned value `r` is always positive.
@@ -133,9 +140,17 @@
/// See [remainder] for the remainder of the truncating division.
///
/// The result is an [int], as described by [int.%],
- /// if both this number and [other] is an integer,
+ /// if both this number and [other] are integers,
/// otherwise the result is a [double].
- num operator %(num other);
+ ///
+ /// Example:
+ /// ```dart
+ /// print(5 % 3); // 2
+ /// print(-5 % 3); // 1
+ /// print(5 % -3); // 2
+ /// print(-5 % -3); // 1
+ /// ```
+ num operator %(num other);
/// Divides this number by [other].
double operator /(num other);
@@ -146,11 +161,11 @@
/// Truncating division is division where a fractional result
/// is converted to an integer by rounding towards zero.
///
- /// If both operands are [int]s then [other] must not be zero.
+ /// If both operands are [int]s, then [other] must not be zero.
/// Then `a ~/ b` corresponds to `a.remainder(b)`
/// such that `a == (a ~/ b) * b + a.remainder(b)`.
///
- /// If either operand is a [double] then the other operand is converted
+ /// If either operand is a [double], then the other operand is converted
/// to a double before performing the division and truncation of the result.
/// Then `a ~/ b` is equivalent to `(a / b).truncate()`.
/// This means that the intermediate result of the double division
@@ -164,7 +179,7 @@
/// numbers numerical value (the result of subtracting the
/// number from zero), if that value *exists*.
///
- /// Negating a double gives a number with same magnitude
+ /// Negating a double gives a number with the same magnitude
/// as the original value (`number.abs() == (-number).abs()`),
/// and the opposite sign (`-(number.sign) == (-number).sign`).
///
@@ -179,11 +194,20 @@
///
/// The result `r` of this operation satisfies:
/// `this == (this ~/ other) * other + r`.
- /// As a consequence the remainder `r` has the same sign as the divider `this`.
+ /// As a consequence, the remainder `r` has the same sign as the divider
+ /// `this`.
///
/// The result is an [int], as described by [int.remainder],
- /// if both this number and [other] is an integer,
+ /// if both this number and [other] are integers,
/// otherwise the result is a [double].
+ ///
+ /// Example:
+ /// ```dart
+ /// print(5.remainder(3)); // 2
+ /// print(-5.remainder(3)); // -2
+ /// print(5.remainder(-3)); // 2
+ /// print(-5.remainder(-3)); // -2
+ /// ```
num remainder(num other);
/// Whether this number is numerically smaller than [other].
@@ -256,6 +280,11 @@
/// and `-value` if the value is negative.
///
/// Integer overflow may cause the result of `-value` to stay negative.
+ ///
+ /// ```dart
+ /// print((2).abs()); // 2
+ /// print((-2.5).abs()); // 2.5
+ /// ```
num abs();
/// Negative one, zero or positive one depending on the sign and
@@ -336,7 +365,7 @@
///
/// For the purpose of rounding, `-0.0` is considered to be below `0.0`,
/// and `-0.0` is therefore considered closer to negative numbers than `0.0`.
- /// This means that for a value, `d` in the range `-0.5 < d < 0.0`,
+ /// This means that for a value `d` in the range `-0.5 < d < 0.0`,
/// the result is `-0.0`.
double roundToDouble();
@@ -377,6 +406,14 @@
///
/// The arguments [lowerLimit] and [upperLimit] must form a valid range where
/// `lowerLimit.compareTo(upperLimit) <= 0`.
+ ///
+ /// Example:
+ /// ```dart
+ /// var result = 10.5.clamp(5, 10.0); // 10.0
+ /// result = 0.75.clamp(5, 10.0); // 5
+ /// result = (-10).clamp(-5, 5.0); // -5
+ /// result = (-0.0).clamp(-5, 5.0); // -0.0
+ /// ```
num clamp(num lowerLimit, num upperLimit);
/// Truncates this [num] to an integer and returns the result as an [int].
@@ -396,11 +433,11 @@
/// before computing the string representation,
/// as by [toDouble].
///
- /// If the absolute value of `this` is greater then or equal to `10^21` then
+ /// If the absolute value of `this` is greater than or equal to `10^21`, then
/// this methods returns an exponential representation computed by
/// `this.toStringAsExponential()`. Otherwise the result
/// is the closest string representation with exactly [fractionDigits] digits
- /// after the decimal point. If [fractionDigits] equals 0 then the decimal
+ /// after the decimal point. If [fractionDigits] equals 0, then the decimal
/// point is omitted.
///
/// The parameter [fractionDigits] must be an integer satisfying:
@@ -422,13 +459,13 @@
/// Converts this number to a [double]
/// before computing the string representation.
///
- /// If [fractionDigits] is given then it must be an integer satisfying:
+ /// If [fractionDigits] is given, then it must be an integer satisfying:
/// `0 <= fractionDigits <= 20`. In this case the string contains exactly
/// [fractionDigits] after the decimal point. Otherwise, without the parameter,
/// the returned string uses the shortest number of digits that accurately
/// represent this number.
///
- /// If [fractionDigits] equals 0 then the decimal point is omitted.
+ /// If [fractionDigits] equals 0, then the decimal point is omitted.
/// Examples:
/// ```dart
/// 1.toStringAsExponential(); // 1e+0
@@ -461,7 +498,7 @@
/// ```
String toStringAsPrecision(int precision);
- /// The shortest string that correctly represent this number number.
+ /// The shortest string that correctly represents this number.
///
/// All [double]s in the range `10^-6` (inclusive) to `10^21` (exclusive)
/// are converted to their decimal representation with at least one digit
@@ -517,6 +554,22 @@
/// The [onError] parameter is deprecated and will be removed.
/// Instead of `num.parse(string, (string) { ... })`,
/// you should use `num.tryParse(string) ?? (...)`.
+ ///
+ /// Examples:
+ /// ```dart
+ /// var value = num.parse('2021'); // 2021
+ /// value = num.parse('3.14'); // 3.14
+ /// value = num.parse(' 3.14 \xA0'); // 3.14
+ /// value = num.parse('0.'); // 0.0
+ /// value = num.parse('.0'); // 0.0
+ /// value = num.parse('-1.e3'); // -1000.0
+ /// value = num.parse('1234E+7'); // 12340000000.0
+ /// value = num.parse('+.12e-9'); // 1.2e-10
+ /// value = num.parse('-NaN'); // NaN
+ /// value = num.parse('0xFF'); // 255
+ /// value = num.parse(double.infinity.toString()); // Infinity
+ /// value = num.parse('1f'); // Throws.
+ /// ```
static num parse(String input, [@deprecated num onError(String input)?]) {
num? result = tryParse(input);
if (result != null) return result;
@@ -526,8 +579,24 @@
/// Parses a string containing a number literal into a number.
///
- /// Like [parse] except that this function returns `null` for invalid inputs
+ /// Like [parse], except that this function returns `null` for invalid inputs
/// instead of throwing.
+ ///
+ /// Examples:
+ /// ```dart
+ /// var value = num.tryParse('2021'); // 2021
+ /// value = num.tryParse('3.14'); // 3.14
+ /// value = num.tryParse(' 3.14 \xA0'); // 3.14
+ /// value = num.tryParse('0.'); // 0.0
+ /// value = num.tryParse('.0'); // 0.0
+ /// value = num.tryParse('-1.e3'); // -1000.0
+ /// value = num.tryParse('1234E+7'); // 12340000000.0
+ /// value = num.tryParse('+.12e-9'); // 1.2e-10
+ /// value = num.tryParse('-NaN'); // NaN
+ /// value = num.tryParse('0xFF'); // 255
+ /// value = num.tryParse(double.infinity.toString()); // Infinity
+ /// value = num.tryParse('1f'); // null
+ /// ```
static num? tryParse(String input) {
String source = input.trim();
// TODO(lrn): Optimize to detect format and result type in one check.
diff --git a/sdk/lib/core/string.dart b/sdk/lib/core/string.dart
index ca31986..8764498 100644
--- a/sdk/lib/core/string.dart
+++ b/sdk/lib/core/string.dart
@@ -8,7 +8,7 @@
///
/// Strings are mainly used to represent text. A character may be represented by
/// multiple code points, each code point consisting of one or two code
-/// units. For example the Papua New Guinea flag character requires four code
+/// units. For example, the Papua New Guinea flag character requires four code
/// units to represent two code points, but should be treated like a single
/// character: "🇵🇬". Platforms that do not support the flag character may show
/// the letters "PG" instead. If the code points are swapped, it instead becomes
@@ -35,41 +35,49 @@
/// Strings are immutable. Although you cannot change a string, you can perform
/// an operation on a string which creates a new string:
/// ```dart
-/// var string = 'Dart is fun';
-/// var newString = string.substring(0, 5);
+/// const string = 'Dart is fun';
+/// print(string.substring(0, 4)); // 'Dart'
/// ```
/// You can use the plus (`+`) operator to concatenate strings:
/// ```dart
-/// 'Dart ' + 'is ' + 'fun!'; // 'Dart is fun!'
+/// const string = 'Dart ' + 'is ' + 'fun!';
+/// print(string); // 'Dart is fun!'
/// ```
/// Adjacent string literals are concatenated automatically:
/// ```dart
-/// 'Dart ' 'is ' 'fun!'; // 'Dart is fun!'
+/// const string = 'Dart ' 'is ' 'fun!';
+/// print(string); // 'Dart is fun!'
/// ```
/// You can use `${}` to interpolate the value of Dart expressions
/// within strings. The curly braces can be omitted when evaluating identifiers:
/// ```dart
-/// var string = 'dartlang';
-/// '$string has ${string.length} letters'; // 'dartlang has 8 letters'
+/// const string = 'dartlang';
+/// print('$string has ${string.length} letters'); // dartlang has 8 letters
/// ```
/// A string is represented by a sequence of Unicode UTF-16 code units
/// accessible through the [codeUnitAt] or the [codeUnits] members:
/// ```dart
-/// var string = 'Dart';
-/// string.codeUnitAt(0); // 68
-/// string.codeUnits; // [68, 97, 114, 116]
+/// const string = 'Dart';
+/// final firstCodeUnit = string.codeUnitAt(0);
+/// print(firstCodeUnit); // 68, aka U+0044, the code point for 'D'.
+/// final allCodeUnits = string.codeUnits;
+/// print(allCodeUnits); // [68, 97, 114, 116]
/// ```
-/// The string representation of code units is accessible through the index
-/// operator:
+/// A string representation of the individual code units is accessible through
+/// the index operator:
/// ```dart
-/// string[0]; // 'D'
+/// const string = 'Dart';
+/// final charAtIndex = string[0];
+/// print(charAtIndex); // 'D'
/// ```
/// The characters of a string are encoded in UTF-16. Decoding UTF-16, which
/// combines surrogate pairs, yields Unicode code points. Following a similar
-/// terminology to Go, we use the name 'rune' for an integer representing a
+/// terminology to Go, Dart uses the name 'rune' for an integer representing a
/// Unicode code point. Use the [runes] property to get the runes of a string:
/// ```dart
-/// string.runes.toList(); // [68, 97, 114, 116]
+/// const string = 'Dart';
+/// final runes = string.runes.toList();
+/// print(runes); // [68, 97, 114, 116]
/// ```
/// For a character outside the Basic Multilingual Plane (plane 0) that is
/// composed of a surrogate pair, [runes] combines the pair and returns a
@@ -78,34 +86,38 @@
/// pair: `0xD834` and `0xDD1E`. Using [codeUnits] returns the surrogate pair,
/// and using `runes` returns their combined value:
/// ```dart
-/// var clef = '\u{1D11E}';
-/// clef.codeUnits; // [0xD834, 0xDD1E]
-/// clef.runes.toList(); // [0x1D11E]
+/// const clef = '\u{1D11E}';
+/// for (final item in clef.codeUnits) {
+/// print(item.toRadixString(16));
+/// // d834
+/// // dd1e
+/// }
+/// for (final item in clef.runes) {
+/// print(item.toRadixString(16)); // 1d11e
+/// }
/// ```
/// The `String` class cannot be extended or implemented. Attempting to do so
/// yields a compile-time error.
///
/// ## Other resources
///
-/// See [StringBuffer] to efficiently build a string incrementally. See
-/// [RegExp] to work with regular expressions.
-///
-/// Also see:
-///
+/// * [StringBuffer] to efficiently build a string incrementally.
+/// * [RegExp] to work with regular expressions.
/// * [Strings and regular expressions](https://dart.dev/guides/libraries/library-tour#strings-and-regular-expressions)
@pragma('vm:entry-point')
abstract class String implements Comparable<String>, Pattern {
/// Allocates a new string containing the specified [charCodes].
///
- /// The [charCodes] can be both UTF-16 code units or runes.
+ /// The [charCodes] can be both UTF-16 code units and runes.
/// If a char-code value is 16-bit, it is used as a code unit:
/// ```dart
- /// String.fromCharCodes([68]); // 'D'
+ /// final string = String.fromCharCodes([68]);
+ /// print(string); // D
/// ```
/// If a char-code value is greater than 16-bits, it is decomposed into a
/// surrogate pair:
/// ```dart
- /// var clef = String.fromCharCodes([0x1D11E]);
+ /// final clef = String.fromCharCodes([0x1D11E]);
/// clef.codeUnitAt(0); // 0xD834
/// clef.codeUnitAt(1); // 0xDD1E
/// ```
@@ -224,7 +236,7 @@
/// a positive value if `this` is ordered after `other`,
/// or zero if `this` and `other` are equivalent.
///
- /// The ordering is the same as the ordering of the code points at the first
+ /// The ordering is the same as the ordering of the code units at the first
/// position where the two strings differ.
/// If one string is a prefix of the other,
/// then the shorter string is ordered before the longer string.
@@ -232,28 +244,39 @@
/// regard to the ordering.
/// Ordering does not check for Unicode equivalence.
/// The comparison is case sensitive.
+ /// ```dart
+ /// var relation = 'Dart'.compareTo('Go');
+ /// print(relation); // < 0
+ /// relation = 'Go'.compareTo('Forward');
+ /// print(relation); // > 0
+ /// relation = 'Forward'.compareTo('Forward');
+ /// print(relation); // 0
+ /// ```
int compareTo(String other);
/// Whether this string ends with [other].
///
/// For example:
/// ```dart
- /// 'Dart'.endsWith('t'); // true
+ /// const string = 'Dart is open source';
+ /// print(string.endsWith('urce')); // true
/// ```
bool endsWith(String other);
/// Whether this string starts with a match of [pattern].
///
/// ```dart
- /// var string = 'Dart';
- /// string.startsWith('D'); // true
- /// string.startsWith(RegExp(r'[A-Z][a-z]')); // true
+ /// const string = 'Dart is open source';
+ /// print(string.startsWith('Dar')); // true
+ /// print(string.startsWith(RegExp(r'[A-Z][a-z]'))); // true
/// ```
/// If [index] is provided, this method checks if the substring starting
/// at that index starts with a match of [pattern]:
/// ```dart
- /// string.startsWith('art', 1); // true
- /// string.startsWith(RegExp(r'\w{3}')); // true
+ /// const string = 'Dart';
+ /// print(string.startsWith('art', 0)); // false
+ /// print(string.startsWith('art', 1)); // true
+ /// print(string.startsWith(RegExp(r'\w{3}'), 2)); // false
/// ```
/// [index] must not be negative or greater than [length].
///
@@ -262,21 +285,23 @@
/// The pattern works on the string as a whole, and does not extract
/// a substring starting at [index] first:
/// ```dart
- /// string.startsWith(RegExp(r'^art'), 1); // false
- /// string.startsWith(RegExp(r'art'), 1); // true
+ /// const string = 'Dart';
+ /// print(string.startsWith(RegExp(r'^art'), 1)); // false
+ /// print(string.startsWith(RegExp(r'art'), 1)); // true
/// ```
bool startsWith(Pattern pattern, [int index = 0]);
/// Returns the position of the first match of [pattern] in this string,
/// starting at [start], inclusive:
/// ```dart
- /// var string = 'Dartisans';
- /// string.indexOf('art'); // 1
- /// string.indexOf(RegExp(r'[A-Z][a-z]')); // 0
+ /// const string = 'Dartisans';
+ /// print(string.indexOf('art')); // 1
+ /// print(string.indexOf(RegExp(r'[A-Z][a-z]'))); // 0
/// ```
/// Returns -1 if no match is found:
/// ```dart
- /// string.indexOf(RegExp(r'dart')); // -1
+ /// const string = 'Dartisans';
+ /// string.indexOf(RegExp(r'dart')); // -1
/// ```
/// The [start] must be non-negative and not greater than [length].
int indexOf(Pattern pattern, [int start = 0]);
@@ -285,13 +310,14 @@
///
/// Finds a match of pattern by searching backward starting at [start]:
/// ```dart
- /// var string = 'Dartisans';
- /// string.lastIndexOf('a'); // 6
- /// string.lastIndexOf(RegExp(r'a(r|n)')); // 6
+ /// const string = 'Dartisans';
+ /// print(string.lastIndexOf('a')); // 6
+ /// print(string.lastIndexOf(RegExp(r'a(r|n)'))); // 6
/// ```
/// Returns -1 if [pattern] could not be found in this string.
/// ```dart
- /// string.lastIndexOf(RegExp(r'DART')); // -1
+ /// const string = 'Dartisans';
+ /// print(string.lastIndexOf(RegExp(r'DART'))); // -1
/// ```
/// If [start] is omitted, search starts from the end of the string.
/// If supplied, [start] must be non-negative and not greater than [length].
@@ -307,17 +333,17 @@
///
/// Example:
/// ```dart
- /// 'dart' + 'lang'; // 'dartlang'
+ /// const string = 'dart' + 'lang'; // 'dartlang'
/// ```
String operator +(String other);
- /// The substring of this string from [start],inclusive, to [end], exclusive.
+ /// The substring of this string from [start], inclusive, to [end], exclusive.
///
/// Example:
/// ```dart
- /// var string = 'dartlang';
- /// string.substring(1); // 'artlang'
- /// string.substring(1, 4); // 'art'
+ /// const string = 'dartlang';
+ /// var result = string.substring(1); // 'artlang'
+ /// result = string.substring(1, 4); // 'art'
/// ```
///
/// Both [start] and [end] must be non-negative and no greater than [length], and
@@ -329,13 +355,14 @@
/// If the string contains leading or trailing whitespace, a new string with no
/// leading and no trailing whitespace is returned:
/// ```dart
- /// '\tDart is fun\n'.trim(); // 'Dart is fun'
+ /// final trimmed = '\tDart is fun\n'.trim();
+ /// print(trimmed); // 'Dart is fun'
/// ```
/// Otherwise, the original string itself is returned:
/// ```dart
- /// var str1 = 'Dart';
- /// var str2 = str1.trim();
- /// identical(str1, str2); // true
+ /// const string1 = 'Dart';
+ /// final string2 = string1.trim(); // 'Dart'
+ /// print(identical(string1, string2)); // true
/// ```
/// Whitespace is defined by the Unicode White_Space property (as defined in
/// version 6.2 or later) and the BOM character, 0xFEFF.
@@ -364,11 +391,19 @@
/// The string without any leading whitespace.
///
/// As [trim], but only removes leading whitespace.
+ /// ```dart
+ /// final string = ' Dart '.trimLeft();
+ /// print(string); // 'Dart '
+ /// ```
String trimLeft();
/// The string without any trailing whitespace.
///
/// As [trim], but only removes trailing whitespace.
+ /// ```dart
+ /// final string = ' Dart '.trimRight();
+ /// print(string); // ' Dart'
+ /// ```
String trimRight();
/// Creates a new string by concatenating this string with itself a number
@@ -377,6 +412,11 @@
/// The result of `str * n` is equivalent to
/// `str + str + ...`(n times)`... + str`.
///
+ /// ```dart
+ /// const string = 'Dart';
+ /// final multiplied = string * 3;
+ /// print(multiplied); // 'DartDartDart'
+ /// ```
/// Returns an empty string if [times] is zero or negative.
String operator *(int times);
@@ -385,6 +425,14 @@
/// Returns a new string that prepends [padding] onto this string
/// one time for each position the length is less than [width].
///
+ /// ```dart
+ /// const string = 'D';
+ /// print(string.padLeft(4)); // ' D'
+ /// print(string.padLeft(2, 'x')); // 'xD'
+ /// print(string.padLeft(4, 'y')); // 'yyyD'
+ /// print(string.padLeft(4, '>>')); // '>>>>>>D'
+ /// ```
+ ///
/// If [width] is already smaller than or equal to `this.length`,
/// no padding is added. A negative `width` is treated as zero.
///
@@ -393,7 +441,7 @@
/// padding is a longer string representing a single character, like
/// `" "` or `"\u{10002}`".
/// In that case, the user should make sure that `this.length` is
- /// the correct measure of the strings length.
+ /// the correct measure of the string's length.
String padLeft(int width, [String padding = ' ']);
/// Pads this string on the right if it is shorter than [width].
@@ -401,6 +449,14 @@
/// Returns a new string that appends [padding] after this string
/// one time for each position the length is less than [width].
///
+ /// ```dart
+ /// const string = 'D';
+ /// print(string.padRight(4)); // 'D '
+ /// print(string.padRight(2, 'x')); // 'Dx'
+ /// print(string.padRight(4, 'y')); // 'Dyyy'
+ /// print(string.padRight(4, '>>')); // 'D>>>>>>'
+ /// ```
+ ///
/// If [width] is already smaller than or equal to `this.length`,
/// no padding is added. A negative `width` is treated as zero.
///
@@ -409,22 +465,23 @@
/// padding is a longer string representing a single character, like
/// `" "` or `"\u{10002}`".
/// In that case, the user should make sure that `this.length` is
- /// the correct measure of the strings length.
+ /// the correct measure of the string's length.
String padRight(int width, [String padding = ' ']);
/// Whether this string contains a match of [other].
///
/// Example:
/// ```dart
- /// var string = 'Dart strings';
- /// string.contains('D'); // true
- /// string.contains(RegExp(r'[A-Z]')); // true
+ /// const string = 'Dart strings';
+ /// final containsD = string.contains('D'); // true
+ /// final containsUpperCase = string.contains(RegExp(r'[A-Z]')); // true
/// ```
/// If [startIndex] is provided, this method matches only at or after that
/// index:
/// ```dart
- /// string.contains('D', 1); // false
- /// string.contains(RegExp(r'[A-Z]'), 1); // false
+ /// const string = 'Dart strings';
+ /// final containsD = string.contains(RegExp('D'), 0); // true
+ /// final caseSensitive = string.contains(RegExp(r'[A-Z]'), 1); // false
/// ```
/// The [startIndex] must not be negative or greater than [length].
bool contains(Pattern other, [int startIndex = 0]);
@@ -437,12 +494,21 @@
/// Example:
/// ```dart
/// '0.0001'.replaceFirst(RegExp(r'0'), ''); // '.0001'
- /// '0.0001'.replaceFirst(RegExp(r'0'), '7', 1); // '0.7001'
+ /// '0.0001'.replaceFirst(RegExp(r'0'), '7', 1); // '0.7001'
/// ```
String replaceFirst(Pattern from, String to, [int startIndex = 0]);
/// Replace the first occurrence of [from] in this string.
///
+ /// ```dart
+ /// const string = 'Dart is fun';
+ /// print(string.replaceFirstMapped(
+ /// 'fun', (m) => 'open source')); // Dart is open source
+ ///
+ /// print(string.replaceFirstMapped(
+ /// RegExp(r'\w(\w*)'), (m) => '<${m[0]}-${m[1]}>')); // <Dart-art> is fun
+ /// ```
+ ///
/// Returns a new string, which is this string
/// except that the first match of [from], starting from [startIndex],
/// is replaced by the result of calling [replace] with the match object.
@@ -460,7 +526,7 @@
/// 'resume'.replaceAll(RegExp(r'e'), 'é'); // 'résumé'
/// ```
/// Notice that the [replace] string is not interpreted. If the replacement
- /// depends on the match (for example on a [RegExp]'s capture groups), use
+ /// depends on the match (for example, on a [RegExp]'s capture groups), use
/// the [replaceAllMapped] method instead.
String replaceAll(Pattern from, String replace);
@@ -479,11 +545,12 @@
/// The function defined below converts each word in a string to simplified
/// 'pig latin' using [replaceAllMapped]:
/// ```dart
- /// pigLatin(String words) => words.replaceAllMapped(
+ /// String pigLatin(String words) => words.replaceAllMapped(
/// RegExp(r'\b(\w*?)([aeiou]\w*)', caseSensitive: false),
/// (Match m) => "${m[2]}${m[1]}${m[1]!.isEmpty ? 'way' : 'ay'}");
///
- /// pigLatin('I have a secret now!'); // 'Iway avehay away ecretsay ownay!'
+ /// final result = pigLatin('I have a secret now!');
+ /// print(result); // 'Iway avehay away ecretsay ownay!'
/// ```
String replaceAllMapped(Pattern from, String Function(Match match) replace);
@@ -493,6 +560,12 @@
/// ```dart
/// this.substring(0, start) + replacement + this.substring(end)
/// ```
+ /// Example:
+ /// ```dart
+ /// const string = 'Dart is fun';
+ /// final result = string.replaceRange(8, null, 'open source');
+ /// print(result); // Dart is open source
+ /// ```
/// The [start] and [end] indices must specify a valid range of this string.
/// That is `0 <= start <= end <= this.length`.
/// If [end] is `null`, it defaults to [length].
@@ -505,8 +578,9 @@
/// and returns the list of the substrings between the matches,
/// before the first match, and after the last match.
/// ```dart
- /// var string = "Hello world!";
- /// string.split(" "); // ["Hello", "world!"];
+ /// const string = 'Hello world!';
+ /// final splitted = string.split(' ');
+ /// print(splitted); // [Hello, world!];
/// ```
/// If the pattern doesn't match this string at all,
/// the result is always a list containing only the original string.
@@ -525,22 +599,22 @@
/// then the empty substring between the two matches is not
/// included in the result.
/// ```dart
- /// var string = "abba";
- /// var re = RegExp(r"b*");
+ /// const string = 'abba';
+ /// final re = RegExp(r'b*');
/// // re.allMatches(string) will find four matches:
/// // * empty match before first "a".
/// // * match of "bb"
/// // * empty match after "bb", before second "a"
/// // * empty match after second "a".
- /// print(string.split(re)); // ["a", "a"]
+ /// print(string.split(re)); // [a, a]
/// ```
///
/// A non-empty match at the start or end of the string, or after another
/// match, is not treated specially, and will introduce empty substrings
/// in the result:
/// ```dart
- /// var string = "abbaa";
- /// string.split("a"); // ["", "bb", "", ""]
+ /// const string = 'abbaa';
+ /// final splitted = string.split('a'); // ['', 'bb', '', '']
/// ```
///
/// If this string is the empty string, the result is an empty list
@@ -549,34 +623,40 @@
/// (It is still a list containing the original empty string `[""]`
/// if the pattern doesn't match).
/// ```dart
- /// var string = "";
- /// string.split(""); // []
- /// string.split("a"); // [""]
+ /// const string = '';
+ /// print(string.split('')); // []
+ /// print(string.split('a')); // []
/// ```
///
/// Splitting with an empty pattern splits the string into single-code unit
/// strings.
/// ```dart
- /// var string = "Pub";
- /// string.split(""); // ["P", "u", "b"]
+ /// const string = 'Pub';
+ /// print(string.split('')); // [P, u, b]
///
/// // Same as:
- /// [for (var unit in string.codeUnits)
- /// String.fromCharCode(unit)]; // ["P", "u", "b"]
+ /// var codeUnitStrings = [
+ /// for (final unit in string.codeUnits) String.fromCharCode(unit)
+ /// ];
+ /// print(codeUnitStrings); // [P, u, b]
/// ```
///
/// Splitting happens at UTF-16 code unit boundaries,
/// and not at rune (Unicode code point) boundaries:
/// ```dart
/// // String made up of two code units, but one rune.
- /// var string = '\u{1D11E}';
- /// string.split(''); // ["\ud834", "\udd1e"] - 2 unpaired surrogate values
+ /// const string = '\u{1D11E}';
+ /// final splitted = string.split('');
+ /// print(splitted); // ['\ud834', '\udd1e'] - 2 unpaired surrogate values
/// ```
/// To get a list of strings containing the individual runes of a string,
/// you should not use split.
/// You can instead get a string for each rune as follows:
/// ```dart
- /// [for (var run in string.runes) String.fromCharCode(rune)]
+ /// const string = '\u{1F642}';
+ /// for (final rune in string.runes) {
+ /// print(String.fromCharCode(rune));
+ /// }
/// ```
List<String> split(Pattern pattern);
@@ -600,9 +680,10 @@
///
/// Then all the converted parts are concatenated into the resulting string.
/// ```dart
- /// 'Eats shoots leaves'.splitMapJoin((RegExp(r'shoots')),
- /// onMatch: (m) => '${m[0]}', // (or no onMatch at all)
- /// onNonMatch: (n) => '*'); // Result: "*shoots*"
+ /// final result = 'Eats shoots leaves'.splitMapJoin(RegExp(r'shoots'),
+ /// onMatch: (m) => '${m[0]}', // (or no onMatch at all)
+ /// onNonMatch: (n) => '*');
+ /// print(result); // *shoots*
/// ```
String splitMapJoin(Pattern pattern,
{String Function(Match)? onMatch, String Function(String)? onNonMatch});
@@ -622,7 +703,7 @@
/// If the string is already in all lower case, this method returns `this`.
/// ```dart
/// 'ALPHABET'.toLowerCase(); // 'alphabet'
- /// 'abc'.toLowerCase(); // 'abc'
+ /// 'abc'.toLowerCase(); // 'abc'
/// ```
/// This function uses the language independent Unicode mapping and thus only
/// works in some languages.
@@ -634,7 +715,7 @@
/// If the string is already in all upper case, this method returns `this`.
/// ```dart
/// 'alphabet'.toUpperCase(); // 'ALPHABET'
- /// 'ABC'.toUpperCase(); // 'ABC'
+ /// 'ABC'.toUpperCase(); // 'ABC'
/// ```
/// This function uses the language independent Unicode mapping and thus only
/// works in some languages.
@@ -706,7 +787,7 @@
///
/// When created, there is no [current] value.
/// A [moveNext] will use the rune starting at [index] the current value,
- /// and a [movePrevious] will use the rune ending just before [index] as the
+ /// and a [movePrevious] will use the rune ending just before [index] as
/// the current value.
///
/// The [index] position must not be in the middle of a surrogate pair.
diff --git a/sdk/lib/math/math.dart b/sdk/lib/math/math.dart
index ad1da4d..d9e3f75 100644
--- a/sdk/lib/math/math.dart
+++ b/sdk/lib/math/math.dart
@@ -8,6 +8,71 @@
/// ```dart
/// import 'dart:math';
/// ```
+///
+/// ## Random
+/// [Random] is a generator of [bool], [int] or [double] values.
+/// ```dart
+/// var intValue = Random().nextInt(10); // Value is >= 0.0 and < 1.0.
+/// var doubleValue = Random().nextDouble(); // Value is >= 0.0 and < 1.0.
+/// var boolValue = Random().nextBool(); // true or false, with equal chance.
+/// ```
+///
+/// ## Point
+/// [Point] is a utility class for representing two-dimensional positions.
+/// ```dart
+/// var leftTop = const Point(0, 0);
+/// var rightBottom = const Point(200, 400);
+/// ```
+///
+/// ## Rectangle
+/// [Rectangle] is a class for representing two-dimensional axis-aligned
+/// rectangles whose properties are immutable.
+///
+/// Create a rectangle spanned by the points.
+/// ```dart
+/// var leftTop = const Point(20, 50);
+/// var rightBottom = const Point(300, 600);
+/// var rectangle = Rectangle.fromPoints(leftTop, rightBottom);
+/// print(rectangle.left); // 20
+/// print(rectangle.top); // 50
+/// print(rectangle.right); // 300
+/// print(rectangle.bottom); // 600
+/// ```
+///
+/// Create a rectangle spanned by `(left, top)` and
+/// `(left+width, top+height)`.
+/// ```dart
+/// var rectangle = const Rectangle(20, 50, 300, 600);
+/// print(rectangle.left); // 20
+/// print(rectangle.top); // 50
+/// print(rectangle.right); // 320
+/// print(rectangle.bottom); // 650
+/// ```
+///
+/// ## MutableRectangle
+/// [MutableRectangle] is a class for representing two-dimensional axis-aligned
+/// rectangles with mutable properties.
+///
+/// Create a mutable rectangle spanned by `(left, top)` and
+/// `(left+width, top+height)`.
+/// ```dart
+/// var rectangle = MutableRectangle(20, 50, 300, 600);
+/// print(rectangle); // Rectangle (20, 50) 300 x 600
+/// print(rectangle.left); // 20
+/// print(rectangle.top); // 50
+/// print(rectangle.right); // 320
+/// print(rectangle.bottom); // 650
+///
+/// // Change rectangle width and height.
+/// rectangle.width = 200;
+/// rectangle.height = 100;
+/// print(rectangle); // Rectangle (20, 50) 200 x 100
+/// print(rectangle.left); // 20
+/// print(rectangle.top); // 50
+/// print(rectangle.right); // 220
+/// print(rectangle.bottom); // 150
+/// ```
+///
/// {@category Core}
library dart.math;
@@ -101,7 +166,7 @@
///
/// - if `y` is zero (0.0 or -0.0), the result is always 1.0.
/// - if `x` is 1.0, the result is always 1.0.
-/// - otherwise, if either `x` or `y` is NaN then the result is NaN.
+/// - otherwise, if either `x` or `y` is NaN, then the result is NaN.
/// - if `x` is negative (but not -0.0) and `y` is a finite non-integer, the
/// result is NaN.
/// - if `x` is Infinity and `y` is negative, the result is 0.0.
@@ -165,6 +230,16 @@
/// value.
///
/// Returns -0.0 if [x] is -0.0, and NaN if [x] is otherwise negative or NaN.
+/// ```dart
+/// var result = sqrt(9.3);
+/// print(result); // 3.0495901363953815
+/// result = sqrt(2);
+/// print(result); // 1.4142135623730951
+/// result = sqrt(0);
+/// print(result); // 0.0
+/// result = sqrt(-2.2);
+/// print(result); // NaN
+/// ```
external double sqrt(num x);
/// Converts [x] to a [double] and returns the natural exponent, [e],
diff --git a/sdk/lib/math/point.dart b/sdk/lib/math/point.dart
index df26e9a..1291e23 100644
--- a/sdk/lib/math/point.dart
+++ b/sdk/lib/math/point.dart
@@ -5,6 +5,12 @@
part of dart.math;
/// A utility class for representing two-dimensional positions.
+///
+/// Example:
+/// ```dart
+/// var leftTop = const Point(0, 0);
+/// var rightBottom = const Point(200, 400);
+/// ```
class Point<T extends num> {
final T x;
final T y;
@@ -21,6 +27,12 @@
/// Returns `true` if [other] is a [Point] with [x] and [y]
/// coordinates equal to the corresponding coordinates of this point,
/// and `false` otherwise.
+ ///
+ /// Example:
+ /// ```dart
+ /// var result = const Point(0, 0) == const Point(0, 0); // true
+ /// result = const Point(1.0, 0) == const Point(-1.0, 0); // false
+ /// ```
bool operator ==(Object other) =>
other is Point && x == other.x && y == other.y;
@@ -29,6 +41,12 @@
/// Add [other] to `this`, as if both points were vectors.
///
/// Returns the resulting "vector" as a Point.
+ ///
+ /// Example:
+ /// ```dart
+ /// var point = const Point(10, 100) + const Point(10, 10); // Point(20, 110)
+ /// point = const Point(-10, -20) + const Point(10, 100); // Point(0, 80)
+ /// ```
Point<T> operator +(Point<T> other) {
return Point<T>((x + other.x) as T, (y + other.y) as T);
}
@@ -36,26 +54,57 @@
/// Subtract [other] from `this`, as if both points were vectors.
///
/// Returns the resulting "vector" as a Point.
+ ///
+ /// Example:
+ /// ```dart
+ /// var point = const Point(10, 100) - const Point(10, 10); // Point(0, 90)
+ /// point = const Point(-10, -20) - const Point(10, 100); // Point(-110, -120)
+ /// ```
Point<T> operator -(Point<T> other) {
return Point<T>((x - other.x) as T, (y - other.y) as T);
}
/// Scale this point by [factor] as if it were a vector.
///
- /// *Important* *Note*: This function accepts a `num` as its argument only so
+ /// **Important Note**: This function accepts a `num` as its argument only so
/// that you can scale `Point<double>` objects by an `int` factor. Because the
/// `*` operator always returns the same type of `Point` as it is called on,
/// passing in a double [factor] on a `Point<int>` _causes_ _a_
/// _runtime_ _error_.
+ ///
+ /// Example:
+ /// ```dart
+ /// // Integer values.
+ /// var point = const Point(10, 100) * 10; // Point(100, 1000)
+ /// point = const Point(-10, -100) * 5; // Point(-50, -500)
+ /// // Double values.
+ /// var doublePoint = Point(10.0, 100.0) * 1.5; // Point(15.0, 150.0)
+ /// // Runtime error due the invalid type cast.
+ /// var newPoint = const Point(10, 100) * 1.5; // Throws.
+ /// ```
Point<T> operator *(num /*T|int*/ factor) {
return Point<T>((x * factor) as T, (y * factor) as T);
}
/// Get the straight line (Euclidean) distance between the origin (0, 0) and
/// this point.
+ ///
+ /// Example:
+ /// ```dart
+ /// var magnitude = const Point(0, 0).magnitude; // 0.0
+ /// magnitude = const Point(10, 0).magnitude; // 10.0
+ /// magnitude = const Point(0, -10).magnitude; // 10.0
+ /// magnitude = const Point(10, 10).magnitude; // 14.142135623730951
+ /// ```
double get magnitude => sqrt(x * x + y * y);
/// Returns the distance between `this` and [other].
+ /// ```dart
+ /// var distanceTo = const Point(0, 0).distanceTo(const Point(0, 0)); // 0.0
+ /// distanceTo = const Point(0, 0).distanceTo(const Point(10, 0)); // 10.0
+ /// distanceTo = const Point(0, 0).distanceTo(const Point(0, -10)); // 10.0
+ /// distanceTo = const Point(-10, 0).distanceTo(const Point(100, 0)); // 110.0
+ /// ```
double distanceTo(Point<T> other) {
var dx = x - other.x;
var dy = y - other.y;
@@ -66,6 +115,18 @@
///
/// Squared distances can be used for comparisons when the actual value is not
/// required.
+ ///
+ /// Example:
+ /// ```dart
+ /// var squaredDistance =
+ /// const Point(0, 0).squaredDistanceTo(const Point(0, 0)); // 0.0
+ /// squaredDistance =
+ /// const Point(0, 0).squaredDistanceTo(const Point(10, 0)); // 100
+ /// squaredDistance =
+ /// const Point(0, 0).squaredDistanceTo(const Point(0, -10)); // 100
+ /// squaredDistance =
+ /// const Point(-10, 0).squaredDistanceTo(const Point(100, 0)); // 12100
+ /// ```
T squaredDistanceTo(Point<T> other) {
var dx = x - other.x;
var dy = y - other.y;
diff --git a/sdk/lib/math/rectangle.dart b/sdk/lib/math/rectangle.dart
index 1fe8ea9..fd7d783 100644
--- a/sdk/lib/math/rectangle.dart
+++ b/sdk/lib/math/rectangle.dart
@@ -11,7 +11,7 @@
/// computer graphics.
///
/// See also:
-/// [W3C Coordinate Systems Specification](http://www.w3.org/TR/SVG/coords.html#InitialCoordinateSystem).
+/// [W3C Coordinate Systems Specification](https://www.w3.org/TR/SVG/coords.html#InitialCoordinateSystem).
///
/// The rectangle is the set of points with representable coordinates greater
/// than or equal to left/top, and with distance to left/top no greater than
@@ -135,6 +135,15 @@
///
/// If `width` and `height` are zero, the "rectangle" comprises only the
/// single point `(left, top)`.
+ ///
+ /// Example:
+ /// ```dart
+ /// var rectangle = const Rectangle(20, 50, 300, 600);
+ /// print(rectangle.left); // 20
+ /// print(rectangle.top); // 50
+ /// print(rectangle.right); // 320
+ /// print(rectangle.bottom); // 650
+ /// ```
const Rectangle(this.left, this.top, T width, T height)
: width = (width < 0)
? (width == double.negativeInfinity ? 0.0 : (-width * 0)) as dynamic
@@ -154,6 +163,19 @@
/// (which can happen if one or both is a double),
/// the actual right edge might be slightly off from `max(a.x, b.x)`.
/// Similar for the y-coordinates and the bottom edge.
+ ///
+ /// Example:
+ /// ```dart
+ /// var leftTop = const Point(20, 50);
+ /// var rightBottom = const Point(300, 600);
+ ///
+ /// var rectangle = Rectangle.fromPoints(leftTop, rightBottom);
+ /// print(rectangle); // Rectangle (20, 50) 280 x 550
+ /// print(rectangle.left); // 20
+ /// print(rectangle.top); // 50
+ /// print(rectangle.right); // 300
+ /// print(rectangle.bottom); // 600
+ /// ```
factory Rectangle.fromPoints(Point<T> a, Point<T> b) {
T left = min(a.x, b.x);
T width = (max(a.x, b.x) - left) as T;
@@ -191,6 +213,26 @@
///
/// If `width` and `height` are zero, the "rectangle" comprises only the
/// single point `(left, top)`.
+ ///
+ /// Example:
+ /// ```dart
+ /// var rectangle = MutableRectangle(20, 50, 300, 600);
+ /// print(rectangle); // Rectangle (20, 50) 300 x 600
+ /// print(rectangle.left); // 20
+ /// print(rectangle.top); // 50
+ /// print(rectangle.right); // 320
+ /// print(rectangle.bottom); // 650
+ ///
+ /// // Change rectangle width and height.
+ /// rectangle.width = 200;
+ /// rectangle.height = 100;
+ ///
+ /// print(rectangle); // Rectangle (20, 50) 200 x 100
+ /// print(rectangle.left); // 20
+ /// print(rectangle.top); // 50
+ /// print(rectangle.right); // 220
+ /// print(rectangle.bottom); // 150
+ /// ```
MutableRectangle(this.left, this.top, T width, T height)
: this._width =
(width < 0) ? _clampToZero<T>(width) : (width + 0 as dynamic),
@@ -207,6 +249,18 @@
/// (which can happen if one or both is a double),
/// the actual right edge might be slightly off from `max(a.x, b.x)`.
/// Similar for the y-coordinates and the bottom edge.
+ ///
+ /// Example:
+ /// ```dart
+ /// var leftTop = const Point(20, 50);
+ /// var rightBottom = const Point(300, 600);
+ /// var rectangle = MutableRectangle.fromPoints(leftTop, rightBottom);
+ /// print(rectangle); // Rectangle (20, 50) 280 x 550
+ /// print(rectangle.left); // 20
+ /// print(rectangle.top); // 50
+ /// print(rectangle.right); // 300
+ /// print(rectangle.bottom); // 600
+ /// ```
factory MutableRectangle.fromPoints(Point<T> a, Point<T> b) {
T left = min(a.x, b.x);
T width = (max(a.x, b.x) - left) as T;
diff --git a/tools/VERSION b/tools/VERSION
index 9856362..8f2a41d 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 16
PATCH 0
-PRERELEASE 128
+PRERELEASE 129
PRERELEASE_PATCH 0
\ No newline at end of file