Version 2.13.0-102.0.dev
Merge commit '810d6c7a6b646d1cda5ffe967b5b99576cfd785d' into 'dev'
diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json
index 45febc4..3ce1a567e 100644
--- a/.dart_tool/package_config.json
+++ b/.dart_tool/package_config.json
@@ -11,7 +11,7 @@
"constraint, update this by running tools/generate_package_config.dart."
],
"configVersion": 2,
- "generated": "2021-03-01T09:26:17.118461",
+ "generated": "2021-03-03T09:46:04.757962",
"generator": "tools/generate_package_config.dart",
"packages": [
{
@@ -232,7 +232,7 @@
"name": "dartdoc",
"rootUri": "../third_party/pkg/dartdoc",
"packageUri": "lib/",
- "languageVersion": "2.10"
+ "languageVersion": "2.11"
},
{
"name": "dds",
@@ -392,7 +392,7 @@
"name": "linter",
"rootUri": "../third_party/pkg/linter",
"packageUri": "lib/",
- "languageVersion": "2.6"
+ "languageVersion": "2.12"
},
{
"name": "logging",
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3f33539..6a2ee87 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,15 @@
#### Dartanalyzer
+#### Linter
+
+Updated the Linter to `1.0.0`, which includes:
+
+- full library migration to null-safety.
+- new lint: `use_if_null_to_convert_nulls_to_bools`.
+- new lint: `deprecated_consistency`.
+- new lint: `use_named_constants`.
+- deprecation of `avoid_as`.
## 2.12.0
diff --git a/DEPS b/DEPS
index 383b118..c5853e5 100644
--- a/DEPS
+++ b/DEPS
@@ -118,7 +118,7 @@
"intl_tag": "0.17.0-nullsafety",
"jinja2_rev": "2222b31554f03e62600cd7e383376a7c187967a1",
"json_rpc_2_rev": "b8dfe403fd8528fd14399dee3a6527b55802dd4d",
- "linter_tag": "0.1.129",
+ "linter_tag": "1.0.0",
"logging_rev": "e2f633b543ef89c54688554b15ca3d7e425b86a2",
"markupsafe_rev": "8f45f5cfa0009d2a70589bcda0349b8cb2b72783",
"markdown_rev": "9c4beaac96d8f008078e00b027915f81b665d2de",
diff --git a/pkg/_fe_analyzer_shared/lib/src/base/errors.dart b/pkg/_fe_analyzer_shared/lib/src/base/errors.dart
index 46bc443..27bd02b 100644
--- a/pkg/_fe_analyzer_shared/lib/src/base/errors.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/base/errors.dart
@@ -47,7 +47,7 @@
required String message,
required this.name,
required this.uniqueName,
- }) : _correction = correction,
+ }) : _correction = correction,
_message = message,
// ignore: unnecessary_null_comparison
assert(hasPublishedDocs != null),
diff --git a/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart b/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
index 2f8d1e5..766b57a 100644
--- a/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
@@ -321,8 +321,9 @@
@override
R accept<R, Node extends Object, Expression extends Object,
- Variable extends Object>(
- NonPromotionReasonVisitor<R, Node, Expression, Variable> visitor) =>
+ Variable extends Object, Type extends Object>(
+ NonPromotionReasonVisitor<R, Node, Expression, Variable, Type>
+ visitor) =>
visitor.visitDemoteViaExplicitWrite(
this as DemoteViaExplicitWrite<Variable, Expression>);
@@ -348,8 +349,9 @@
@override
R accept<R, Node extends Object, Expression extends Object,
- Variable extends Object>(
- NonPromotionReasonVisitor<R, Node, Expression, Variable> visitor) =>
+ Variable extends Object, Type extends Object>(
+ NonPromotionReasonVisitor<R, Node, Expression, Variable, Type>
+ visitor) =>
visitor.visitDemoteViaForEachVariableWrite(
this as DemoteViaForEachVariableWrite<Variable, Node>);
@@ -766,9 +768,10 @@
/// Call this method just after visiting a property get expression.
/// [wholeExpression] should be the whole property get, [target] should be the
/// expression to the left hand side of the `.`, and [propertyName] should be
- /// the identifier to the right hand side of the `.`.
- void propertyGet(
- Expression wholeExpression, Expression target, String propertyName);
+ /// the identifier to the right hand side of the `.`. [staticType] should be
+ /// the static type of the value returned by the property get.
+ void propertyGet(Expression wholeExpression, Expression target,
+ String propertyName, Type staticType);
/// Retrieves the SSA node associated with [variable], or `null` if [variable]
/// is not associated with an SSA node because it is write captured. For
@@ -808,16 +811,19 @@
/// Call this method just after visiting the expression `this` (or the
/// pseudo-expression `super`, in the case of the analyzer, which represents
/// `super.x` as a property get whose target is `super`). [expression] should
- /// be the `this` or `super` expression.
- void thisOrSuper(Expression expression);
+ /// be the `this` or `super` expression. [staticType] should be the static
+ /// type of `this`.
+ void thisOrSuper(Expression expression, Type staticType);
/// Call this method just after visiting an expression that represents a
/// property get on `this` or `super`. This handles situations where there is
/// an implicit reference to `this`, or the case of the front end, where
/// `super.x` is represented by a single expression. [expression] should be
/// the whole property get, and [propertyName] should be the name of the
- /// property being read.
- void thisOrSuperPropertyGet(Expression expression, String propertyName);
+ /// property being read. [staticType] should be the static type of the value
+ /// returned by the property get.
+ void thisOrSuperPropertyGet(
+ Expression expression, String propertyName, Type staticType);
/// Call this method just before visiting the body of a "try/catch" statement.
///
@@ -928,7 +934,19 @@
/// promotion, to retrieve information about why [target] was not promoted.
/// This call must be made right after visiting [target].
///
- /// If [target] is `null` it is assumed to be an implicit reference to `this`.
+ /// The returned value is a map whose keys are types that the user might have
+ /// been expecting the target to be promoted to, and whose values are reasons
+ /// why the corresponding promotion did not occur. The caller is expected to
+ /// select which non-promotion reason to report to the user by seeing which
+ /// promotion would have prevented the error. (For example, if an error
+ /// occurs due to the target having a nullable type, the caller should report
+ /// a non-promotion reason associated with non-promotion to a non-nullable
+ /// type).
+ Map<Type, NonPromotionReason> whyNotPromoted(Expression target);
+
+ /// Call this method when an error occurs that may be due to a lack of type
+ /// promotion, to retrieve information about why an implicit reference to
+ /// `this` was not promoted. [staticType] is the (unpromoted) type of `this`.
///
/// The returned value is a map whose keys are types that the user might have
/// been expecting the target to be promoted to, and whose values are reasons
@@ -938,7 +956,7 @@
/// occurs due to the target having a nullable type, the caller should report
/// a non-promotion reason associated with non-promotion to a non-nullable
/// type).
- Map<Type, NonPromotionReason> whyNotPromoted(Expression? target);
+ Map<Type, NonPromotionReason> whyNotPromotedImplicitThis(Type staticType);
/// Register write of the given [variable] in the current state.
/// [writtenType] should be the type of the value that was written.
@@ -1333,10 +1351,12 @@
}
@override
- void propertyGet(
- Expression wholeExpression, Expression target, String propertyName) {
- _wrap('propertyGet($wholeExpression, $target, $propertyName)',
- () => _wrapped.propertyGet(wholeExpression, target, propertyName));
+ void propertyGet(Expression wholeExpression, Expression target,
+ String propertyName, Type staticType) {
+ _wrap(
+ 'propertyGet($wholeExpression, $target, $propertyName, $staticType)',
+ () => _wrapped.propertyGet(
+ wholeExpression, target, propertyName, staticType));
}
@override
@@ -1365,15 +1385,18 @@
}
@override
- void thisOrSuper(Expression expression) {
- return _wrap(
- 'thisOrSuper($expression)', () => _wrapped.thisOrSuper(expression));
+ void thisOrSuper(Expression expression, Type staticType) {
+ return _wrap('thisOrSuper($expression, $staticType)',
+ () => _wrapped.thisOrSuper(expression, staticType));
}
@override
- void thisOrSuperPropertyGet(Expression expression, String propertyName) {
- _wrap('thisOrSuperPropertyGet($expression, $propertyName)',
- () => _wrapped.thisOrSuperPropertyGet(expression, propertyName));
+ void thisOrSuperPropertyGet(
+ Expression expression, String propertyName, Type staticType) {
+ _wrap(
+ 'thisOrSuperPropertyGet($expression, $propertyName, $staticType)',
+ () => _wrapped.thisOrSuperPropertyGet(
+ expression, propertyName, staticType));
}
@override
@@ -1453,13 +1476,20 @@
}
@override
- Map<Type, NonPromotionReason> whyNotPromoted(Expression? target) {
+ Map<Type, NonPromotionReason> whyNotPromoted(Expression target) {
return _wrap(
'whyNotPromoted($target)', () => _wrapped.whyNotPromoted(target),
isQuery: true);
}
@override
+ Map<Type, NonPromotionReason> whyNotPromotedImplicitThis(Type staticType) {
+ return _wrap('whyNotPromotedImplicitThis($staticType)',
+ () => _wrapped.whyNotPromotedImplicitThis(staticType),
+ isQuery: true);
+ }
+
+ @override
void write(Expression expression, Variable variable, Type writtenType,
Expression? writtenExpression) {
_wrap(
@@ -1895,23 +1925,22 @@
/// potentially nullable.
ExpressionInfo<Variable, Type> tryMarkNonNullable(
TypeOperations<Variable, Type> typeOperations,
- Reference<Variable, Type> reference) {
- VariableModel<Variable, Type> info = reference.getInfo(variableInfo);
+ ReferenceWithType<Variable, Type> referenceWithType) {
+ VariableModel<Variable, Type> info =
+ referenceWithType.reference.getInfo(variableInfo);
if (info.writeCaptured) {
return new _TrivialExpressionInfo<Variable, Type>(this);
}
- Type? previousType = info.promotedTypes?.last;
- previousType ??= reference.getDeclaredType(typeOperations);
-
+ Type previousType = referenceWithType.type;
Type newType = typeOperations.promoteToNonNull(previousType);
if (typeOperations.isSameType(newType, previousType)) {
return new _TrivialExpressionInfo<Variable, Type>(this);
}
assert(typeOperations.isSubtypeOf(newType, previousType));
- FlowModel<Variable, Type> modelIfSuccessful =
- _finishTypeTest(typeOperations, reference, info, null, newType);
+ FlowModel<Variable, Type> modelIfSuccessful = _finishTypeTest(
+ typeOperations, referenceWithType.reference, info, null, newType);
FlowModel<Variable, Type> modelIfFailed = this;
@@ -1920,7 +1949,8 @@
}
/// Returns an [ExpressionInfo] indicating the result of casting the given
- /// [reference] to the given [type], as a consequence of an `as` expression.
+ /// [referenceWithType] to the given [type], as a consequence of an `as`
+ /// expression.
///
/// Note that the state is only changed if [type] is a subtype of the
/// variable's previous (possibly promoted) type.
@@ -1929,16 +1959,15 @@
/// variable as definitely assigned? Does it matter?
FlowModel<Variable, Type> tryPromoteForTypeCast(
TypeOperations<Variable, Type> typeOperations,
- Reference<Variable, Type> reference,
+ ReferenceWithType<Variable, Type> referenceWithType,
Type type) {
- VariableModel<Variable, Type> info = reference.getInfo(variableInfo);
+ VariableModel<Variable, Type> info =
+ referenceWithType.reference.getInfo(variableInfo);
if (info.writeCaptured) {
return this;
}
- Type? previousType = info.promotedTypes?.last;
- previousType ??= reference.getDeclaredType(typeOperations);
-
+ Type previousType = referenceWithType.type;
Type? newType = typeOperations.tryPromoteToType(type, previousType);
if (newType == null || typeOperations.isSameType(newType, previousType)) {
return this;
@@ -1946,7 +1975,8 @@
assert(typeOperations.isSubtypeOf(newType, previousType),
"Expected $newType to be a subtype of $previousType.");
- return _finishTypeTest(typeOperations, reference, info, type, newType);
+ return _finishTypeTest(
+ typeOperations, referenceWithType.reference, info, type, newType);
}
/// Returns an [ExpressionInfo] indicating the result of checking whether the
@@ -1960,24 +1990,23 @@
/// variable as definitely assigned? Does it matter?
ExpressionInfo<Variable, Type> tryPromoteForTypeCheck(
TypeOperations<Variable, Type> typeOperations,
- Reference<Variable, Type> reference,
+ ReferenceWithType<Variable, Type> referenceWithType,
Type type) {
- VariableModel<Variable, Type> info = reference.getInfo(variableInfo);
+ VariableModel<Variable, Type> info =
+ referenceWithType.reference.getInfo(variableInfo);
if (info.writeCaptured) {
return new _TrivialExpressionInfo<Variable, Type>(this);
}
- Type? previousType = info.promotedTypes?.last;
- previousType ??= reference.getDeclaredType(typeOperations);
-
+ Type previousType = referenceWithType.type;
FlowModel<Variable, Type> modelIfSuccessful = this;
Type? typeIfSuccess = typeOperations.tryPromoteToType(type, previousType);
if (typeIfSuccess != null &&
!typeOperations.isSameType(typeIfSuccess, previousType)) {
assert(typeOperations.isSubtypeOf(typeIfSuccess, previousType),
"Expected $typeIfSuccess to be a subtype of $previousType.");
- modelIfSuccessful =
- _finishTypeTest(typeOperations, reference, info, type, typeIfSuccess);
+ modelIfSuccessful = _finishTypeTest(typeOperations,
+ referenceWithType.reference, info, type, typeIfSuccess);
}
Type factoredType = typeOperations.factor(previousType, type);
@@ -1992,8 +2021,8 @@
} else {
typeIfFailed = factoredType;
}
- FlowModel<Variable, Type> modelIfFailed =
- _finishTypeTest(typeOperations, reference, info, type, typeIfFailed);
+ FlowModel<Variable, Type> modelIfFailed = _finishTypeTest(
+ typeOperations, referenceWithType.reference, info, type, typeIfFailed);
return new ExpressionInfo<Variable, Type>(
this, modelIfSuccessful, modelIfFailed);
@@ -2292,13 +2321,13 @@
/// Implementation of the visitor pattern for non-promotion reasons.
R accept<R, Node extends Object, Expression extends Object,
- Variable extends Object>(
- NonPromotionReasonVisitor<R, Node, Expression, Variable> visitor);
+ Variable extends Object, Type extends Object>(
+ NonPromotionReasonVisitor<R, Node, Expression, Variable, Type> visitor);
}
/// Implementation of the visitor pattern for non-promotion reasons.
abstract class NonPromotionReasonVisitor<R, Node extends Object,
- Expression extends Object, Variable extends Object> {
+ Expression extends Object, Variable extends Object, Type extends Object> {
NonPromotionReasonVisitor._() : assert(false, 'Do not extend this class');
R visitDemoteViaExplicitWrite(
@@ -2307,27 +2336,33 @@
R visitDemoteViaForEachVariableWrite(
DemoteViaForEachVariableWrite<Variable, Node> reason);
- R visitPropertyNotPromoted(PropertyNotPromoted reason);
+ R visitPropertyNotPromoted(PropertyNotPromoted<Type> reason);
R visitThisNotPromoted(ThisNotPromoted reason);
}
/// Non-promotion reason describing the situation where an expression was not
/// promoted due to the fact that it's a property get.
-class PropertyNotPromoted extends NonPromotionReason {
+class PropertyNotPromoted<Type extends Object> extends NonPromotionReason {
/// The name of the property.
final String propertyName;
- PropertyNotPromoted(this.propertyName);
+ /// The static type of the property at the time of the access. This is the
+ /// type that was passed to [FlowAnalysis.whyNotPromoted]; it is provided to
+ /// the client as a convenience for ID testing.
+ final Type staticType;
+
+ PropertyNotPromoted(this.propertyName, this.staticType);
@override
String get shortName => 'propertyNotPromoted';
@override
R accept<R, Node extends Object, Expression extends Object,
- Variable extends Object>(
- NonPromotionReasonVisitor<R, Node, Expression, Variable> visitor) =>
- visitor.visitPropertyNotPromoted(this);
+ Variable extends Object, Type extends Object>(
+ NonPromotionReasonVisitor<R, Node, Expression, Variable, Type>
+ visitor) =>
+ visitor.visitPropertyNotPromoted(this as PropertyNotPromoted<Type>);
}
/// Immutable data structure modeling the reachability of the given point in the
@@ -2479,10 +2514,6 @@
/// why promotion did not occur.
@visibleForTesting
abstract class Reference<Variable extends Object, Type extends Object> {
- /// Retrieves the declared type of this reference. This is used as the
- /// starting point for promotions.
- Type getDeclaredType(TypeOperations<Variable, Type> typeOperations);
-
/// Gets the info for this reference, creating it if it doesn't exist.
VariableModel<Variable, Type> getInfo(
Map<Variable?, VariableModel<Variable, Type>> variableInfo) =>
@@ -2492,6 +2523,7 @@
/// is the map that will be returned from [FlowAnalysis.whyNotPromoted].
Map<Type, NonPromotionReason> getNonPromotionReasons(
Map<Variable?, VariableModel<Variable, Type>> variableInfo,
+ Type staticType,
TypeOperations<Variable, Type> typeOperations);
/// Creates a reference representing a get of a property called [propertyName]
@@ -2508,6 +2540,16 @@
Map<Variable?, VariableModel<Variable, Type>> variableInfo);
}
+/// Container object combining a [Reference] object with its static type.
+@visibleForTesting
+class ReferenceWithType<Variable extends Object, Type extends Object> {
+ final Reference<Variable, Type> reference;
+
+ final Type type;
+
+ ReferenceWithType(this.reference, this.type);
+}
+
/// Data structure representing a unique value that a variable might take on
/// during execution of the code being analyzed. SSA nodes are immutable (so
/// they can be safety shared among data structures) and have identity (so that
@@ -2552,8 +2594,9 @@
@override
R accept<R, Node extends Object, Expression extends Object,
- Variable extends Object>(
- NonPromotionReasonVisitor<R, Node, Expression, Variable> visitor) =>
+ Variable extends Object, Type extends Object>(
+ NonPromotionReasonVisitor<R, Node, Expression, Variable, Type>
+ visitor) =>
visitor.visitThisNotPromoted(this);
}
@@ -2573,9 +2616,6 @@
/// Operations on types, abstracted from concrete type interfaces.
abstract class TypeOperations<Variable extends Object, Type extends Object> {
- /// Gets the representation of the top type (`Object?`) in the type system.
- Type get topType;
-
/// Classifies the given type into one of the three categories defined by
/// the [TypeClassification] enum.
TypeClassification classifyType(Type type);
@@ -3214,12 +3254,9 @@
VariableReference(this.variable);
@override
- Type getDeclaredType(TypeOperations<Variable, Type> typeOperations) =>
- typeOperations.variableType(variable);
-
- @override
Map<Type, NonPromotionReason> getNonPromotionReasons(
Map<Variable?, VariableModel<Variable, Type>> variableInfo,
+ Type staticType,
TypeOperations<Variable, Type> typeOperations) {
Map<Type, NonPromotionReason> result = <Type, NonPromotionReason>{};
VariableModel<Variable, Type>? currentVariableInfo = variableInfo[variable];
@@ -3339,7 +3376,7 @@
/// If the LHS of `==` or `!=` is a reference, the thing being referred to.
/// Otherwise `null`.
- final Reference<Variable, Type>? _leftOperandReference;
+ final ReferenceWithType<Variable, Type>? _leftOperandReference;
_EqualityOpContext(ExpressionInfo<Variable, Type>? conditionInfo,
this._leftOperandType, this._leftOperandReference)
@@ -3385,7 +3422,7 @@
/// If [_expressionVariable] is not `null`, the reference corresponding to it.
/// Otherwise `null`.
- Reference<Variable, Type>? _expressionReference;
+ ReferenceWithType<Variable, Type>? _expressionReference;
int _functionNestingLevel = 0;
@@ -3398,10 +3435,11 @@
@override
void asExpression_end(Expression subExpression, Type type) {
- Reference<Variable, Type>? reference =
+ ReferenceWithType<Variable, Type>? referenceWithType =
_getExpressionReference(subExpression);
- if (reference == null) return;
- _current = _current.tryPromoteForTypeCast(typeOperations, reference, type);
+ if (referenceWithType == null) return;
+ _current =
+ _current.tryPromoteForTypeCast(typeOperations, referenceWithType, type);
}
@override
@@ -3508,10 +3546,11 @@
_EqualityOpContext<Variable, Type> context =
_stack.removeLast() as _EqualityOpContext<Variable, Type>;
ExpressionInfo<Variable, Type>? lhsInfo = context._conditionInfo;
- Reference<Variable, Type>? lhsReference = context._leftOperandReference;
+ ReferenceWithType<Variable, Type>? lhsReference =
+ context._leftOperandReference;
Type leftOperandType = context._leftOperandType;
ExpressionInfo<Variable, Type>? rhsInfo = _getExpressionInfo(rightOperand);
- Reference<Variable, Type>? rhsReference =
+ ReferenceWithType<Variable, Type>? rhsReference =
_getExpressionReference(rightOperand);
TypeClassification leftOperandTypeClassification =
typeOperations.classifyType(leftOperandType);
@@ -3692,7 +3731,7 @@
@override
void ifNullExpression_rightBegin(
Expression leftHandSide, Type leftHandSideType) {
- Reference<Variable, Type>? lhsReference =
+ ReferenceWithType<Variable, Type>? lhsReference =
_getExpressionReference(leftHandSide);
FlowModel<Variable, Type> promoted;
_current = _current.split();
@@ -3771,7 +3810,7 @@
@override
void isExpression_end(Expression isExpression, Expression subExpression,
bool isNot, Type type) {
- Reference<Variable, Type>? subExpressionReference =
+ ReferenceWithType<Variable, Type>? subExpressionReference =
_getExpressionReference(subExpression);
if (subExpressionReference != null) {
ExpressionInfo<Variable, Type> expressionInfo = _current
@@ -3865,7 +3904,7 @@
@override
void nonNullAssert_end(Expression operand) {
- Reference<Variable, Type>? operandReference =
+ ReferenceWithType<Variable, Type>? operandReference =
_getExpressionReference(operand);
if (operandReference != null) {
_current =
@@ -3886,7 +3925,7 @@
assert(targetType != null);
_current = _current.split();
_stack.add(new _NullAwareAccessContext<Variable, Type>(_current));
- Reference<Variable, Type>? targetReference =
+ ReferenceWithType<Variable, Type>? targetReference =
_getExpressionReference(target);
if (targetReference != null) {
_current =
@@ -3908,8 +3947,13 @@
@override
void promote(Variable variable, Type type) {
_current = _current
- .tryPromoteForTypeCheck(typeOperations,
- new VariableReference<Variable, Type>(variable), type)
+ .tryPromoteForTypeCheck(
+ typeOperations,
+ new ReferenceWithType<Variable, Type>(
+ new VariableReference<Variable, Type>(variable),
+ promotedType(variable) ??
+ typeOperations.variableType(variable)),
+ type)
.ifTrue;
}
@@ -3919,12 +3963,15 @@
}
@override
- void propertyGet(
- Expression wholeExpression, Expression target, String propertyName) {
- Reference<Variable, Type>? reference = _getExpressionReference(target);
+ void propertyGet(Expression wholeExpression, Expression target,
+ String propertyName, Type staticType) {
+ Reference<Variable, Type>? reference =
+ _getExpressionReference(target)?.reference;
if (reference != null) {
_storeExpressionReference(
- wholeExpression, reference.propertyGet(propertyName));
+ wholeExpression,
+ new ReferenceWithType<Variable, Type>(
+ reference.propertyGet(propertyName), staticType));
}
}
@@ -3973,14 +4020,21 @@
}
@override
- void thisOrSuper(Expression expression) {
- _storeExpressionReference(expression, new _ThisReference<Variable, Type>());
+ void thisOrSuper(Expression expression, Type staticType) {
+ _storeExpressionReference(
+ expression,
+ new ReferenceWithType<Variable, Type>(
+ new _ThisReference<Variable, Type>(), staticType));
}
@override
- void thisOrSuperPropertyGet(Expression expression, String propertyName) {
- _storeExpressionReference(expression,
- new _ThisReference<Variable, Type>().propertyGet(propertyName));
+ void thisOrSuperPropertyGet(
+ Expression expression, String propertyName, Type staticType) {
+ _storeExpressionReference(
+ expression,
+ new ReferenceWithType<Variable, Type>(
+ new _ThisReference<Variable, Type>().propertyGet(propertyName),
+ staticType));
}
@override
@@ -4067,16 +4121,19 @@
Type? variableRead(Expression expression, Variable variable) {
VariableReference<Variable, Type> variableReference =
new VariableReference<Variable, Type>(variable);
- _storeExpressionReference(expression, variableReference);
VariableModel<Variable, Type> variableModel =
variableReference.getInfo(_current.variableInfo);
+ Type? promotedType = variableModel.promotedTypes?.last;
+ Type currentType = promotedType ?? typeOperations.variableType(variable);
+ _storeExpressionReference(expression,
+ new ReferenceWithType<Variable, Type>(variableReference, currentType));
ExpressionInfo<Variable, Type>? expressionInfo = variableModel
.ssaNode?.expressionInfo
?.rebaseForward(typeOperations, _current);
if (expressionInfo != null) {
_storeExpressionInfo(expression, expressionInfo);
}
- return variableModel.promotedTypes?.last;
+ return promotedType;
}
@override
@@ -4107,21 +4164,22 @@
}
@override
- Map<Type, NonPromotionReason> whyNotPromoted(Expression? target) {
- Reference<Variable, Type>? reference;
- if (target == null) {
- reference = new _ThisReference<Variable, Type>();
- } else if (identical(target, _expressionWithReference)) {
- reference = _expressionReference;
- }
- if (reference != null) {
- return reference.getNonPromotionReasons(
- _current.variableInfo, typeOperations);
+ Map<Type, NonPromotionReason> whyNotPromoted(Expression target) {
+ ReferenceWithType<Variable, Type>? referenceWithType = _expressionReference;
+ if (referenceWithType != null) {
+ return referenceWithType.reference.getNonPromotionReasons(
+ _current.variableInfo, referenceWithType.type, typeOperations);
}
return {};
}
@override
+ Map<Type, NonPromotionReason> whyNotPromotedImplicitThis(Type staticType) {
+ return new _ThisReference<Variable, Type>().getNonPromotionReasons(
+ _current.variableInfo, staticType, typeOperations);
+ }
+
+ @override
void write(Expression expression, Variable variable, Type writtenType,
Expression? writtenExpression) {
ExpressionInfo<Variable, Type>? expressionInfo = writtenExpression == null
@@ -4174,9 +4232,11 @@
/// Gets the [Reference] associated with the [expression] (which should be the
/// last expression that was traversed). If there is no [Reference]
/// associated with the [expression], then `null` is returned.
- Reference<Variable, Type>? _getExpressionReference(Expression? expression) {
+ ReferenceWithType<Variable, Type>? _getExpressionReference(
+ Expression? expression) {
if (identical(expression, _expressionWithReference)) {
- Reference<Variable, Type>? expressionReference = _expressionReference;
+ ReferenceWithType<Variable, Type>? expressionReference =
+ _expressionReference;
_expressionReference = null;
return expressionReference;
} else {
@@ -4205,8 +4265,8 @@
/// Associates [expression], which should be the most recently visited
/// expression, with the given [Reference] object.
- void _storeExpressionReference(
- Expression expression, Reference<Variable, Type> expressionReference) {
+ void _storeExpressionReference(Expression expression,
+ ReferenceWithType<Variable, Type> expressionReference) {
_expressionWithReference = expression;
_expressionReference = expressionReference;
}
@@ -4637,8 +4697,8 @@
}
@override
- void propertyGet(
- Expression wholeExpression, Expression target, String propertyName) {}
+ void propertyGet(Expression wholeExpression, Expression target,
+ String propertyName, Type staticType) {}
@override
SsaNode<Variable, Type>? ssaNodeForTesting(Variable variable) {
@@ -4655,10 +4715,11 @@
void switchStatement_expressionEnd(Statement switchStatement) {}
@override
- void thisOrSuper(Expression expression) {}
+ void thisOrSuper(Expression expression, Type staticType) {}
@override
- void thisOrSuperPropertyGet(Expression expression, String propertyName) {}
+ void thisOrSuperPropertyGet(
+ Expression expression, String propertyName, Type staticType) {}
@override
void tryCatchStatement_bodyBegin() {}
@@ -4703,7 +4764,12 @@
void whileStatement_end() {}
@override
- Map<Type, NonPromotionReason> whyNotPromoted(Expression? target) {
+ Map<Type, NonPromotionReason> whyNotPromoted(Expression target) {
+ return {};
+ }
+
+ @override
+ Map<Type, NonPromotionReason> whyNotPromotedImplicitThis(Type staticType) {
return {};
}
@@ -4856,44 +4922,15 @@
_PropertyGetReference(this.target, this.propertyName);
@override
- Type getDeclaredType(TypeOperations<Variable, Type> typeOperations) {
- // Since we don't actually support property promotion, we just compute what
- // promotions would have occurred if we *did* support it (for the purpose of
- // issuing more useful error messages), we have some leeway in how we define
- // the "declared type" of a property. It's tempting to define it as the
- // return type of the referenced getter, but this is problematic for two
- // reasons: (1) we don't have the necessary hooks to ask the client what
- // this type is, and (2) the referenced getter can become more specific due
- // to the presence of other promotions, breaking the invariant that promoted
- // types are expected to be subtypes of the declared type, e.g.:
- //
- // abstract class C { num? get x; }
- // abstract class D extends C { int? get x; }
- // f(C c) {
- // if (c.x != null) { // "promotes" c.x to `num`
- // if (c is D) { // promotes c to D, so c.x now refers to an `int?`
- // // Invariant broken: `num` is not a subtype of `int?`
- // }
- // }
- // }
- //
- // Rather than break the invariant (which could lead to unexpected behaviors
- // of flow analysis, including possibly crashes), it seems wiser to simply
- // define the "declared type" for properties to be the top type; in practice
- // this still produces useful results, and it doesn't violate soundness
- // because we don't actually promote property references.
- return typeOperations.topType;
- }
-
- @override
Map<Type, NonPromotionReason> getNonPromotionReasons(
Map<Variable?, VariableModel<Variable, Type>> variableInfo,
+ Type staticType,
TypeOperations<Variable, Type> typeOperations) {
Map<Type, NonPromotionReason> result = <Type, NonPromotionReason>{};
List<Type>? promotedTypes = _getInfo(variableInfo)?.promotedTypes;
if (promotedTypes != null) {
for (Type type in promotedTypes) {
- result[type] = new PropertyNotPromoted(propertyName);
+ result[type] = new PropertyNotPromoted(propertyName, staticType);
}
}
return result;
@@ -4957,15 +4994,9 @@
class _ThisReference<Variable extends Object, Type extends Object>
extends Reference<Variable, Type> {
@override
- Type getDeclaredType(TypeOperations<Variable, Type> typeOperations) {
- // TODO(paulberry): can we return the actual type? Would that have a
- // user-visible effect?
- return typeOperations.topType;
- }
-
- @override
Map<Type, NonPromotionReason> getNonPromotionReasons(
Map<Variable?, VariableModel<Variable, Type>> variableInfo,
+ Type staticType,
TypeOperations<Variable, Type> typeOperations) {
Map<Type, NonPromotionReason> result = <Type, NonPromotionReason>{};
List<Type>? promotedTypes = _getInfo(variableInfo)?.promotedTypes;
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_mini_ast.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_mini_ast.dart
index d1a4d13..024a4c6 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_mini_ast.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_mini_ast.dart
@@ -144,9 +144,9 @@
[List<Statement>? ifFalse]) =>
new _If(condition, ifTrue, ifFalse);
-Statement implicitThis_whyNotPromoted(
+Statement implicitThis_whyNotPromoted(String staticType,
void Function(Map<Type, NonPromotionReason>) callback) =>
- new _WhyNotPromoted_ImplicitThis(callback);
+ new _WhyNotPromoted_ImplicitThis(Type(staticType), callback);
Statement labeled(Statement body) => new _LabeledStatement(body);
@@ -161,7 +161,7 @@
Expression this_(String type) => new _This(Type(type));
Expression thisOrSuperPropertyGet(String name, {String type = 'Object?'}) =>
- new _ThisOrSuperPropertyGet(name, type);
+ new _ThisOrSuperPropertyGet(name, Type(type));
Expression throw_(Expression operand) => new _Throw(operand);
@@ -284,7 +284,7 @@
/// If `this` is an expression `x`, creates the expression `x.name`.
Expression propertyGet(String name, {String type = 'Object?'}) =>
- new _PropertyGet(this, name, type);
+ new _PropertyGet(this, name, Type(type));
/// If `this` is an expression `x`, creates a pseudo-expression that models
/// evaluation of `x` followed by execution of [stmt]. This can be used to
@@ -435,9 +435,6 @@
Harness({this.legacy = false});
- @override
- Type get topType => Type('Object?');
-
/// Updates the harness so that when a [factor] query is invoked on types
/// [from] and [what], [result] will be returned.
void addFactor(String from, String what, String result) {
@@ -1477,7 +1474,7 @@
final String propertyName;
- final String type;
+ final Type type;
_PropertyGet(this.target, this.propertyName, this.type);
@@ -1490,8 +1487,8 @@
Type _visit(
Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
target._visit(h, flow);
- flow.propertyGet(this, target, propertyName);
- return Type(type);
+ flow.propertyGet(this, target, propertyName, type);
+ return type;
}
}
@@ -1566,7 +1563,7 @@
@override
Type _visit(
Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
- flow.thisOrSuper(this);
+ flow.thisOrSuper(this, type);
return type;
}
}
@@ -1574,7 +1571,7 @@
class _ThisOrSuperPropertyGet extends Expression {
final String propertyName;
- final String type;
+ final Type type;
_ThisOrSuperPropertyGet(this.propertyName, this.type);
@@ -1584,8 +1581,8 @@
@override
Type _visit(
Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
- flow.thisOrSuperPropertyGet(this, propertyName);
- return Type(type);
+ flow.thisOrSuperPropertyGet(this, propertyName, type);
+ return type;
}
}
@@ -1760,9 +1757,11 @@
}
class _WhyNotPromoted_ImplicitThis extends Statement {
+ final Type staticType;
+
final void Function(Map<Type, NonPromotionReason>) callback;
- _WhyNotPromoted_ImplicitThis(this.callback) : super._();
+ _WhyNotPromoted_ImplicitThis(this.staticType, this.callback) : super._();
@override
String toString() => 'implicit this (whyNotPromoted)';
@@ -1776,7 +1775,7 @@
assert(!Type._allowComparisons);
Type._allowComparisons = true;
try {
- callback(flow.whyNotPromoted(null));
+ callback(flow.whyNotPromotedImplicitThis(staticType));
} finally {
Type._allowComparisons = false;
}
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart
index f594559..67012be 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart
@@ -518,7 +518,9 @@
});
test('equalityOp_end does not set reachability for `this`', () {
- var h = Harness();
+ var h = Harness()
+ ..addSubtype('Null', 'C', false)
+ ..addFactor('C', 'Null', 'C');
h.addSubtype('C', 'Object', true);
h.run([
if_(this_('C').is_('Null'), [
@@ -1461,7 +1463,9 @@
});
test('isExpression_end() does not set reachability for `this`', () {
- var h = Harness();
+ var h = Harness()
+ ..addSubtype('Never', 'C', true)
+ ..addFactor('C', 'Never', 'C');
h.run([
if_(this_('C').is_('Never'), [
checkReachable(true),
@@ -3319,34 +3323,28 @@
test('unpromoted -> unchanged (same)', () {
var h = Harness();
var s1 = FlowModel<Var, Type>(Reachability.initial);
- var s2 =
- s1.tryPromoteForTypeCheck(h, _varRef(intVar), Type('int')).ifTrue;
+ var s2 = s1._tryPromoteForTypeCheck(h, intVar, 'int').ifTrue;
expect(s2, same(s1));
});
test('unpromoted -> unchanged (supertype)', () {
var h = Harness();
var s1 = FlowModel<Var, Type>(Reachability.initial);
- var s2 = s1
- .tryPromoteForTypeCheck(h, _varRef(intVar), Type('Object'))
- .ifTrue;
+ var s2 = s1._tryPromoteForTypeCheck(h, intVar, 'Object').ifTrue;
expect(s2, same(s1));
});
test('unpromoted -> unchanged (unrelated)', () {
var h = Harness();
var s1 = FlowModel<Var, Type>(Reachability.initial);
- var s2 = s1
- .tryPromoteForTypeCheck(h, _varRef(intVar), Type('String'))
- .ifTrue;
+ var s2 = s1._tryPromoteForTypeCheck(h, intVar, 'String').ifTrue;
expect(s2, same(s1));
});
test('unpromoted -> subtype', () {
var h = Harness();
var s1 = FlowModel<Var, Type>(Reachability.initial);
- var s2 =
- s1.tryPromoteForTypeCheck(h, _varRef(intQVar), Type('int')).ifTrue;
+ var s2 = s1._tryPromoteForTypeCheck(h, intQVar, 'int').ifTrue;
expect(s2.reachable.overallReachable, true);
expect(s2.variableInfo, {
intQVar: _matchVariableModel(chain: ['int'], ofInterest: ['int'])
@@ -3356,44 +3354,36 @@
test('promoted -> unchanged (same)', () {
var h = Harness();
var s1 = FlowModel<Var, Type>(Reachability.initial)
- .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('int'))
+ ._tryPromoteForTypeCheck(h, objectQVar, 'int')
.ifTrue;
- var s2 = s1
- .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('int'))
- .ifTrue;
+ var s2 = s1._tryPromoteForTypeCheck(h, objectQVar, 'int').ifTrue;
expect(s2, same(s1));
});
test('promoted -> unchanged (supertype)', () {
var h = Harness();
var s1 = FlowModel<Var, Type>(Reachability.initial)
- .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('int'))
+ ._tryPromoteForTypeCheck(h, objectQVar, 'int')
.ifTrue;
- var s2 = s1
- .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('Object'))
- .ifTrue;
+ var s2 = s1._tryPromoteForTypeCheck(h, objectQVar, 'Object').ifTrue;
expect(s2, same(s1));
});
test('promoted -> unchanged (unrelated)', () {
var h = Harness();
var s1 = FlowModel<Var, Type>(Reachability.initial)
- .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('int'))
+ ._tryPromoteForTypeCheck(h, objectQVar, 'int')
.ifTrue;
- var s2 = s1
- .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('String'))
- .ifTrue;
+ var s2 = s1._tryPromoteForTypeCheck(h, objectQVar, 'String').ifTrue;
expect(s2, same(s1));
});
test('promoted -> subtype', () {
var h = Harness();
var s1 = FlowModel<Var, Type>(Reachability.initial)
- .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('int?'))
+ ._tryPromoteForTypeCheck(h, objectQVar, 'int?')
.ifTrue;
- var s2 = s1
- .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('int'))
- .ifTrue;
+ var s2 = s1._tryPromoteForTypeCheck(h, objectQVar, 'int').ifTrue;
expect(s2.reachable.overallReachable, true);
expect(s2.variableInfo, {
objectQVar: _matchVariableModel(
@@ -3450,7 +3440,7 @@
var h = Harness();
var s1 = FlowModel<Var, Type>(Reachability.initial)
.declare(objectQVar, true)
- .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('int'))
+ ._tryPromoteForTypeCheck(h, objectQVar, 'int')
.ifTrue;
expect(s1.variableInfo, contains(objectQVar));
var s2 = s1.write(_MockNonPromotionReason(), objectQVar, Type('int?'),
@@ -3469,9 +3459,9 @@
var h = Harness();
var s1 = FlowModel<Var, Type>(Reachability.initial)
.declare(objectQVar, true)
- .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('num?'))
+ ._tryPromoteForTypeCheck(h, objectQVar, 'num?')
.ifTrue
- .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('int'))
+ ._tryPromoteForTypeCheck(h, objectQVar, 'int')
.ifTrue;
expect(s1.variableInfo, {
objectQVar: _matchVariableModel(
@@ -3496,11 +3486,11 @@
var h = Harness();
var s1 = FlowModel<Var, Type>(Reachability.initial)
.declare(objectQVar, true)
- .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('num?'))
+ ._tryPromoteForTypeCheck(h, objectQVar, 'num?')
.ifTrue
- .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('num'))
+ ._tryPromoteForTypeCheck(h, objectQVar, 'num')
.ifTrue
- .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('int'))
+ ._tryPromoteForTypeCheck(h, objectQVar, 'int')
.ifTrue;
expect(s1.variableInfo, {
objectQVar: _matchVariableModel(
@@ -3525,9 +3515,9 @@
var h = Harness();
var s1 = FlowModel<Var, Type>(Reachability.initial)
.declare(objectQVar, true)
- .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('num?'))
+ ._tryPromoteForTypeCheck(h, objectQVar, 'num?')
.ifTrue
- .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('num'))
+ ._tryPromoteForTypeCheck(h, objectQVar, 'num')
.ifTrue;
expect(s1.variableInfo, {
objectQVar: _matchVariableModel(
@@ -3553,9 +3543,9 @@
var h = Harness();
var s1 = FlowModel<Var, Type>(Reachability.initial)
.declare(objectQVar, true)
- .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('num?'))
+ ._tryPromoteForTypeCheck(h, objectQVar, 'num?')
.ifTrue
- .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('num'))
+ ._tryPromoteForTypeCheck(h, objectQVar, 'num')
.ifTrue;
expect(s1.variableInfo, {
objectQVar: _matchVariableModel(
@@ -3620,7 +3610,7 @@
var h = Harness();
var s1 = FlowModel<Var, Type>(Reachability.initial)
.declare(objectQVar, true)
- .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('int?'))
+ ._tryPromoteForTypeCheck(h, objectQVar, 'int?')
.ifTrue;
expect(s1.variableInfo, {
objectQVar: _matchVariableModel(
@@ -3642,7 +3632,7 @@
var h = Harness();
var s1 = FlowModel<Var, Type>(Reachability.initial)
.declare(objectQVar, true)
- .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('int?'))
+ ._tryPromoteForTypeCheck(h, objectQVar, 'int?')
.ifFalse;
expect(s1.variableInfo, {
objectQVar: _matchVariableModel(
@@ -3665,7 +3655,7 @@
var h = Harness();
var s1 = FlowModel<Var, Type>(Reachability.initial)
.declare(objectQVar, true)
- .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('num?'))
+ ._tryPromoteForTypeCheck(h, objectQVar, 'num?')
.ifFalse;
expect(s1.variableInfo, {
objectQVar: _matchVariableModel(
@@ -3687,9 +3677,9 @@
var h = Harness();
var s1 = FlowModel<Var, Type>(Reachability.initial)
.declare(objectQVar, true)
- .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('num?'))
+ ._tryPromoteForTypeCheck(h, objectQVar, 'num?')
.ifTrue
- .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('int?'))
+ ._tryPromoteForTypeCheck(h, objectQVar, 'int?')
.ifFalse;
expect(s1.variableInfo, {
objectQVar: _matchVariableModel(
@@ -3756,9 +3746,9 @@
var s1 = FlowModel<Var, Type>(Reachability.initial)
.declare(x, true)
- .tryPromoteForTypeCheck(h, _varRef(x), Type('B?'))
+ ._tryPromoteForTypeCheck(h, x, 'B?')
.ifFalse
- .tryPromoteForTypeCheck(h, _varRef(x), Type('A?'))
+ ._tryPromoteForTypeCheck(h, x, 'A?')
.ifFalse;
expect(s1.variableInfo, {
x: _matchVariableModel(
@@ -3782,9 +3772,9 @@
var s1 = FlowModel<Var, Type>(Reachability.initial)
.declare(x, true)
- .tryPromoteForTypeCheck(h, _varRef(x), Type('A?'))
+ ._tryPromoteForTypeCheck(h, x, 'A?')
.ifFalse
- .tryPromoteForTypeCheck(h, _varRef(x), Type('B?'))
+ ._tryPromoteForTypeCheck(h, x, 'B?')
.ifFalse;
expect(s1.variableInfo, {
x: _matchVariableModel(
@@ -3808,9 +3798,9 @@
var s1 = FlowModel<Var, Type>(Reachability.initial)
.declare(x, true)
- .tryPromoteForTypeCheck(h, _varRef(x), Type('A'))
+ ._tryPromoteForTypeCheck(h, x, 'A')
.ifFalse
- .tryPromoteForTypeCheck(h, _varRef(x), Type('A?'))
+ ._tryPromoteForTypeCheck(h, x, 'A?')
.ifFalse;
expect(s1.variableInfo, {
x: _matchVariableModel(
@@ -3835,9 +3825,9 @@
var h = Harness();
var s1 = FlowModel<Var, Type>(Reachability.initial)
.declare(objectQVar, true)
- .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('num?'))
+ ._tryPromoteForTypeCheck(h, objectQVar, 'num?')
.ifFalse
- .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('num*'))
+ ._tryPromoteForTypeCheck(h, objectQVar, 'num*')
.ifFalse;
expect(s1.variableInfo, {
objectQVar: _matchVariableModel(
@@ -3863,9 +3853,9 @@
var h = Harness();
var s1 = FlowModel<Var, Type>(Reachability.initial)
.declare(objectQVar, true)
- .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('num?'))
+ ._tryPromoteForTypeCheck(h, objectQVar, 'num?')
.ifFalse
- .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('num*'))
+ ._tryPromoteForTypeCheck(h, objectQVar, 'num*')
.ifFalse;
expect(s1.variableInfo, {
objectQVar: _matchVariableModel(
@@ -3895,9 +3885,9 @@
var s1 = FlowModel<Var, Type>(Reachability.initial)
.declare(x, true)
- .tryPromoteForTypeCheck(h, _varRef(x), Type('num?'))
+ ._tryPromoteForTypeCheck(h, x, 'num?')
.ifTrue
- .tryPromoteForTypeCheck(h, _varRef(x), Type('int?'))
+ ._tryPromoteForTypeCheck(h, x, 'int?')
.ifTrue;
expect(s1.variableInfo, {
x: _matchVariableModel(
@@ -3941,14 +3931,14 @@
test('unpromoted -> unchanged', () {
var h = Harness();
var s1 = FlowModel<Var, Type>(Reachability.initial);
- var s2 = s1.tryMarkNonNullable(h, _varRef(intVar)).ifTrue;
+ var s2 = s1._tryMarkNonNullable(h, intVar).ifTrue;
expect(s2, same(s1));
});
test('unpromoted -> promoted', () {
var h = Harness();
var s1 = FlowModel<Var, Type>(Reachability.initial);
- var s2 = s1.tryMarkNonNullable(h, _varRef(intQVar)).ifTrue;
+ var s2 = s1._tryMarkNonNullable(h, intQVar).ifTrue;
expect(s2.reachable.overallReachable, true);
expect(s2.infoFor(intQVar),
_matchVariableModel(chain: ['int'], ofInterest: []));
@@ -3957,18 +3947,18 @@
test('promoted -> unchanged', () {
var h = Harness();
var s1 = FlowModel<Var, Type>(Reachability.initial)
- .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('int'))
+ ._tryPromoteForTypeCheck(h, objectQVar, 'int')
.ifTrue;
- var s2 = s1.tryMarkNonNullable(h, _varRef(objectQVar)).ifTrue;
+ var s2 = s1._tryMarkNonNullable(h, objectQVar).ifTrue;
expect(s2, same(s1));
});
test('promoted -> re-promoted', () {
var h = Harness();
var s1 = FlowModel<Var, Type>(Reachability.initial)
- .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('int?'))
+ ._tryPromoteForTypeCheck(h, objectQVar, 'int?')
.ifTrue;
- var s2 = s1.tryMarkNonNullable(h, _varRef(objectQVar)).ifTrue;
+ var s2 = s1._tryMarkNonNullable(h, objectQVar).ifTrue;
expect(s2.reachable.overallReachable, true);
expect(s2.variableInfo, {
objectQVar:
@@ -3979,7 +3969,7 @@
test('promote to Never', () {
var h = Harness();
var s1 = FlowModel<Var, Type>(Reachability.initial);
- var s2 = s1.tryMarkNonNullable(h, _varRef(nullVar)).ifTrue;
+ var s2 = s1._tryMarkNonNullable(h, nullVar).ifTrue;
expect(s2.reachable.overallReachable, false);
expect(s2.infoFor(nullVar),
_matchVariableModel(chain: ['Never'], ofInterest: []));
@@ -3991,7 +3981,7 @@
var h = Harness();
var s1 = FlowModel<Var, Type>(Reachability.initial)
.declare(intQVar, true)
- .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('int'))
+ ._tryPromoteForTypeCheck(h, objectQVar, 'int')
.ifTrue;
var s2 = s1.conservativeJoin([intQVar], []);
expect(s2, isNot(same(s1)));
@@ -4005,9 +3995,9 @@
test('written', () {
var h = Harness();
var s1 = FlowModel<Var, Type>(Reachability.initial)
- .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('int'))
+ ._tryPromoteForTypeCheck(h, objectQVar, 'int')
.ifTrue
- .tryPromoteForTypeCheck(h, _varRef(intQVar), Type('int'))
+ ._tryPromoteForTypeCheck(h, intQVar, 'int')
.ifTrue;
var s2 = s1.conservativeJoin([intQVar], []);
expect(s2.reachable.overallReachable, true);
@@ -4020,9 +4010,9 @@
test('write captured', () {
var h = Harness();
var s1 = FlowModel<Var, Type>(Reachability.initial)
- .tryPromoteForTypeCheck(h, _varRef(objectQVar), Type('int'))
+ ._tryPromoteForTypeCheck(h, objectQVar, 'int')
.ifTrue
- .tryPromoteForTypeCheck(h, _varRef(intQVar), Type('int'))
+ ._tryPromoteForTypeCheck(h, intQVar, 'int')
.ifTrue;
var s2 = s1.conservativeJoin([], [intQVar]);
expect(s2.reachable.overallReachable, true);
@@ -4112,7 +4102,7 @@
var s0 = FlowModel<Var, Type>(Reachability.initial).declare(a, false);
// In s1, a is write captured. In s2 it's promoted.
var s1 = s0.conservativeJoin([a], [a]);
- var s2 = s0.tryPromoteForTypeCheck(h, _varRef(a), Type('int')).ifTrue;
+ var s2 = s0._tryPromoteForTypeCheck(h, a, 'int').ifTrue;
expect(
s1.rebaseForward(h, s2).infoFor(a),
_matchVariableModel(writeCaptured: true, chain: isNull),
@@ -4135,14 +4125,11 @@
null, x, Type('Object?'), new SsaNode<Var, Type>(null), h);
}
if (thisType != null) {
- s1 =
- s1.tryPromoteForTypeCheck(h, _varRef(x), Type(thisType)).ifTrue;
+ s1 = s1._tryPromoteForTypeCheck(h, x, thisType).ifTrue;
}
var s2 = otherType == null
? s0
- : s0
- .tryPromoteForTypeCheck(h, _varRef(x), Type(otherType))
- .ifTrue;
+ : s0._tryPromoteForTypeCheck(h, x, otherType).ifTrue;
var result = s2.rebaseForward(h, s1);
if (expectedChain == null) {
expect(result.variableInfo, contains(x));
@@ -4191,23 +4178,18 @@
var initialModel =
FlowModel<Var, Type>(Reachability.initial).declare(x, true);
for (var t in before) {
- initialModel = initialModel
- .tryPromoteForTypeCheck(h, _varRef(x), Type(t))
- .ifTrue;
+ initialModel = initialModel._tryPromoteForTypeCheck(h, x, t).ifTrue;
}
_checkChain(initialModel.infoFor(x).promotedTypes, before);
var tryModel = initialModel;
for (var t in inTry) {
- tryModel =
- tryModel.tryPromoteForTypeCheck(h, _varRef(x), Type(t)).ifTrue;
+ tryModel = tryModel._tryPromoteForTypeCheck(h, x, t).ifTrue;
}
var expectedTryChain = before.toList()..addAll(inTry);
_checkChain(tryModel.infoFor(x).promotedTypes, expectedTryChain);
var finallyModel = initialModel;
for (var t in inFinally) {
- finallyModel = finallyModel
- .tryPromoteForTypeCheck(h, _varRef(x), Type(t))
- .ifTrue;
+ finallyModel = finallyModel._tryPromoteForTypeCheck(h, x, t).ifTrue;
}
var expectedFinallyChain = before.toList()..addAll(inFinally);
_checkChain(
@@ -4246,9 +4228,8 @@
var h = Harness();
var a = Var('a', 'Object');
var s0 = FlowModel<Var, Type>(Reachability.initial).declare(a, false);
- var s1 = s0.tryPromoteForTypeCheck(h, _varRef(a), Type('int')).ifFalse;
- var s2 =
- s0.tryPromoteForTypeCheck(h, _varRef(a), Type('String')).ifFalse;
+ var s1 = s0._tryPromoteForTypeCheck(h, a, 'int').ifFalse;
+ var s2 = s0._tryPromoteForTypeCheck(h, a, 'String').ifFalse;
expect(
s1.rebaseForward(h, s2).infoFor(a),
_matchVariableModel(ofInterest: ['int', 'String']),
@@ -5687,8 +5668,8 @@
group('because this', () {
test('explicit', () {
var h = Harness()
- ..addSubtype('D', 'Object?', true)
- ..addFactor('Object?', 'D', 'Object?');
+ ..addSubtype('D', 'C', true)
+ ..addFactor('C', 'D', 'C');
h.run([
if_(this_('C').isNot('D'), [
return_(),
@@ -5703,13 +5684,13 @@
test('implicit', () {
var h = Harness()
- ..addSubtype('D', 'Object?', true)
- ..addFactor('Object?', 'D', 'Object?');
+ ..addSubtype('D', 'C', true)
+ ..addFactor('C', 'D', 'C');
h.run([
if_(this_('C').isNot('D'), [
return_(),
]),
- implicitThis_whyNotPromoted((reasons) {
+ implicitThis_whyNotPromoted('C', (reasons) {
expect(reasons.keys, unorderedEquals([Type('D')]));
var nonPromotionReason = reasons.values.single;
expect(nonPromotionReason, TypeMatcher<ThisNotPromoted>());
@@ -5787,14 +5768,28 @@
'writeCaptured: ${_describeMatcher(writeCapturedMatcher)})');
}
-Reference<Var, Type> _varRef(Var variable) =>
- new VariableReference<Var, Type>(variable);
-
class _MockNonPromotionReason extends NonPromotionReason {
String get shortName => fail('Unexpected call to shortName');
R accept<R, Node extends Object, Expression extends Object,
- Variable extends Object>(
- NonPromotionReasonVisitor<R, Node, Expression, Variable> visitor) =>
+ Variable extends Object, Type extends Object>(
+ NonPromotionReasonVisitor<R, Node, Expression, Variable, Type>
+ visitor) =>
fail('Unexpected call to accept');
}
+
+extension on FlowModel<Var, Type> {
+ Reference<Var, Type> _varRef(Var variable) =>
+ new VariableReference<Var, Type>(variable);
+
+ ReferenceWithType<Var, Type> _varRefWithType(Var variable) =>
+ new ReferenceWithType<Var, Type>(_varRef(variable),
+ variableInfo[variable]?.promotedTypes?.last ?? variable.type);
+
+ ExpressionInfo<Var, Type> _tryPromoteForTypeCheck(
+ Harness h, Var variable, String type) =>
+ tryPromoteForTypeCheck(h, _varRefWithType(variable), Type(type));
+
+ ExpressionInfo<Var, Type> _tryMarkNonNullable(Harness h, Var variable) =>
+ tryMarkNonNullable(h, _varRefWithType(variable));
+}
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/extension_property.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/extension_property.dart
index dbbefe9..1ac0a15 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/extension_property.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/extension_property.dart
@@ -5,17 +5,21 @@
class C {
get_property_via_explicit_this() {
if (this.i == null) return;
- this.i. /*notPromoted(propertyNotPromoted(member:E|get#i))*/ isEven;
+ this
+ .i
+ . /*notPromoted(propertyNotPromoted(target: member:E|get#i, type: int?))*/ isEven;
}
get_property_via_explicit_this_parenthesized() {
if ((this).i == null) return;
- (this).i. /*notPromoted(propertyNotPromoted(member:E|get#i))*/ isEven;
+ (this)
+ .i
+ . /*notPromoted(propertyNotPromoted(target: member:E|get#i, type: int?))*/ isEven;
}
get_property_by_implicit_this() {
if (i == null) return;
- i. /*notPromoted(propertyNotPromoted(member:E|get#i))*/ isEven;
+ i. /*notPromoted(propertyNotPromoted(target: member:E|get#i, type: int?))*/ isEven;
}
}
@@ -27,13 +31,13 @@
class D extends C {
get_property_by_implicit_super() {
if (i == null) return;
- i. /*notPromoted(propertyNotPromoted(member:E|get#i))*/ isEven;
+ i. /*notPromoted(propertyNotPromoted(target: member:E|get#i, type: int?))*/ isEven;
}
}
get_property_via_prefixed_identifier(C c) {
if (c.i == null) return;
- c.i. /*notPromoted(propertyNotPromoted(member:E|get#i))*/ isEven;
+ c.i. /*notPromoted(propertyNotPromoted(target: member:E|get#i, type: int?))*/ isEven;
}
get_property_via_prefixed_identifier_mismatched_target(C c1, C c2) {
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/field.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/field.dart
index 1829ad0..bc0a5e7 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/field.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/field.dart
@@ -8,35 +8,41 @@
get_field_via_explicit_this() {
if (this.i == null) return;
- this.i. /*notPromoted(propertyNotPromoted(member:C.i))*/ isEven;
+ this
+ .i
+ . /*notPromoted(propertyNotPromoted(target: member:C.i, type: int?))*/ isEven;
}
get_field_via_explicit_this_parenthesized() {
if ((this).i == null) return;
- (this).i. /*notPromoted(propertyNotPromoted(member:C.i))*/ isEven;
+ (this)
+ .i
+ . /*notPromoted(propertyNotPromoted(target: member:C.i, type: int?))*/ isEven;
}
get_field_by_implicit_this() {
if (i == null) return;
- i. /*notPromoted(propertyNotPromoted(member:C.i))*/ isEven;
+ i. /*notPromoted(propertyNotPromoted(target: member:C.i, type: int?))*/ isEven;
}
}
class D extends C {
get_field_via_explicit_super() {
if (super.i == null) return;
- super.i. /*notPromoted(propertyNotPromoted(member:C.i))*/ isEven;
+ super
+ .i
+ . /*notPromoted(propertyNotPromoted(target: member:C.i, type: int?))*/ isEven;
}
get_field_by_implicit_super() {
if (i == null) return;
- i. /*notPromoted(propertyNotPromoted(member:C.i))*/ isEven;
+ i. /*notPromoted(propertyNotPromoted(target: member:C.i, type: int?))*/ isEven;
}
}
get_field_via_prefixed_identifier(C c) {
if (c.i == null) return;
- c.i. /*notPromoted(propertyNotPromoted(member:C.i))*/ isEven;
+ c.i. /*notPromoted(propertyNotPromoted(target: member:C.i, type: int?))*/ isEven;
}
get_field_via_prefixed_identifier_mismatched_target(C c1, C c2) {
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/for_in_loop_type_not_iterable_nullability_error.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/for_in_loop_type_not_iterable_nullability_error.dart
index 4c0d40f..d43d616 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/for_in_loop_type_not_iterable_nullability_error.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/for_in_loop_type_not_iterable_nullability_error.dart
@@ -17,5 +17,6 @@
test(C1 c) {
if (c.bad == null) return;
for (var x
- in /*analyzer.notPromoted(propertyNotPromoted(member:C1.bad))*/ c.bad) {}
+ in /*analyzer.notPromoted(propertyNotPromoted(target: member:C1.bad, type: List<int>?))*/ c
+ .bad) {}
}
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/invalid_assignment_error_nullability_error.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/invalid_assignment_error_nullability_error.dart
index b8e021a..a249136 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/invalid_assignment_error_nullability_error.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/invalid_assignment_error_nullability_error.dart
@@ -16,5 +16,6 @@
test(C1 c) sync* {
if (c.bad == null) return;
- yield* /*analyzer.notPromoted(propertyNotPromoted(member:C1.bad))*/ c.bad;
+ yield* /*analyzer.notPromoted(propertyNotPromoted(target: member:C1.bad, type: List<int>?))*/ c
+ .bad;
}
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/nullable_expression_call_error.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/nullable_expression_call_error.dart
index 3e33316..985feaa 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/nullable_expression_call_error.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/nullable_expression_call_error.dart
@@ -16,8 +16,9 @@
instance_method_invocation(C1 c) {
if (c.bad == null) return;
- /*analyzer.notPromoted(propertyNotPromoted(member:C1.bad))*/ c.bad
- /*cfe.invoke: notPromoted(propertyNotPromoted(member:C1.bad))*/
+ /*analyzer.notPromoted(propertyNotPromoted(target: member:C1.bad, type: C2?))*/ c
+ .bad
+ /*cfe.invoke: notPromoted(propertyNotPromoted(target: member:C1.bad, type: C2?))*/
();
}
@@ -42,8 +43,9 @@
if (c.ok == null) return;
c.ok();
if (c.bad == null) return;
- /*analyzer.notPromoted(propertyNotPromoted(member:C3.bad))*/ c.bad
- /*cfe.invoke: notPromoted(propertyNotPromoted(member:C3.bad))*/
+ /*analyzer.notPromoted(propertyNotPromoted(target: member:C3.bad, type: C5?))*/ c
+ .bad
+ /*cfe.invoke: notPromoted(propertyNotPromoted(target: member:C3.bad, type: C5?))*/
();
}
@@ -57,8 +59,9 @@
instance_getter_invocation(C6 c) {
if (c.bad == null) return;
- /*analyzer.notPromoted(propertyNotPromoted(member:C6.bad))*/ c.bad
- /*cfe.invoke: notPromoted(propertyNotPromoted(member:C6.bad))*/
+ /*analyzer.notPromoted(propertyNotPromoted(target: member:C6.bad, type: C7?))*/ c
+ .bad
+ /*cfe.invoke: notPromoted(propertyNotPromoted(target: member:C6.bad, type: C7?))*/
();
}
@@ -83,8 +86,9 @@
if (c.ok == null) return;
c.ok();
if (c.bad == null) return;
- /*analyzer.notPromoted(propertyNotPromoted(member:C8.bad))*/ c.bad
- /*cfe.invoke: notPromoted(propertyNotPromoted(member:C8.bad))*/
+ /*analyzer.notPromoted(propertyNotPromoted(target: member:C8.bad, type: C10?))*/ c
+ .bad
+ /*cfe.invoke: notPromoted(propertyNotPromoted(target: member:C8.bad, type: C10?))*/
();
}
@@ -94,8 +98,9 @@
function_invocation(C11 c) {
if (c.bad == null) return;
- /*analyzer.notPromoted(propertyNotPromoted(member:C11.bad))*/ c.bad
- /*cfe.invoke: notPromoted(propertyNotPromoted(member:C11.bad))*/
+ /*analyzer.notPromoted(propertyNotPromoted(target: member:C11.bad, type: void Function()?))*/ c
+ .bad
+ /*cfe.invoke: notPromoted(propertyNotPromoted(target: member:C11.bad, type: void Function()?))*/
();
}
@@ -112,8 +117,8 @@
if (c.bad == null) return;
c.bad
.
- /*analyzer.notPromoted(propertyNotPromoted(member:C12.bad))*/
+ /*analyzer.notPromoted(propertyNotPromoted(target: member:C12.bad, type: C13?))*/
foo
- /*cfe.invoke: notPromoted(propertyNotPromoted(member:C12.bad))*/
+ /*cfe.invoke: notPromoted(propertyNotPromoted(target: member:C12.bad, type: C13?))*/
();
}
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/nullable_method_call_error.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/nullable_method_call_error.dart
index 40cc053..8fc9608 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/nullable_method_call_error.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/nullable_method_call_error.dart
@@ -39,7 +39,7 @@
property_get_of_expression(C c) {
if (c.i == null) return;
- c.i. /*notPromoted(propertyNotPromoted(member:C.i))*/ isEven;
+ c.i. /*notPromoted(propertyNotPromoted(target: member:C.i, type: int?))*/ isEven;
}
extension_property_get_of_expression(C c) {
@@ -48,8 +48,8 @@
c
.i
.
- /*cfe.invoke: notPromoted(propertyNotPromoted(member:C.i))*/
- /*analyzer.notPromoted(propertyNotPromoted(member:C.i))*/
+ /*cfe.invoke: notPromoted(propertyNotPromoted(target: member:C.i, type: int?))*/
+ /*analyzer.notPromoted(propertyNotPromoted(target: member:C.i, type: int?))*/
propertyOnNonNullInt;
}
@@ -57,8 +57,8 @@
if (c.i == null) return;
c.i
.
- /*cfe.invoke: notPromoted(propertyNotPromoted(member:C.i))*/
- /*analyzer.notPromoted(propertyNotPromoted(member:C.i))*/
+ /*cfe.invoke: notPromoted(propertyNotPromoted(target: member:C.i, type: int?))*/
+ /*analyzer.notPromoted(propertyNotPromoted(target: member:C.i, type: int?))*/
abs();
}
@@ -67,8 +67,8 @@
c.i.methodOnNullableInt();
c.i
.
- /*cfe.invoke: notPromoted(propertyNotPromoted(member:C.i))*/
- /*analyzer.notPromoted(propertyNotPromoted(member:C.i))*/
+ /*cfe.invoke: notPromoted(propertyNotPromoted(target: member:C.i, type: int?))*/
+ /*analyzer.notPromoted(propertyNotPromoted(target: member:C.i, type: int?))*/
methodOnNonNullInt();
}
@@ -76,7 +76,7 @@
if (c.f == null) return;
c.f
.
- /*cfe.invoke: notPromoted(propertyNotPromoted(member:C.f))*/
- /*analyzer.notPromoted(propertyNotPromoted(member:C.f))*/
+ /*cfe.invoke: notPromoted(propertyNotPromoted(target: member:C.f, type: void Function()?))*/
+ /*analyzer.notPromoted(propertyNotPromoted(target: member:C.f, type: void Function()?))*/
call();
}
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/nullable_spread_error.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/nullable_spread_error.dart
index d3f6451..8398f56 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/nullable_spread_error.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/nullable_spread_error.dart
@@ -16,6 +16,7 @@
test(C1 c) {
if (c.bad == null) return;
return [
- ... /*analyzer.notPromoted(propertyNotPromoted(member:C1.bad))*/ c.bad
+ ... /*analyzer.notPromoted(propertyNotPromoted(target: member:C1.bad, type: List<int>?))*/ c
+ .bad
];
}
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/property.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/property.dart
index 24b85cc..90fe382 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/property.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/why_not_promoted/data/property.dart
@@ -8,35 +8,41 @@
get_property_via_explicit_this() {
if (this.i == null) return;
- this.i. /*notPromoted(propertyNotPromoted(member:C.i))*/ isEven;
+ this
+ .i
+ . /*notPromoted(propertyNotPromoted(target: member:C.i, type: int?))*/ isEven;
}
get_property_via_explicit_this_parenthesized() {
if ((this).i == null) return;
- (this).i. /*notPromoted(propertyNotPromoted(member:C.i))*/ isEven;
+ (this)
+ .i
+ . /*notPromoted(propertyNotPromoted(target: member:C.i, type: int?))*/ isEven;
}
get_property_by_implicit_this() {
if (i == null) return;
- i. /*notPromoted(propertyNotPromoted(member:C.i))*/ isEven;
+ i. /*notPromoted(propertyNotPromoted(target: member:C.i, type: int?))*/ isEven;
}
}
class D extends C {
get_property_via_explicit_super() {
if (super.i == null) return;
- super.i. /*notPromoted(propertyNotPromoted(member:C.i))*/ isEven;
+ super
+ .i
+ . /*notPromoted(propertyNotPromoted(target: member:C.i, type: int?))*/ isEven;
}
get_property_by_implicit_super() {
if (i == null) return;
- i. /*notPromoted(propertyNotPromoted(member:C.i))*/ isEven;
+ i. /*notPromoted(propertyNotPromoted(target: member:C.i, type: int?))*/ isEven;
}
}
get_property_via_prefixed_identifier(C c) {
if (c.i == null) return;
- c.i. /*notPromoted(propertyNotPromoted(member:C.i))*/ isEven;
+ c.i. /*notPromoted(propertyNotPromoted(target: member:C.i, type: int?))*/ isEven;
}
get_property_via_prefixed_identifier_mismatched_target(C c1, C c2) {
diff --git a/pkg/analysis_server/lib/src/context_manager.dart b/pkg/analysis_server/lib/src/context_manager.dart
index abacc10..6fd6cb7 100644
--- a/pkg/analysis_server/lib/src/context_manager.dart
+++ b/pkg/analysis_server/lib/src/context_manager.dart
@@ -362,17 +362,19 @@
void _checkForAndroidManifestXmlUpdate(String path) {
if (file_paths.isAndroidManifestXml(pathContext, path)) {
- var context = getContextFor(path);
- var driver = context.driver;
- _analyzeAndroidManifestXml(driver, path);
+ var driver = getDriverFor(path);
+ if (driver != null) {
+ _analyzeAndroidManifestXml(driver, path);
+ }
}
}
void _checkForFixDataYamlUpdate(String path) {
if (file_paths.isFixDataYaml(pathContext, path)) {
- var context = getContextFor(path);
- var driver = context.driver;
- _analyzeFixDataYaml(driver, path);
+ var driver = getDriverFor(path);
+ if (driver != null) {
+ _analyzeFixDataYaml(driver, path);
+ }
}
}
diff --git a/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart b/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart
index 7f4ab1f..5280479 100644
--- a/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart
+++ b/pkg/analysis_server/lib/src/services/correction/bulk_fix_processor.dart
@@ -237,7 +237,7 @@
) sync* {
final errorCode = diagnostic.errorCode;
if (errorCode is LintCode) {
- var fixes = FixProcessor.lintProducerMap2[errorCode.name];
+ var fixes = FixProcessor.lintProducerMap2[errorCode.name] ?? [];
for (var fix in fixes) {
if (fix.canBeBulkApplied) {
final generators = fix.generators;
@@ -366,7 +366,7 @@
try {
var codeName = errorCode.name;
if (errorCode is LintCode) {
- var fixes = FixProcessor.lintProducerMap2[errorCode.name];
+ var fixes = FixProcessor.lintProducerMap2[errorCode.name] ?? [];
for (var fix in fixes) {
if (fix.canBeBulkApplied) {
final generators = fix.generators;
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/add_ne_null.dart b/pkg/analysis_server/lib/src/services/correction/dart/add_ne_null.dart
index 69ba3a9..ef38ab3 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/add_ne_null.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/add_ne_null.dart
@@ -12,6 +12,9 @@
FixKind get fixKind => DartFixKind.ADD_NE_NULL;
@override
+ FixKind get multiFixKind => DartFixKind.ADD_NE_NULL_MULTI;
+
+ @override
Future<void> compute(ChangeBuilder builder) async {
var problemMessage = diagnostic.problemMessage;
await builder.addDartFileEdit(file, (builder) {
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/add_null_check.dart b/pkg/analysis_server/lib/src/services/correction/dart/add_null_check.dart
index 1eaee2a..bc898f7 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/add_null_check.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/add_null_check.dart
@@ -68,7 +68,11 @@
toType = enclosingExecutable.declaredElement.returnType;
}
} else if ((parent is PrefixedIdentifier && target == parent.prefix) ||
+ parent is PostfixExpression ||
+ parent is PrefixExpression ||
+ parent is BinaryExpression ||
(parent is PropertyAccess && target == parent.target) ||
+ (parent is CascadeExpression && target == parent.target) ||
(parent is MethodInvocation && target == parent.target) ||
(parent is FunctionExpressionInvocation && target == parent.function)) {
// No need to set the `toType` because there isn't any need for a type
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_generic_function_syntax.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_generic_function_syntax.dart
index c101539..9b3906c 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_generic_function_syntax.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_generic_function_syntax.dart
@@ -89,19 +89,16 @@
if (!_allParametersHaveTypes(node.parameters)) {
return;
}
- String returnType;
- if (node.returnType != null) {
- returnType = utils.getNodeText(node.returnType);
- }
+ var required = node.requiredKeyword != null ? 'required ' : '';
+ var covariant = node.covariantKeyword != null ? 'covariant ' : '';
+ var returnType =
+ node.returnType != null ? '${utils.getNodeText(node.returnType)} ' : '';
var functionName = utils.getRangeText(range.startEnd(
node.identifier, node.typeParameters ?? node.identifier));
var parameters = utils.getNodeText(node.parameters);
- String replacement;
- if (returnType == null) {
- replacement = 'Function$parameters $functionName';
- } else {
- replacement = '$returnType Function$parameters $functionName';
- }
+ var question = node.question != null ? '?' : '';
+ var replacement =
+ '$required$covariant${returnType}Function$parameters$question $functionName';
// add change
await builder.addDartFileEdit(file, (builder) {
builder.addSimpleReplacement(range.node(node), replacement);
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index c6ddc15..6e59e10 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -314,6 +314,15 @@
class FixProcessor extends BaseProcessor {
/// todo (pq): to replace nonLintProducerMap.
static const Map<ErrorCode, List<FixInfo>> nonLintProducerMap2 = {
+ CompileTimeErrorCode.NON_BOOL_CONDITION: [
+ FixInfo(
+ canBeAppliedToFile: true,
+ canBeBulkApplied: false,
+ generators: [
+ AddNeNull.newInstance,
+ ],
+ ),
+ ],
HintCode.UNUSED_IMPORT: [
FixInfo(
canBeAppliedToFile: true,
@@ -956,10 +965,8 @@
],
LintNames.unnecessary_parenthesis: [
FixInfo(
- // todo (pq): enable when tested
- canBeAppliedToFile: false,
- // not currently supported; TODO(pq): consider adding
- canBeBulkApplied: false,
+ canBeAppliedToFile: true,
+ canBeBulkApplied: true,
generators: [
RemoveUnnecessaryParentheses.newInstance,
],
diff --git a/pkg/analysis_server/test/src/cider/fixes_test.dart b/pkg/analysis_server/test/src/cider/fixes_test.dart
index 6eeaf47..8b8d691 100644
--- a/pkg/analysis_server/test/src/cider/fixes_test.dart
+++ b/pkg/analysis_server/test/src/cider/fixes_test.dart
@@ -48,7 +48,7 @@
''');
// The file was resolved only once, even though we have 2 errors.
- expect(fileResolver.testView.resolvedFiles, [testPath]);
+ expect(fileResolver.testView.resolvedFiles, [convertPath(testPath)]);
}
Future<void> test_createMethod() async {
diff --git a/pkg/analysis_server/test/src/plugin/plugin_manager_test.dart b/pkg/analysis_server/test/src/plugin/plugin_manager_test.dart
index 87241b1..d9bea42 100644
--- a/pkg/analysis_server/test/src/plugin/plugin_manager_test.dart
+++ b/pkg/analysis_server/test/src/plugin/plugin_manager_test.dart
@@ -32,17 +32,8 @@
});
}
-ContextRootImpl _newContextRoot(String root) {
- var resourceProvider = PhysicalResourceProvider.INSTANCE;
- return ContextRootImpl(
- resourceProvider,
- resourceProvider.getFolder(root),
- BasicWorkspace.find(resourceProvider, {}, root),
- );
-}
-
@reflectiveTest
-class BuiltInPluginInfoTest {
+class BuiltInPluginInfoTest with ResourceProviderMixin, _ContextRoot {
TestNotificationManager notificationManager;
BuiltInPluginInfo plugin;
@@ -111,7 +102,7 @@
}
@reflectiveTest
-class DiscoveredPluginInfoTest {
+class DiscoveredPluginInfoTest with ResourceProviderMixin, _ContextRoot {
TestNotificationManager notificationManager;
String pluginPath = '/pluginDir';
String executionPath = '/pluginDir/bin/plugin.dart';
@@ -125,10 +116,9 @@
}
void test_addContextRoot() {
- var optionsFilePath = '/pkg1/analysis_options.yaml';
var contextRoot1 = _newContextRoot('/pkg1');
- contextRoot1.optionsFile =
- contextRoot1.resourceProvider.getFile(optionsFilePath);
+ var optionsFile = getFile('/pkg1/analysis_options.yaml');
+ contextRoot1.optionsFile = optionsFile;
var session = PluginSession(plugin);
var channel = TestServerCommunicationChannel(session);
plugin.currentSession = session;
@@ -139,7 +129,7 @@
var sentRequests = channel.sentRequests;
expect(sentRequests, hasLength(1));
List<Map> roots = sentRequests[0].params['roots'];
- expect(roots[0]['optionsFile'], optionsFilePath);
+ expect(roots[0]['optionsFile'], optionsFile.path);
}
void test_creation() {
@@ -447,10 +437,14 @@
});
pkg1Dir.deleteSync(recursive: true);
}
+
+ ContextRootImpl _newContextRoot(String root) {
+ throw UnimplementedError();
+ }
}
@reflectiveTest
-class PluginManagerTest with ResourceProviderMixin {
+class PluginManagerTest with ResourceProviderMixin, _ContextRoot {
String byteStorePath;
String sdkPath;
TestNotificationManager notificationManager;
@@ -944,3 +938,14 @@
}
}
}
+
+mixin _ContextRoot on ResourceProviderMixin {
+ ContextRootImpl _newContextRoot(String root) {
+ root = convertPath(root);
+ return ContextRootImpl(
+ resourceProvider,
+ resourceProvider.getFolder(root),
+ BasicWorkspace.find(resourceProvider, {}, root),
+ );
+ }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/add_ne_null_test.dart b/pkg/analysis_server/test/src/services/correction/fix/add_ne_null_test.dart
index c7b5820..fe07091 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/add_ne_null_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/add_ne_null_test.dart
@@ -11,36 +11,21 @@
void main() {
defineReflectiveSuite(() {
+ defineReflectiveTests(AddNeNullMultiTest);
defineReflectiveTests(AddNeNullTest);
});
}
@reflectiveTest
-class AddNeNullTest extends FixProcessorTest {
+class AddNeNullMultiTest extends FixProcessorTest {
@override
- FixKind get kind => DartFixKind.ADD_NE_NULL;
+ FixKind get kind => DartFixKind.ADD_NE_NULL_MULTI;
- Future<void> test_nonBoolCondition() async {
- await resolveTestCode('''
-main(String p) {
- if (p) {
- print(p);
- }
-}
-''');
- await assertHasFix('''
-main(String p) {
- if (p != null) {
- print(p);
- }
-}
-''');
- }
-
- @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/45026')
+ // todo (pq): add null-safe aware tests
+ // see: https://dart-review.googlesource.com/c/sdk/+/188681
Future<void> test_nonBoolCondition_all() async {
await resolveTestCode('''
-main(String p, String q) {
+f(String p, String q) {
if (p) {
print(p);
}
@@ -50,7 +35,7 @@
}
''');
await assertHasFixAllFix(CompileTimeErrorCode.NON_BOOL_CONDITION, '''
-main(String p, String q) {
+f(String p, String q) {
if (p != null) {
print(p);
}
@@ -61,3 +46,26 @@
''');
}
}
+
+@reflectiveTest
+class AddNeNullTest extends FixProcessorTest {
+ @override
+ FixKind get kind => DartFixKind.ADD_NE_NULL;
+
+ Future<void> test_nonBoolCondition() async {
+ await resolveTestCode('''
+f(String p) {
+ if (p) {
+ print(p);
+ }
+}
+''');
+ await assertHasFix('''
+f(String p) {
+ if (p != null) {
+ print(p);
+ }
+}
+''');
+ }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/add_null_check_test.dart b/pkg/analysis_server/test/src/services/correction/fix/add_null_check_test.dart
index 09750df..84fb89a 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/add_null_check_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/add_null_check_test.dart
@@ -99,6 +99,24 @@
''');
}
+ Future<void> test_binaryOperator_leftSide() async {
+ await resolveTestCode('''
+f(int? i) => i + 1;
+''');
+ await assertHasFix('''
+f(int? i) => i! + 1;
+''');
+ }
+
+ Future<void> test_binaryOperator_rightSide() async {
+ await resolveTestCode('''
+f(int? i) => 1 + i;
+''');
+ await assertHasFix('''
+f(int? i) => 1 + i!;
+''');
+ }
+
Future<void> test_forEachWithDeclarationCondition() async {
await resolveTestCode('''
void f (List<String>? args) {
@@ -225,6 +243,15 @@
''');
}
+ Future<void> test_postfixOperator() async {
+ await resolveTestCode('''
+f(int? i) => i++;
+''');
+ await assertHasFix('''
+f(int? i) => i!++;
+''');
+ }
+
Future<void> test_prefixedIdentifier() async {
await resolveTestCode('''
int f(String? s) => s.length;
@@ -234,6 +261,15 @@
''');
}
+ Future<void> test_prefixOperator() async {
+ await resolveTestCode('''
+f(int? i) => -i;
+''');
+ await assertHasFix('''
+f(int? i) => -i!;
+''');
+ }
+
Future<void> test_propertyAccess() async {
await resolveTestCode('''
int f(String? s) => (s).length;
@@ -243,6 +279,24 @@
''');
}
+ Future<void> test_propertyAccess_cascade() async {
+ await resolveTestCode('''
+String? f(String? s) => s..length;
+''');
+ await assertHasFix('''
+String? f(String? s) => s!..length;
+''');
+ }
+
+ Future<void> test_propertyAccess_cascadeAfterNullProperty() async {
+ await resolveTestCode('''
+String? f(String? s) => s..hashCode..length;
+''');
+ await assertHasFix('''
+String? f(String? s) => s!..hashCode..length;
+''');
+ }
+
Future<void> test_spreadList() async {
await resolveTestCode('''
void f (List<String>? args) {
diff --git a/pkg/analysis_server/test/src/services/correction/fix/bulk/bulk_fix_processor_test.dart b/pkg/analysis_server/test/src/services/correction/fix/bulk/bulk_fix_processor_test.dart
index 8ac6ee0..2e36f14 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/bulk/bulk_fix_processor_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/bulk/bulk_fix_processor_test.dart
@@ -11,6 +11,7 @@
void main() {
defineReflectiveSuite(() {
defineReflectiveTests(ChangeMapTest);
+ defineReflectiveTests(NoFixTest);
});
}
@@ -36,3 +37,25 @@
expect(errors[LintNames.unnecessary_new], 2);
}
}
+
+@reflectiveTest
+class NoFixTest extends BulkFixProcessorTest {
+ /// See: https://github.com/dart-lang/sdk/issues/45177
+ Future<void> test_noFix() async {
+ createAnalysisOptionsFile(experiments: experiments, lints: [
+ 'avoid_catching_errors', // NOTE: not in lintProducerMap
+ ]);
+
+ await resolveTestCode('''
+void bad() {
+ try {
+ } on Error catch (e) {
+ print(e);
+ }
+}
+''');
+
+ var processor = await computeFixes();
+ expect(processor.fixDetails, isEmpty);
+ }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_to_generic_function_syntax_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_to_generic_function_syntax_test.dart
index de45575..6d1ed6b 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/convert_to_generic_function_syntax_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_to_generic_function_syntax_test.dart
@@ -69,7 +69,8 @@
}
@reflectiveTest
-class UseFunctionTypeSyntaxForParametersTest extends FixProcessorLintTest {
+class UseFunctionTypeSyntaxForParametersTest extends FixProcessorLintTest
+ with WithNullSafetyLintMixin {
@override
FixKind get kind => DartFixKind.CONVERT_TO_GENERIC_FUNCTION_SYNTAX;
@@ -83,6 +84,24 @@
await assertNoFix();
}
+ Future<void> test_functionTypedParameter_nullable() async {
+ await resolveTestCode('''
+g(List<String> f()?) {}
+''');
+ await assertHasFix('''
+g(List<String> Function()? f) {}
+''');
+ }
+
+ Future<void> test_functionTypedParameter_requiredNamed() async {
+ await resolveTestCode('''
+g({required List<Object?> f()}) {}
+''');
+ await assertHasFix('''
+g({required List<Object?> Function() f}) {}
+''');
+ }
+
Future<void> test_functionTypedParameter_returnType() async {
await resolveTestCode('''
g(String f(int x)) {}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_unnecessary_parentheses_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_unnecessary_parentheses_test.dart
index c8c9629..166007e 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_unnecessary_parentheses_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_unnecessary_parentheses_test.dart
@@ -7,15 +7,40 @@
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
+import 'bulk/bulk_fix_processor.dart';
import 'fix_processor.dart';
void main() {
defineReflectiveSuite(() {
+ defineReflectiveTests(RemoveUnnecessaryParenthesesBulkTest);
defineReflectiveTests(RemoveUnnecessaryParenthesesTest);
});
}
@reflectiveTest
+class RemoveUnnecessaryParenthesesBulkTest extends BulkFixProcessorTest {
+ @override
+ String get lintCode => LintNames.unnecessary_parenthesis;
+
+ Future<void> test_singleFile() async {
+ await resolveTestCode('''
+void f() {
+ (1);
+ (22);
+ (333);
+}
+''');
+ await assertHasFix('''
+void f() {
+ 1;
+ 22;
+ 333;
+}
+''');
+ }
+}
+
+@reflectiveTest
class RemoveUnnecessaryParenthesesTest extends FixProcessorLintTest {
@override
FixKind get kind => DartFixKind.REMOVE_UNNECESSARY_PARENTHESES;
@@ -23,25 +48,6 @@
@override
String get lintCode => LintNames.unnecessary_parenthesis;
- @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/45026')
- Future<void> test_all() async {
- await resolveTestCode('''
-void f() {
- (1);
- (22);
- (333);
-}
-''');
- var lintCode = await lintCodeByName(this.lintCode);
- await assertHasFixAllFix(lintCode, '''
-void f() {
- 1;
- 22;
- 333;
-}
-''');
- }
-
Future<void> test_double_atInner() async {
await resolveTestCode('''
void f() {
@@ -63,7 +69,9 @@
void f() {
(42);
}
-''', errorFilter: (e) => e.offset == testCode.indexOf('((42'));
+''',
+ errorFilter: (e) => e.offset == testCode.indexOf('((42'),
+ allowFixAllFixes: true);
}
Future<void> test_single() async {
diff --git a/pkg/analysis_server/test/src/services/correction/fix/replace_with_interpolation_test.dart b/pkg/analysis_server/test/src/services/correction/fix/replace_with_interpolation_test.dart
index 0a630e7..0a2539b 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/replace_with_interpolation_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/replace_with_interpolation_test.dart
@@ -124,14 +124,6 @@
''');
}
- Future<void> test_stringLiteral_variable_raw_single_notMulti() async {
- await resolveTestCode('''
-var b = 'b';
-var c = r'a' + b;
-''');
- await assertNoFix();
- }
-
Future<void> test_stringLiteral_variable_withEscapes() async {
await resolveTestCode(r'''
var b = 'b';
diff --git a/pkg/analyzer/lib/src/dart/analysis/analysis_context_collection.dart b/pkg/analyzer/lib/src/dart/analysis/analysis_context_collection.dart
index 03e4627..d610cce 100644
--- a/pkg/analyzer/lib/src/dart/analysis/analysis_context_collection.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/analysis_context_collection.dart
@@ -32,6 +32,8 @@
bool enableIndex = false,
required List<String> includedPaths,
List<String>? excludedPaths,
+ String? optionsFile,
+ String? packagesFile,
PerformanceLog? performanceLog,
ResourceProvider? resourceProvider,
bool retainDataForTesting = false,
@@ -50,6 +52,8 @@
var roots = contextLocator.locateRoots(
includedPaths: includedPaths,
excludedPaths: excludedPaths,
+ optionsFile: optionsFile,
+ packagesFile: packagesFile,
);
var fileContentOverlay = FileContentOverlay();
for (var root in roots) {
diff --git a/pkg/analyzer/lib/src/dart/analysis/context_builder.dart b/pkg/analyzer/lib/src/dart/analysis/context_builder.dart
index 7ec4bfb..4fcd8c8 100644
--- a/pkg/analyzer/lib/src/dart/analysis/context_builder.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/context_builder.dart
@@ -77,6 +77,7 @@
if (librarySummaryPaths != null) {
options.librarySummaryPaths = librarySummaryPaths;
}
+ options.defaultAnalysisOptionsFilePath = contextRoot.optionsFile?.path;
options.defaultPackageFilePath = contextRoot.packagesFile?.path;
old.ContextBuilder builder = old.ContextBuilder(
diff --git a/pkg/analyzer/lib/src/dart/analysis/context_locator.dart b/pkg/analyzer/lib/src/dart/analysis/context_locator.dart
index 6ad20a4..6612823 100644
--- a/pkg/analyzer/lib/src/dart/analysis/context_locator.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/context_locator.dart
@@ -17,6 +17,7 @@
import 'package:analyzer/src/task/options.dart';
import 'package:analyzer/src/util/file_paths.dart' as file_paths;
import 'package:analyzer/src/util/yaml.dart';
+import 'package:analyzer/src/workspace/basic.dart';
import 'package:analyzer/src/workspace/workspace.dart';
import 'package:glob/glob.dart';
import 'package:path/path.dart';
@@ -95,6 +96,7 @@
folder,
defaultOptionsFile: defaultOptionsFile,
defaultPackagesFile: defaultPackagesFile,
+ defaultRootFolder: () => folder,
);
ContextRootImpl? root;
@@ -105,15 +107,14 @@
}
}
- if (root == null) {
- var rootFolder = _lowest2(location.rootFolder, folder)!;
- root = _createContextRoot(
- roots,
- rootFolder: rootFolder,
- optionsFile: location.optionsFile,
- packagesFile: location.packagesFile,
- );
- }
+ root ??= _createContextRoot(
+ roots,
+ rootFolder: folder,
+ workspace: location.workspace,
+ optionsFile: location.optionsFile,
+ packagesFile: location.packagesFile,
+ );
+
if (!root.isAnalyzed(folder.path)) {
root.included.add(folder);
}
@@ -134,13 +135,15 @@
parent,
defaultOptionsFile: defaultOptionsFile,
defaultPackagesFile: defaultPackagesFile,
+ defaultRootFolder: () => _fileSystemRoot(parent),
);
- var rootFolder = location.rootFolder ?? _fileSystemRoot(parent);
+ var rootFolder = location.rootFolder;
var root = rootMap.putIfAbsent(rootFolder, () {
return _createContextRoot(
roots,
rootFolder: rootFolder,
+ workspace: location.workspace,
optionsFile: location.optionsFile,
packagesFile: location.packagesFile,
);
@@ -173,6 +176,7 @@
Folder parent, {
required File? defaultOptionsFile,
required File? defaultPackagesFile,
+ required Folder Function() defaultRootFolder,
}) {
File? optionsFile;
Folder? optionsFolderToChooseRoot;
@@ -198,8 +202,24 @@
packagesFolderToChooseRoot,
);
+ var workspace = _createWorkspace(parent, packagesFile);
+ if (workspace is! BasicWorkspace) {
+ rootFolder = _lowest2(
+ rootFolder,
+ resourceProvider.getFolder(workspace.root),
+ );
+ }
+
+ if (rootFolder == null) {
+ rootFolder = defaultRootFolder();
+ if (workspace is BasicWorkspace) {
+ workspace = _createWorkspace(rootFolder, packagesFile);
+ }
+ }
+
return _RootLocation(
rootFolder: rootFolder,
+ workspace: workspace,
optionsFile: optionsFile,
packagesFile: packagesFile,
);
@@ -208,10 +228,10 @@
ContextRootImpl _createContextRoot(
List<ContextRootImpl> roots, {
required Folder rootFolder,
+ required Workspace workspace,
required File? optionsFile,
required File? packagesFile,
}) {
- var workspace = _createWorkspace(rootFolder, packagesFile);
var root = ContextRootImpl(resourceProvider, rootFolder, workspace);
root.packagesFile = packagesFile;
root.optionsFile = optionsFile;
@@ -385,11 +405,11 @@
List<Glob> patterns = [];
File? optionsFile = root.optionsFile;
if (optionsFile != null) {
- var doc = AnalysisOptionsProvider(
- root.workspace.createSourceFactory(null, null))
- .getOptionsFromFile(optionsFile);
-
try {
+ var doc = AnalysisOptionsProvider(
+ root.workspace.createSourceFactory(null, null))
+ .getOptionsFromFile(optionsFile);
+
if (doc is YamlMap) {
var analyzerOptions = getValue(doc, AnalyzerOptions.analyzer);
if (analyzerOptions is YamlMap) {
@@ -462,14 +482,12 @@
List<String> paths, List<Folder> folders, List<File> files) {
for (String path in _uniqueSortedPaths(paths)) {
Resource resource = resourceProvider.getResource(path);
- if (resource.exists) {
- if (resource is Folder) {
- folders.add(resource);
- } else if (resource is File) {
- files.add(resource);
- } else {
- // Internal error: unhandled kind of resource.
- }
+ if (resource is Folder) {
+ folders.add(resource);
+ } else if (resource is File) {
+ files.add(resource);
+ } else {
+ // Internal error: unhandled kind of resource.
}
}
}
@@ -520,12 +538,14 @@
}
class _RootLocation {
- final Folder? rootFolder;
+ final Folder rootFolder;
+ final Workspace workspace;
final File? optionsFile;
final File? packagesFile;
_RootLocation({
required this.rootFolder,
+ required this.workspace,
required this.optionsFile,
required this.packagesFile,
});
diff --git a/pkg/analyzer/lib/src/dart/resolver/annotation_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/annotation_resolver.dart
index a02ad16..fbbd960 100644
--- a/pkg/analyzer/lib/src/dart/resolver/annotation_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/annotation_resolver.dart
@@ -32,6 +32,7 @@
if (element is ExecutableElement) {
InferenceContext.setType(node.arguments, element.type);
}
+ node.typeArguments?.accept(_resolver);
node.arguments?.accept(_resolver);
var elementAnnotationImpl =
diff --git a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
index 40726d1..658adba 100644
--- a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
@@ -355,9 +355,6 @@
TypeSystemTypeOperations(this.typeSystem);
@override
- DartType get topType => typeSystem.objectQuestion;
-
- @override
TypeClassification classifyType(DartType type) {
if (isSubtypeOf(type, typeSystem.typeProvider.objectType)) {
return TypeClassification.nonNullable;
diff --git a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
index e05d2ad..816af4c 100644
--- a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
@@ -752,8 +752,8 @@
node.methodName,
);
}
- _resolver.flowAnalysis?.flow
- ?.propertyGet(functionExpression, target, node.methodName.name);
+ _resolver.flowAnalysis?.flow?.propertyGet(
+ functionExpression, target, node.methodName.name, getterReturnType);
functionExpression.staticType = targetType;
}
diff --git a/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart
index 5d0133f..23fcd9b 100644
--- a/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart
@@ -202,8 +202,10 @@
if (hasRead) {
var readLookup = _resolver.lexicalLookup(node: node, setter: false);
readElementRequested = readLookup.requested;
- if (readElementRequested is PropertyAccessorElement) {
- _resolver.flowAnalysis?.flow?.thisOrSuperPropertyGet(node, node.name);
+ if (readElementRequested is PropertyAccessorElement &&
+ !readElementRequested.isStatic) {
+ _resolver.flowAnalysis?.flow?.thisOrSuperPropertyGet(
+ node, node.name, readElementRequested.returnType);
}
_resolver.checkReadOfNotAssignedLocalVariable(node, readElementRequested);
}
@@ -372,7 +374,8 @@
nameErrorEntity: propertyName,
);
- _resolver.flowAnalysis?.flow?.propertyGet(node, target, propertyName.name);
+ _resolver.flowAnalysis?.flow?.propertyGet(node, target, propertyName.name,
+ result.getter?.returnType ?? _typeSystem.typeProvider.dynamicType);
if (hasRead && result.needsGetterError) {
_errorReporter.reportErrorForNode(
@@ -621,8 +624,6 @@
if (targetType is InterfaceTypeImpl) {
if (hasRead) {
- _resolver.flowAnalysis?.flow
- ?.propertyGet(node, target, propertyName.name);
var name = Name(_definingLibrary.source.uri, propertyName.name);
readElement = _resolver.inheritance
.getMember2(targetType.element, name, forSuper: true);
@@ -649,6 +650,11 @@
);
}
}
+ _resolver.flowAnalysis?.flow?.propertyGet(
+ node,
+ target,
+ propertyName.name,
+ readElement?.returnType ?? _typeSystem.typeProvider.dynamicType);
}
if (hasWrite) {
diff --git a/pkg/analyzer/lib/src/dart/resolver/type_property_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/type_property_resolver.dart
index 99b1277..b189618 100644
--- a/pkg/analyzer/lib/src/dart/resolver/type_property_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/type_property_resolver.dart
@@ -115,8 +115,20 @@
}
}
- List<DiagnosticMessage> messages =
- _resolver.computeWhyNotPromotedMessages(receiver, nameErrorEntity);
+ List<DiagnosticMessage> messages = [];
+ var flow = _resolver.flowAnalysis?.flow;
+ if (flow != null) {
+ if (receiver != null) {
+ messages = _resolver.computeWhyNotPromotedMessages(
+ receiver, nameErrorEntity, flow.whyNotPromoted(receiver));
+ } else {
+ var thisType = _resolver.thisType;
+ if (thisType != null) {
+ messages = _resolver.computeWhyNotPromotedMessages(receiver,
+ nameErrorEntity, flow.whyNotPromotedImplicitThis(thisType));
+ }
+ }
+ }
_resolver.nullableDereferenceVerifier.report(
receiverErrorNode, receiverType,
errorCode: errorCode, arguments: [name], messages: messages);
diff --git a/pkg/analyzer/lib/src/error/nullable_dereference_verifier.dart b/pkg/analyzer/lib/src/error/nullable_dereference_verifier.dart
index 6044fab..87f07b8 100644
--- a/pkg/analyzer/lib/src/error/nullable_dereference_verifier.dart
+++ b/pkg/analyzer/lib/src/error/nullable_dereference_verifier.dart
@@ -67,7 +67,8 @@
List<DiagnosticMessage>? messages;
if (errorNode is Expression) {
- messages = _resolver.computeWhyNotPromotedMessages(errorNode, errorNode);
+ messages = _resolver.computeWhyNotPromotedMessages(errorNode, errorNode,
+ _resolver.flowAnalysis?.flow?.whyNotPromoted(errorNode));
}
report(errorNode, receiverType, errorCode: errorCode, messages: messages);
return true;
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index fcdafed..581f6e1 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -514,9 +514,10 @@
/// Computes the appropriate set of context messages to report along with an
/// error that may have occurred because [receiver] was not type promoted.
List<DiagnosticMessage> computeWhyNotPromotedMessages(
- Expression? receiver, SyntacticEntity errorEntity) {
+ Expression? receiver,
+ SyntacticEntity errorEntity,
+ Map<DartType, NonPromotionReason>? whyNotPromoted) {
List<DiagnosticMessage> messages = [];
- var whyNotPromoted = flowAnalysis?.flow?.whyNotPromoted(receiver);
if (whyNotPromoted != null) {
for (var entry in whyNotPromoted.entries) {
var whyNotPromotedVisitor = _WhyNotPromotedVisitor(
@@ -526,10 +527,17 @@
if (message != null) {
if (flowAnalysis!.dataForTesting != null) {
var nonPromotionReasonText = entry.value.shortName;
+ var args = <String>[];
if (whyNotPromotedVisitor.propertyReference != null) {
var id =
computeMemberId(whyNotPromotedVisitor.propertyReference!);
- nonPromotionReasonText += '($id)';
+ args.add('target: $id');
+ }
+ if (whyNotPromotedVisitor.propertyType != null) {
+ args.add('type: ${whyNotPromotedVisitor.propertyType}');
+ }
+ if (args.isNotEmpty) {
+ nonPromotionReasonText += '(${args.join(', ')})';
}
flowAnalysis!.dataForTesting!.nonPromotionReasons[errorEntity] =
nonPromotionReasonText;
@@ -3338,7 +3346,7 @@
class _WhyNotPromotedVisitor
implements
NonPromotionReasonVisitor<DiagnosticMessage?, AstNode, Expression,
- PromotableElement> {
+ PromotableElement, DartType> {
final Source source;
final Expression? _receiver;
@@ -3349,6 +3357,8 @@
PropertyAccessorElement? propertyReference;
+ DartType? propertyType;
+
_WhyNotPromotedVisitor(
this.source, this._receiver, this._errorEntity, this._dataForTesting);
@@ -3394,7 +3404,8 @@
}
@override
- DiagnosticMessage? visitPropertyNotPromoted(PropertyNotPromoted reason) {
+ DiagnosticMessage? visitPropertyNotPromoted(
+ PropertyNotPromoted<DartType> reason) {
var receiver = _receiver;
Element? receiverElement;
if (receiver is SimpleIdentifier) {
@@ -3408,6 +3419,7 @@
}
if (receiverElement is PropertyAccessorElement) {
propertyReference = receiverElement;
+ propertyType = reason.staticType;
return _contextMessageForProperty(receiverElement, reason.propertyName);
} else {
assert(receiverElement == null,
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index 96b116d..9ca8628 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -285,8 +285,8 @@
@override
void visitSuperExpression(SuperExpression node) {
- _resolver.flowAnalysis?.flow?.thisOrSuper(node);
var thisType = _resolver.thisType;
+ _resolver.flowAnalysis?.flow?.thisOrSuper(node, thisType ?? _dynamicType);
if (thisType == null ||
node.thisOrAncestorOfType<ExtensionDeclaration>() != null) {
// TODO(brianwilkerson) Report this error if it hasn't already been
@@ -306,8 +306,8 @@
/// interface of the immediately enclosing class.</blockquote>
@override
void visitThisExpression(ThisExpression node) {
- _resolver.flowAnalysis?.flow?.thisOrSuper(node);
var thisType = _resolver.thisType;
+ _resolver.flowAnalysis?.flow?.thisOrSuper(node, thisType ?? _dynamicType);
if (thisType == null) {
// TODO(brianwilkerson) Report this error if it hasn't already been
// reported.
diff --git a/pkg/analyzer/lib/src/test_utilities/resource_provider_mixin.dart b/pkg/analyzer/lib/src/test_utilities/resource_provider_mixin.dart
index 50e73cb..c082771 100644
--- a/pkg/analyzer/lib/src/test_utilities/resource_provider_mixin.dart
+++ b/pkg/analyzer/lib/src/test_utilities/resource_provider_mixin.dart
@@ -55,6 +55,11 @@
return newFile(path, content: content);
}
+ File newBazelBuildFile(String directoryPath, String content) {
+ String path = join(directoryPath, file_paths.bazelBuild);
+ return newFile(path, content: content);
+ }
+
File newDotPackagesFile(String directoryPath, {String content = ''}) {
String path = join(directoryPath, file_paths.dotPackages);
return newFile(path, content: content);
diff --git a/pkg/analyzer/lib/src/util/file_paths.dart b/pkg/analyzer/lib/src/util/file_paths.dart
index 6f8ade1..6420a36 100644
--- a/pkg/analyzer/lib/src/util/file_paths.dart
+++ b/pkg/analyzer/lib/src/util/file_paths.dart
@@ -31,6 +31,14 @@
/// File name of pubspec files.
const String pubspecYaml = 'pubspec.yaml';
+/// Converts the given [path] into absolute and normalized.
+String absoluteNormalized(p.Context pathContext, String path) {
+ path = path.trim();
+ path = pathContext.absolute(path);
+ path = pathContext.normalize(path);
+ return path;
+}
+
/// Return `true` if [path] is an analysis options file.
bool isAnalysisOptionsYaml(p.Context pathContext, String path) {
return pathContext.basename(path) == analysisOptionsYaml;
diff --git a/pkg/analyzer/test/file_system/file_system_test_support.dart b/pkg/analyzer/test/file_system/file_system_test_support.dart
index 87c34b8..4004239 100644
--- a/pkg/analyzer/test/file_system/file_system_test_support.dart
+++ b/pkg/analyzer/test/file_system/file_system_test_support.dart
@@ -23,6 +23,10 @@
/// A path to a folder within the [tempPath] that can be used by tests.
String get defaultFolderPath;
+ /// Return `true` if the file system has support for symbolic links.
+ /// Windows until recently (Windows 10, 2016) did not have it.
+ bool get hasSymbolicLinkSupport;
+
/// Return the resource provider to be used by the tests.
ResourceProvider get provider;
@@ -139,6 +143,8 @@
}
test_exists_links_existing() {
+ if (!hasSymbolicLinkSupport) return;
+
var a_path = join(tempPath, 'a.dart');
var b_path = join(tempPath, 'b.dart');
@@ -153,6 +159,8 @@
}
test_exists_links_notExisting() {
+ if (!hasSymbolicLinkSupport) return;
+
var a_path = join(tempPath, 'a.dart');
var b_path = join(tempPath, 'b.dart');
@@ -306,6 +314,8 @@
test_renameSync_notExisting();
test_resolveSymbolicLinksSync_links_existing() {
+ if (!hasSymbolicLinkSupport) return;
+
var a_path = join(tempPath, 'aaa', 'a.dart');
var b_path = join(tempPath, 'bbb', 'b.dart');
@@ -317,6 +327,8 @@
}
test_resolveSymbolicLinksSync_links_existing2() {
+ if (!hasSymbolicLinkSupport) return;
+
var a = join(tempPath, 'aaa', 'a.dart');
var b = join(tempPath, 'bbb', 'b.dart');
var c = join(tempPath, 'ccc', 'c.dart');
@@ -330,6 +342,8 @@
}
test_resolveSymbolicLinksSync_links_notExisting() {
+ if (!hasSymbolicLinkSupport) return;
+
var a = join(tempPath, 'a.dart');
var b = join(tempPath, 'b.dart');
@@ -527,6 +541,8 @@
}
test_exists_links_existing() {
+ if (!hasSymbolicLinkSupport) return;
+
var foo_path = join(tempPath, 'foo');
var bar_path = join(tempPath, 'bar');
@@ -541,6 +557,8 @@
}
test_exists_links_notExisting() {
+ if (!hasSymbolicLinkSupport) return;
+
var foo_path = join(tempPath, 'foo');
var bar_path = join(tempPath, 'bar');
@@ -664,6 +682,8 @@
}
test_getChildren_hasLink_file() {
+ if (!hasSymbolicLinkSupport) return;
+
var a_path = join(tempPath, 'a.dart');
var b_path = join(tempPath, 'b.dart');
@@ -682,6 +702,8 @@
}
test_getChildren_hasLink_folder() {
+ if (!hasSymbolicLinkSupport) return;
+
var foo_path = join(tempPath, 'foo');
var bar_path = join(tempPath, 'bar');
@@ -700,6 +722,8 @@
}
test_getChildren_isLink() {
+ if (!hasSymbolicLinkSupport) return;
+
var foo_path = join(tempPath, 'foo');
var bar_path = join(tempPath, 'bar');
var foo_a_path = join(foo_path, 'a.dart');
@@ -778,6 +802,8 @@
}
test_resolveSymbolicLinksSync_links_existing() {
+ if (!hasSymbolicLinkSupport) return;
+
var foo = join(tempPath, 'foo');
var bar = join(tempPath, 'bar');
@@ -789,6 +815,8 @@
}
test_resolveSymbolicLinksSync_links_notExisting() {
+ if (!hasSymbolicLinkSupport) return;
+
var foo = join(tempPath, 'foo');
var bar = join(tempPath, 'bar');
diff --git a/pkg/analyzer/test/file_system/memory_file_system_test.dart b/pkg/analyzer/test/file_system/memory_file_system_test.dart
index c4a447c..34dc801 100644
--- a/pkg/analyzer/test/file_system/memory_file_system_test.dart
+++ b/pkg/analyzer/test/file_system/memory_file_system_test.dart
@@ -48,6 +48,9 @@
@override
String get defaultFileContent => 'a';
+ @override
+ bool get hasSymbolicLinkSupport => true;
+
/// Return the resource provider to be used by the tests.
@override
MemoryResourceProvider get provider => _provider ??= createProvider();
diff --git a/pkg/analyzer/test/file_system/physical_file_system_test.dart b/pkg/analyzer/test/file_system/physical_file_system_test.dart
index 9f871dd..3d33576 100644
--- a/pkg/analyzer/test/file_system/physical_file_system_test.dart
+++ b/pkg/analyzer/test/file_system/physical_file_system_test.dart
@@ -48,6 +48,9 @@
@override
String get defaultFileContent => 'a';
+ @override
+ bool get hasSymbolicLinkSupport => !io.Platform.isWindows;
+
/// Return the resource provider to be used by the tests.
@override
PhysicalResourceProvider get provider => _provider ??= createProvider();
diff --git a/pkg/analyzer/test/src/dart/analysis/context_locator_test.dart b/pkg/analyzer/test/src/dart/analysis/context_locator_test.dart
index 2eac307..5869b63 100644
--- a/pkg/analyzer/test/src/dart/analysis/context_locator_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/context_locator_test.dart
@@ -7,6 +7,10 @@
import 'package:analyzer/src/dart/analysis/context_locator.dart';
import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
import 'package:analyzer/src/util/file_paths.dart' as file_paths;
+import 'package:analyzer/src/workspace/basic.dart';
+import 'package:analyzer/src/workspace/bazel.dart';
+import 'package:analyzer/src/workspace/pub.dart';
+import 'package:analyzer/src/workspace/workspace.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -464,10 +468,106 @@
expect(root.excludedPaths, isEmpty);
expect(root.optionsFile, isNull);
expect(root.packagesFile, isNull);
+ _assertBasicWorkspace(root.workspace, root.root.path);
_assertAnalyzedFiles2(root, [testFile1, testFile2]);
}
+ void test_locateRoots_multiple_files_bazel_differentWorkspaces() {
+ var workspacePath1 = '/home/workspace1';
+ var workspacePath2 = '/home/workspace2';
+ var pkgPath1 = '$workspacePath1/pkg1';
+ var pkgPath2 = '$workspacePath2/pkg2';
+
+ newFile('$workspacePath1/WORKSPACE');
+ newFile('$workspacePath2/WORKSPACE');
+ newBazelBuildFile(pkgPath1, '');
+ newBazelBuildFile(pkgPath2, '');
+
+ var file1 = newFile('$pkgPath1/lib/file1.dart');
+ var file2 = newFile('$pkgPath2/lib/file2.dart');
+
+ var roots = contextLocator.locateRoots(
+ includedPaths: [file1.path, file2.path],
+ );
+ expect(roots, hasLength(2));
+
+ var root1 = findRoot(roots, getFolder(workspacePath1));
+ expect(root1.includedPaths, unorderedEquals([file1.path]));
+ expect(root1.excludedPaths, isEmpty);
+ expect(root1.optionsFile, isNull);
+ expect(root1.packagesFile, isNull);
+ _assertBazelWorkspace(root1.workspace, workspacePath1);
+ _assertAnalyzedFiles2(root1, [file1]);
+
+ var root2 = findRoot(roots, getFolder(workspacePath2));
+ expect(root2.includedPaths, unorderedEquals([file2.path]));
+ expect(root2.excludedPaths, isEmpty);
+ expect(root2.optionsFile, isNull);
+ expect(root2.packagesFile, isNull);
+ _assertBazelWorkspace(root2.workspace, workspacePath2);
+ _assertAnalyzedFiles2(root2, [file2]);
+ }
+
+ void test_locateRoots_multiple_files_bazel_sameWorkspace_differentPackages() {
+ var workspacePath = '/home/workspace';
+ var fooPath = '$workspacePath/foo';
+ var barPath = '$workspacePath/bar';
+
+ newFile('$workspacePath/WORKSPACE');
+ newBazelBuildFile(fooPath, '');
+ newBazelBuildFile(barPath, '');
+
+ var fooFile = newFile('$fooPath/lib/foo.dart');
+ var barFile = newFile('$barPath/lib/bar.dart');
+
+ var roots = contextLocator.locateRoots(
+ includedPaths: [fooFile.path, barFile.path],
+ );
+ expect(roots, hasLength(1));
+
+ var root = findRoot(roots, getFolder(workspacePath));
+ expect(root.includedPaths, unorderedEquals([fooFile.path, barFile.path]));
+ expect(root.excludedPaths, isEmpty);
+ expect(root.optionsFile, isNull);
+ expect(root.packagesFile, isNull);
+ _assertBazelWorkspace(root.workspace, workspacePath);
+ _assertAnalyzedFiles2(root, [fooFile, barFile]);
+ }
+
+ void test_locateRoots_multiple_files_differentWorkspaces_pub() {
+ var rootPath = '/home';
+ var fooPath = '$rootPath/foo';
+ var barPath = '$rootPath/bar';
+
+ newPubspecYamlFile(fooPath, '');
+ newPubspecYamlFile(barPath, '');
+
+ var fooFile = newFile('$fooPath/lib/foo.dart');
+ var barFile = newFile('$barPath/lib/bar.dart');
+
+ var roots = contextLocator.locateRoots(
+ includedPaths: [fooFile.path, barFile.path],
+ );
+ expect(roots, hasLength(2));
+
+ var fooRoot = findRoot(roots, getFolder(fooPath));
+ expect(fooRoot.includedPaths, unorderedEquals([fooFile.path]));
+ expect(fooRoot.excludedPaths, isEmpty);
+ expect(fooRoot.optionsFile, isNull);
+ expect(fooRoot.packagesFile, isNull);
+ _assertPubWorkspace(fooRoot.workspace, fooPath);
+ _assertAnalyzedFiles2(fooRoot, [fooFile]);
+
+ var barRoot = findRoot(roots, getFolder(barPath));
+ expect(barRoot.includedPaths, unorderedEquals([barFile.path]));
+ expect(barRoot.excludedPaths, isEmpty);
+ expect(barRoot.optionsFile, isNull);
+ expect(barRoot.packagesFile, isNull);
+ _assertPubWorkspace(barRoot.workspace, barPath);
+ _assertAnalyzedFiles2(barRoot, [barFile]);
+ }
+
void test_locateRoots_multiple_files_sameOptions_differentPackages() {
var fooPackagesFile = newPackageConfigJsonFile('/home/foo');
var barPackagesFile = newPackageConfigJsonFile('/home/bar');
@@ -830,6 +930,33 @@
expect(outerRoot.packagesFile, outerPackagesFile);
}
+ void test_locateRoots_options_hasError() {
+ Folder rootFolder = newFolder('/test/root');
+ File optionsFile = newAnalysisOptionsYamlFile('/test/root', content: '''
+analyzer:
+ exclude:
+ - **.g.dart
+analyzer:
+''');
+ File packagesFile = newDotPackagesFile('/test/root');
+
+ List<ContextRoot> roots =
+ contextLocator.locateRoots(includedPaths: [rootFolder.path]);
+ expect(roots, hasLength(1));
+
+ ContextRoot root = findRoot(roots, rootFolder);
+ expect(root.includedPaths, unorderedEquals([rootFolder.path]));
+ expect(root.excludedPaths, isEmpty);
+ expect(root.optionsFile, optionsFile);
+ expect(root.packagesFile, packagesFile);
+
+ // There is an error in the analysis_options.yaml, so it is ignored.
+ _assertAnalyzed(root, [
+ '/test/root//lib/a.dart',
+ '/test/root//lib/a.g.dart',
+ ]);
+ }
+
void test_locateRoots_options_withExclude_someFiles() {
Folder rootFolder = newFolder('/test/root');
File optionsFile = newAnalysisOptionsYamlFile('/test/root', content: '''
@@ -1127,6 +1254,22 @@
expect(package1Root.packagesFile, packagesFile);
}
+ void test_locateRoots_single_file_notExisting() {
+ File optionsFile = newAnalysisOptionsYamlFile('/test');
+ File packagesFile = newDotPackagesFile('/test/root');
+ File testFile = getFile('/test/root/test.dart');
+
+ List<ContextRoot> roots =
+ contextLocator.locateRoots(includedPaths: [testFile.path]);
+ expect(roots, hasLength(1));
+
+ ContextRoot package1Root = findRoot(roots, testFile.parent2);
+ expect(package1Root.includedPaths, unorderedEquals([testFile.path]));
+ expect(package1Root.excludedPaths, isEmpty);
+ expect(package1Root.optionsFile, optionsFile);
+ expect(package1Root.packagesFile, packagesFile);
+ }
+
void _assertAnalyzed(ContextRoot root, List<String> posixPathList) {
for (var posixPath in posixPathList) {
var path = convertPath(posixPath);
@@ -1150,6 +1293,16 @@
_assertAnalyzedFiles(root, pathList);
}
+ void _assertBasicWorkspace(Workspace _workspace, String root) {
+ var workspace = _workspace as BasicWorkspace;
+ expect(workspace.root, root);
+ }
+
+ void _assertBazelWorkspace(Workspace _workspace, String root) {
+ var workspace = _workspace as BazelWorkspace;
+ expect(workspace.root, root);
+ }
+
void _assertNotAnalyzed(ContextRoot root, List<String> posixPathList) {
for (var posixPath in posixPathList) {
var path = convertPath(posixPath);
@@ -1157,6 +1310,11 @@
}
}
+ void _assertPubWorkspace(Workspace _workspace, String root) {
+ var workspace = _workspace as PubWorkspace;
+ expect(workspace.root, root);
+ }
+
File _newPackageConfigFile(String directoryPath) {
String path = join(
directoryPath,
diff --git a/pkg/analyzer/tool/diagnostics/diagnostics.md b/pkg/analyzer/tool/diagnostics/diagnostics.md
index 340a5a4..6778017 100644
--- a/pkg/analyzer/tool/diagnostics/diagnostics.md
+++ b/pkg/analyzer/tool/diagnostics/diagnostics.md
@@ -9755,7 +9755,7 @@
### type_argument_not_matching_bounds
-_'{0}' doesn't extend '{1}'._
+_'{0}' doesn't conform to the bound '{2}' of the type parameter '{1}'._
#### Description
diff --git a/pkg/analyzer_cli/lib/src/driver.dart b/pkg/analyzer_cli/lib/src/driver.dart
index a37c423..a98502e 100644
--- a/pkg/analyzer_cli/lib/src/driver.dart
+++ b/pkg/analyzer_cli/lib/src/driver.dart
@@ -5,36 +5,28 @@
import 'dart:io' as io;
import 'dart:isolate';
-import 'package:analyzer/dart/analysis/context_locator.dart' as api;
+import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/sdk/build_sdk_summary.dart';
import 'package:analyzer/error/error.dart';
import 'package:analyzer/error/listener.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/file_system/physical_file_system.dart';
-import 'package:analyzer/src/context/builder.dart';
-import 'package:analyzer/src/context/context_root.dart';
-import 'package:analyzer/src/context/packages.dart';
+import 'package:analyzer/src/dart/analysis/analysis_context_collection.dart';
import 'package:analyzer/src/dart/analysis/byte_store.dart';
import 'package:analyzer/src/dart/analysis/driver.dart';
-import 'package:analyzer/src/dart/analysis/driver_based_analysis_context.dart'
- as api;
+import 'package:analyzer/src/dart/analysis/driver_based_analysis_context.dart';
+import 'package:analyzer/src/dart/analysis/experiments.dart';
import 'package:analyzer/src/dart/analysis/file_state.dart';
-import 'package:analyzer/src/dart/analysis/performance_logger.dart';
import 'package:analyzer/src/dart/analysis/results.dart';
-import 'package:analyzer/src/dart/sdk/sdk.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/interner.dart';
import 'package:analyzer/src/generated/java_engine.dart';
-import 'package:analyzer/src/generated/sdk.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/lint/linter.dart';
import 'package:analyzer/src/lint/pub.dart';
import 'package:analyzer/src/manifest/manifest_validator.dart';
import 'package:analyzer/src/pubspec/pubspec_validator.dart';
-import 'package:analyzer/src/source/package_map_resolver.dart';
import 'package:analyzer/src/source/path_filter.dart';
-import 'package:analyzer/src/summary/package_bundle_reader.dart';
-import 'package:analyzer/src/summary/summary_sdk.dart' show SummaryBasedDartSdk;
import 'package:analyzer/src/task/options.dart';
import 'package:analyzer/src/util/file_paths.dart' as file_paths;
import 'package:analyzer/src/util/yaml.dart';
@@ -51,6 +43,7 @@
import 'package:linter/src/rules.dart' as linter;
import 'package:meta/meta.dart';
import 'package:path/path.dart' as path;
+import 'package:pub_semver/pub_semver.dart';
import 'package:yaml/yaml.dart';
/// Shared IO sink for standard error reporting.
@@ -71,6 +64,9 @@
@override
ContextCache contextCache;
+ _AnalysisContextProvider _analysisContextProvider;
+ DriverBasedAnalysisContext analysisContext;
+
/// The driver that was most recently created by a call to [_analyzeAll], or
/// `null` if [_analyzeAll] hasn't been called yet.
@visibleForTesting
@@ -79,13 +75,6 @@
/// The total number of source files loaded by an AnalysisContext.
int _analyzedFileCount = 0;
- /// If [analysisDriver] is not `null`, the [CommandLineOptions] that guided
- /// its creation.
- CommandLineOptions _previousOptions;
-
- /// SDK instance.
- DartSdk sdk;
-
/// The resource provider used to access the file system.
@override
final ResourceProvider resourceProvider = PhysicalResourceProvider.INSTANCE;
@@ -121,6 +110,8 @@
// Parse commandline options.
var options = CommandLineOptions.parse(resourceProvider, args);
+ _analysisContextProvider = _AnalysisContextProvider(resourceProvider);
+
// Do analysis.
if (options.buildMode) {
var severity = await _buildModeAnalyze(options, sendPort);
@@ -172,12 +163,8 @@
}
}
- Future<ErrorSeverity> _analyzeAll(CommandLineOptions options) async {
- return await _analyzeAllImpl(options);
- }
-
/// Perform analysis according to the given [options].
- Future<ErrorSeverity> _analyzeAllImpl(CommandLineOptions options) async {
+ Future<ErrorSeverity> _analyzeAll(CommandLineOptions options) async {
if (!options.machineFormat) {
var fileNames = options.sourceFiles.map((String file) {
file = path.normalize(file);
@@ -192,6 +179,8 @@
outSink.writeln("Analyzing ${fileNames.join(', ')}...");
}
+ _verifyAnalysisOptionsFileExists(options);
+
// These are used to do part file analysis across sources.
var dartFiles = <String>{};
var libraryFiles = <FileState>{};
@@ -228,16 +217,14 @@
allResult = allResult.max(ErrorSeverity.ERROR);
}
- for (var sourcePath in options.sourceFiles) {
- sourcePath = normalizePath(sourcePath);
+ var pathList = options.sourceFiles.map(normalizePath).toList();
+ _analysisContextProvider.setCommandLineOptions(options, pathList);
- // Create a context, or re-use the previous one.
- try {
- _createContextAndAnalyze(options, sourcePath);
- } on _DriverError catch (error) {
- outSink.writeln(error.msg);
- return ErrorSeverity.ERROR;
- }
+ for (var sourcePath in pathList) {
+ _analysisContextProvider.configureForPath(sourcePath);
+ analysisContext = _analysisContextProvider.analysisContext;
+ analysisDriver = _analysisContextProvider.analysisDriver;
+ pathFilter = _analysisContextProvider.pathFilter;
// Add all the files to be analyzed en masse to the context. Skip any
// files that were added earlier (whether explicitly or implicitly) to
@@ -417,65 +404,6 @@
}
}
- /// Decide on the appropriate method for resolving URIs based on the given
- /// [options] and [customUrlMappings] settings, and return a
- /// [SourceFactory] that has been configured accordingly.
- /// When [includeSdkResolver] is `false`, return a temporary [SourceFactory]
- /// for the purpose of resolved analysis options file `include:` directives.
- /// In this situation, [analysisOptions] is ignored and can be `null`.
- SourceFactory _chooseUriResolutionPolicy(
- CommandLineOptions options,
- Map<Folder, YamlMap> embedderMap,
- _PackageInfo packageInfo,
- SummaryDataStore summaryDataStore,
- bool includeSdkResolver,
- AnalysisOptions analysisOptions) {
- UriResolver packageUriResolver;
-
- if (packageInfo.packageMap != null) {
- packageUriResolver = PackageMapUriResolver(
- resourceProvider,
- packageInfo.packageMap,
- );
- }
-
- // Now, build our resolver list.
- var resolvers = <UriResolver>[];
-
- // 'dart:' URIs come first.
-
- // Setup embedding.
- if (includeSdkResolver) {
- var embedderSdk = EmbedderSdk(
- resourceProvider,
- embedderMap,
- languageVersion: sdk.languageVersion,
- );
- if (embedderSdk.libraryMap.size() == 0) {
- // The embedder uri resolver has no mappings. Use the default Dart SDK
- // uri resolver.
- resolvers.add(DartUriResolver(sdk));
- } else {
- // The embedder uri resolver has mappings, use it instead of the default
- // Dart SDK uri resolver.
- resolvers.add(DartUriResolver(embedderSdk));
- }
- }
-
- // Then package URIs from summaries.
- resolvers.add(InSummaryUriResolver(resourceProvider, summaryDataStore));
-
- // Then package URIs.
- if (packageUriResolver != null) {
- resolvers.add(packageUriResolver);
- }
-
- // Finally files.
- resolvers.add(ResourceUriResolver(resourceProvider));
-
- return SourceFactory(resolvers);
- }
-
/// Collect all analyzable files at [filePath], recursively if it's a
/// directory, ignoring links.
Iterable<io.File> _collectFiles(String filePath, AnalysisOptions options) {
@@ -503,130 +431,6 @@
return files;
}
- /// Create an analysis driver that is prepared to analyze sources according
- /// to the given [options], and store it in [analysisDriver].
- void _createContextAndAnalyze(CommandLineOptions options, String source) {
- // If not the same command-line options, clear cached information.
- if (!_equalCommandLineOptions(_previousOptions, options)) {
- _previousOptions = options;
- contextCache = ContextCache(resourceProvider, options, verbosePrint);
- analysisDriver = null;
- }
-
- var analysisOptions =
- createAnalysisOptionsForCommandLineOptions(options, source);
-
- // Store the [PathFilter] for this context to properly exclude files
- pathFilter = PathFilter(getContextInfo(options, source).analysisRoot,
- analysisOptions.excludePatterns);
-
- // If we have the analysis driver, and the new analysis options are the
- // same, we can reuse this analysis driver.
- if (analysisDriver != null &&
- AnalysisOptions.signaturesEqual(
- analysisDriver.analysisOptions.signature,
- analysisOptions.signature)) {
- return;
- }
-
- // Set up logging.
- if (options.log) {
- AnalysisEngine.instance.instrumentationService = StdInstrumentation();
- }
-
- // Save stats from previous context before clobbering it.
- if (analysisDriver != null) {
- _analyzedFileCount += analysisDriver.knownFiles.length;
- }
-
- // Find package info.
- var packageInfo = _findPackages(options);
-
- // Process embedders.
- var embedderMap = <Folder, YamlMap>{};
- if (packageInfo.packageMap != null) {
- var libFolder = packageInfo.packageMap['sky_engine']?.first;
- if (libFolder != null) {
- var locator = EmbedderYamlLocator.forLibFolder(libFolder);
- embedderMap = locator.embedderYamls;
- }
- }
-
- // No summaries in the presence of embedders.
- var useSummaries = embedderMap.isEmpty;
-
- if (!useSummaries && options.buildSummaryInputs.isNotEmpty) {
- throw _DriverError('Summaries are not yet supported when using Flutter.');
- }
-
- // Read any input summaries.
- var summaryDataStore = SummaryDataStore(
- useSummaries ? options.buildSummaryInputs : <String>[]);
-
- // Once options and embedders are processed, setup the SDK.
- _setupSdk(options, analysisOptions);
-
- // Choose a package resolution policy and a diet parsing policy based on
- // the command-line options.
- var sourceFactory = _chooseUriResolutionPolicy(options, embedderMap,
- packageInfo, summaryDataStore, true, analysisOptions);
-
- var log = PerformanceLog(null);
- var scheduler = AnalysisDriverScheduler(log);
-
- analysisDriver = AnalysisDriver(
- scheduler,
- log,
- resourceProvider,
- analysisDriverMemoryByteStore,
- FileContentOverlay(),
- ContextRoot(source, [], pathContext: resourceProvider.pathContext),
- sourceFactory,
- analysisOptions,
- packages: packageInfo.packages);
- analysisDriver.results.listen((_) {});
- analysisDriver.exceptions.listen((_) {});
- _setAnalysisDriverAnalysisContext(source);
- scheduler.start();
- }
-
- _PackageInfo _findPackages(CommandLineOptions options) {
- Packages packages;
- Map<String, List<Folder>> packageMap;
-
- if (options.packageConfigPath != null) {
- var path = normalizePath(options.packageConfigPath);
- try {
- packages = parsePackagesFile(
- resourceProvider,
- resourceProvider.getFile(path),
- );
- packageMap = _getPackageMap(packages);
- } catch (e) {
- printAndFail('Unable to read package config data from $path: $e');
- }
- } else {
- var cwd = resourceProvider.getResource(path.current);
- // Look for .packages.
- packages = findPackagesFrom(resourceProvider, cwd);
- packageMap = _getPackageMap(packages);
- }
-
- return _PackageInfo(packages, packageMap);
- }
-
- Map<String, List<Folder>> _getPackageMap(Packages packages) {
- if (packages == null) {
- return null;
- }
-
- var packageMap = <String, List<Folder>>{};
- for (var package in packages.packages) {
- packageMap[package.name] = [package.libFolder];
- }
- return packageMap;
- }
-
/// Returns `true` if this relative path is a hidden directory.
bool _isInHiddenDir(String relative) =>
path.split(relative).any((part) => part.startsWith('.'));
@@ -640,41 +444,6 @@
return analyzer.analyze(formatter);
}
- void _setAnalysisDriverAnalysisContext(String rootPath) {
- var apiContextRoots = api.ContextLocator(
- resourceProvider: resourceProvider,
- ).locateRoots(
- includedPaths: [rootPath],
- excludedPaths: [],
- );
-
- if (apiContextRoots.isEmpty) {
- return;
- }
-
- analysisDriver.configure(
- analysisContext: api.DriverBasedAnalysisContext(
- resourceProvider,
- apiContextRoots.first,
- analysisDriver,
- ),
- );
- }
-
- void _setupSdk(CommandLineOptions options, AnalysisOptions analysisOptions) {
- if (sdk == null) {
- if (options.dartSdkSummaryPath != null) {
- sdk = SummaryBasedDartSdk(options.dartSdkSummaryPath, true);
- } else {
- var dartSdkPath = options.dartSdkPath;
- sdk = FolderBasedDartSdk(
- resourceProvider,
- resourceProvider.getFolder(dartSdkPath),
- );
- }
- }
- }
-
bool _shouldBeFatal(ErrorSeverity severity, CommandLineOptions options) {
if (severity == ErrorSeverity.ERROR) {
return true;
@@ -688,6 +457,16 @@
}
}
+ void _verifyAnalysisOptionsFileExists(CommandLineOptions options) {
+ var path = options.analysisOptionsFile;
+ if (path != null) {
+ if (!resourceProvider.getFile(path).exists) {
+ printAndFail('Options file not found: $path',
+ exitCode: ErrorSeverity.ERROR.ordinal);
+ }
+ }
+ }
+
static void verbosePrint(String text) {
outSink.writeln(text);
}
@@ -708,6 +487,7 @@
newOptions.lints == previous.lints &&
_equalLists(
newOptions.buildSummaryInputs, previous.buildSummaryInputs) &&
+ newOptions.defaultLanguageVersion == previous.defaultLanguageVersion &&
newOptions.disableCacheFlushing == previous.disableCacheFlushing &&
_equalLists(newOptions.enabledExperiments, previous.enabledExperiments);
}
@@ -739,15 +519,114 @@
}
}
-class _DriverError implements Exception {
- final String msg;
+class _AnalysisContextProvider {
+ final ResourceProvider _resourceProvider;
- _DriverError(this.msg);
-}
+ CommandLineOptions _commandLineOptions;
+ List<String> _pathList;
-class _PackageInfo {
- final Packages packages;
- final Map<String, List<Folder>> packageMap;
+ final Map<Folder, DriverBasedAnalysisContext> _folderContexts = {};
+ AnalysisContextCollectionImpl _collection;
+ DriverBasedAnalysisContext _analysisContext;
- _PackageInfo(this.packages, this.packageMap);
+ _AnalysisContextProvider(this._resourceProvider);
+
+ DriverBasedAnalysisContext get analysisContext {
+ return _analysisContext;
+ }
+
+ AnalysisDriver get analysisDriver {
+ return _analysisContext.driver;
+ }
+
+ /// TODO(scheglov) Use analyzedFiles()
+ PathFilter get pathFilter {
+ return PathFilter(analysisContext.contextRoot.root.path,
+ analysisContext.analysisOptions.excludePatterns);
+ }
+
+ void configureForPath(String path) {
+ var parentFolder = _resourceProvider.getFile(path).parent2;
+
+ // In batch mode we are given separate file paths to analyze.
+ // All files of a folder have the same configuration.
+ // So, reuse the corresponding analysis context.
+ _analysisContext = _folderContexts[parentFolder];
+ if (_analysisContext != null) {
+ return;
+ }
+
+ if (_collection != null) {
+ try {
+ _setContextForPath(path);
+ return;
+ } on StateError {
+ // The previous collection cannot analyze the path.
+ _collection = null;
+ }
+ }
+
+ _collection = AnalysisContextCollectionImpl(
+ byteStore: Driver.analysisDriverMemoryByteStore,
+ includedPaths: _pathList,
+ optionsFile: _commandLineOptions.analysisOptionsFile,
+ packagesFile: _commandLineOptions.packageConfigPath,
+ resourceProvider: _resourceProvider,
+ sdkPath: _commandLineOptions.dartSdkPath,
+ );
+
+ for (var _analysisContext in _collection.contexts) {
+ var analysisContext = _analysisContext as DriverBasedAnalysisContext;
+ _configureAnalysisOptionsFromCommandLineOptions(analysisContext);
+ }
+
+ _setContextForPath(path);
+ _folderContexts[parentFolder] = _analysisContext;
+ }
+
+ void setCommandLineOptions(
+ CommandLineOptions options,
+ List<String> pathList,
+ ) {
+ if (!Driver._equalCommandLineOptions(_commandLineOptions, options)) {
+ _folderContexts.clear();
+ _collection = null;
+ _analysisContext = null;
+ }
+ _commandLineOptions = options;
+ _pathList = pathList;
+ }
+
+ /// TODO(scheglov) Patch options before we create the driver.
+ void _configureAnalysisOptionsFromCommandLineOptions(
+ DriverBasedAnalysisContext analysisContext,
+ ) {
+ var analysisDriver = analysisContext.driver;
+ var optionsImpl = analysisDriver.analysisOptions as AnalysisOptionsImpl;
+
+ if (_commandLineOptions.enabledExperiments != null) {
+ optionsImpl.contextFeatures = FeatureSet.fromEnableFlags2(
+ sdkLanguageVersion: ExperimentStatus.currentVersion,
+ flags: _commandLineOptions.enabledExperiments,
+ );
+ }
+
+ if (_commandLineOptions.defaultLanguageVersion != null) {
+ var nonPackageLanguageVersion = Version.parse(
+ _commandLineOptions.defaultLanguageVersion + '.0',
+ );
+ optionsImpl.nonPackageLanguageVersion = nonPackageLanguageVersion;
+ optionsImpl.nonPackageFeatureSet = FeatureSet.latestLanguageVersion()
+ .restrictToVersion(nonPackageLanguageVersion);
+ }
+
+ analysisDriver.configure(
+ analysisOptions: optionsImpl,
+ );
+ }
+
+ void _setContextForPath(String path) {
+ var analysisContext = _collection.contextFor(path);
+ _analysisContext = analysisContext as DriverBasedAnalysisContext;
+ }
}
diff --git a/pkg/analyzer_cli/lib/src/options.dart b/pkg/analyzer_cli/lib/src/options.dart
index cff668d..fc2ad75 100644
--- a/pkg/analyzer_cli/lib/src/options.dart
+++ b/pkg/analyzer_cli/lib/src/options.dart
@@ -9,6 +9,7 @@
import 'package:analyzer/src/command_line/arguments.dart';
import 'package:analyzer/src/context/builder.dart';
import 'package:analyzer/src/dart/analysis/experiments.dart';
+import 'package:analyzer/src/util/file_paths.dart' as file_paths;
import 'package:analyzer/src/util/sdk.dart';
import 'package:analyzer_cli/src/ansi.dart' as ansi;
import 'package:analyzer_cli/src/driver.dart';
@@ -223,21 +224,21 @@
// Check SDK.
if (!options.buildModePersistentWorker) {
- // Infer if unspecified.
- options.dartSdkPath ??= getSdkPath(args);
-
var sdkPath = options.dartSdkPath;
- // Check that SDK is specified.
- if (sdkPath == null) {
- printAndFail('No Dart SDK found.');
- return null; // Only reachable in testing.
- }
// Check that SDK is existing directory.
- if (!(io.Directory(sdkPath)).existsSync()) {
- printAndFail('Invalid Dart SDK path: $sdkPath');
- return null; // Only reachable in testing.
+ if (sdkPath != null) {
+ if (!(io.Directory(sdkPath)).existsSync()) {
+ printAndFail('Invalid Dart SDK path: $sdkPath');
+ return null; // Only reachable in testing.
+ }
}
+
+ // Infer if unspecified.
+ sdkPath ??= getSdkPath(args);
+
+ var pathContext = resourceProvider.pathContext;
+ options.dartSdkPath = file_paths.absoluteNormalized(pathContext, sdkPath);
}
// Build mode.
diff --git a/pkg/analyzer_cli/test/driver_test.dart b/pkg/analyzer_cli/test/driver_test.dart
index 249b959..6d818d6 100644
--- a/pkg/analyzer_cli/test/driver_test.dart
+++ b/pkg/analyzer_cli/test/driver_test.dart
@@ -992,15 +992,6 @@
_expectUndefinedClassErrorsWithoutExclusions();
}
- Future<void>
- test_analysisOptions_excludesRelativeToAnalysisOptions_inferred() async {
- // By passing no options, and the path `lib`, it should discover the
- // analysis_options above lib. The exclude is relative to the project, not
- // the analyzed path, and it has to then understand that.
- await drive('data/exclude_test_project/lib', options: null);
- _expectUndefinedClassErrorsWithoutExclusions();
- }
-
Future<void> test_analyzeFilesInDifferentContexts() async {
await driveMany([
'data/linter_project/test_file.dart',
diff --git a/pkg/analyzer_cli/test/embedder_test.dart b/pkg/analyzer_cli/test/embedder_test.dart
index 8b554b0..3420843 100644
--- a/pkg/analyzer_cli/test/embedder_test.dart
+++ b/pkg/analyzer_cli/test/embedder_test.dart
@@ -4,7 +4,6 @@
import 'dart:io';
-import 'package:analyzer/src/dart/sdk/sdk.dart';
import 'package:analyzer_cli/src/driver.dart' show Driver, errorSink, outSink;
import 'package:path/path.dart' as path;
import 'package:test/test.dart';
@@ -41,19 +40,6 @@
expect(exitCode, 0);
expect(outSink.toString(), contains('No issues found'));
}));
-
- test('sdk setup', wrap(() async {
- var testDir = path.join(testDirectory, 'data', 'embedder_client');
- var driver = Driver();
- await driver.start([
- '--packages',
- path.join(testDir, '_packages'),
- path.join(testDir, 'embedder_yaml_user.dart')
- ]);
-
- var sdk = driver.sdk;
- expect(sdk, const TypeMatcher<FolderBasedDartSdk>());
- }));
});
}
diff --git a/pkg/dartdev/lib/src/analysis_server.dart b/pkg/dartdev/lib/src/analysis_server.dart
index 9b8340f..0f616f8 100644
--- a/pkg/dartdev/lib/src/analysis_server.dart
+++ b/pkg/dartdev/lib/src/analysis_server.dart
@@ -261,8 +261,6 @@
int get length => json['location']['length'] as int;
- String get messageSentenceFragment => trimEnd(message, '.');
-
String get url => json['url'] as String;
List<DiagnosticMessage> get contextMessages {
@@ -298,7 +296,7 @@
@override
String toString() => '${severity.toLowerCase()} • '
- '$messageSentenceFragment at $file:$startLine:$startColumn • '
+ '$message • $file:$startLine:$startColumn • '
'($code)';
}
diff --git a/pkg/dartdev/lib/src/commands/analyze.dart b/pkg/dartdev/lib/src/commands/analyze.dart
index 5018dee..cbb4270 100644
--- a/pkg/dartdev/lib/src/commands/analyze.dart
+++ b/pkg/dartdev/lib/src/commands/analyze.dart
@@ -166,7 +166,8 @@
io.Directory relativeToDir,
bool verbose = false,
}) {
- final bullet = log.ansi.bullet;
+ final ansi = log.ansi;
+ final bullet = ansi.bullet;
log.stdout('');
@@ -175,47 +176,43 @@
: (dartdevUsageLineLength - _bodyIndentWidth);
for (final AnalysisError error in errors) {
- // error • Message ... at path.dart:line:col • (code)
-
- var filePath = _relativePath(error.file, relativeToDir?.path);
var severity = error.severity.toLowerCase().padLeft(_severityWidth);
if (error.isError) {
- severity = log.ansi.error(severity);
+ severity = ansi.error(severity);
+ }
+ var filePath = _relativePath(error.file, relativeToDir?.path);
+ var codeRef = error.code;
+ // If we're in verbose mode, write any error urls instead of error codes.
+ if (error.url != null && verbose) {
+ codeRef = error.url;
}
+ // Emit "file:line:col * Error message. Correction (code)."
+ var message = ansi.emphasized('${error.message}');
+ if (error.correction != null) {
+ message += ' ${error.correction}';
+ }
+ var location = '$filePath:${error.startLine}:${error.startColumn}';
+ var output = '$location $bullet '
+ '$message $bullet '
+ '${ansi.green}$codeRef${ansi.none}';
+
+ // TODO(devoncarew): We need to take into account ansi color codes when
+ // performing line wrapping.
+ output = wrapText(output, width: wrapWidth);
log.stdout(
'$severity $bullet '
- '${log.ansi.emphasized(error.messageSentenceFragment)} '
- 'at $filePath:${error.startLine}:${error.startColumn} $bullet '
- '(${error.code})',
+ '${output.replaceAll('\n', '\n$_bodyIndent')}',
);
- if (verbose) {
- for (var message in error.contextMessages) {
- var contextPath = _relativePath(error.file, relativeToDir?.path);
- var messageSentenceFragment = trimEnd(message.message, '.');
+ // Add any context messages as bullet list items.
+ for (var message in error.contextMessages) {
+ var contextPath = _relativePath(error.file, relativeToDir?.path);
+ var messageSentenceFragment = trimEnd(message.message, '.');
- // Wrap longer context messages.
- var contextMessage = wrapText(
- '$messageSentenceFragment at '
- '$contextPath:${message.line}:${message.column}',
- width: wrapWidth);
- log.stdout('$_bodyIndent'
- '${contextMessage.replaceAll('\n', '\n$_bodyIndent')}');
- }
- }
-
- if (error.correction != null) {
- // Wrap longer correction messages.
- var correction = wrapText(error.correction, width: wrapWidth);
- log.stdout(
- '$_bodyIndent${correction.replaceAll('\n', '\n$_bodyIndent')}');
- }
-
- if (verbose) {
- if (error.url != null) {
- log.stdout('$_bodyIndent${error.url}');
- }
+ log.stdout('$_bodyIndent'
+ ' - $messageSentenceFragment at '
+ '$contextPath:${message.line}:${message.column}.');
}
}
diff --git a/pkg/dartdev/test/commands/analyze_test.dart b/pkg/dartdev/test/commands/analyze_test.dart
index 722951e..6d0709d 100644
--- a/pkg/dartdev/test/commands/analyze_test.dart
+++ b/pkg/dartdev/test/commands/analyze_test.dart
@@ -195,13 +195,11 @@
expect(result.exitCode, 3);
expect(result.stderr, isEmpty);
var stdout = result.stdout;
- expect(stdout, contains("The declaration of 'one' is on line 3 at "));
+ expect(stdout, contains("The declaration of 'one' is on line 3"));
expect(
stdout, contains('Try moving the declaration to before the first use'));
- expect(
- stdout,
- contains(
- 'https://dart.dev/tools/diagnostic-messages#referenced_before_declaration'));
+ expect(stdout, contains('https://dart.dev'));
+ expect(stdout, contains('referenced_before_declaration'));
});
group('display mode', () {
@@ -227,10 +225,11 @@
AnalyzeCommand.emitDefaultFormat(logger, errors);
expect(logger.stderrBuffer, isEmpty);
- expect(
- logger.stdoutBuffer.toString().trim(),
- contains('info - Foo bar baz at lib/test.dart:15:4 - (dead_code)'),
- );
+ final stdout = logger.stdoutBuffer.toString().trim();
+ expect(stdout, contains('info'));
+ expect(stdout, contains('lib/test.dart:15:4'));
+ expect(stdout, contains('Foo bar baz.'));
+ expect(stdout, contains('dead_code'));
});
test('machine', () {
diff --git a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
index cb03daa..be077f9 100644
--- a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
@@ -5707,7 +5707,8 @@
ExpressionInferenceResult readResult = _computePropertyGet(
node.fileOffset, receiver, receiverType, node.name, typeContext,
isThisReceiver: node.receiver is ThisExpression);
- inferrer.flowAnalysis.propertyGet(node, node.receiver, node.name.name);
+ inferrer.flowAnalysis.propertyGet(
+ node, node.receiver, node.name.name, readResult.inferredType);
ExpressionInferenceResult expressionInferenceResult =
inferrer.createNullAwareExpressionInferenceResult(
readResult.inferredType, readResult.expression, nullAwareGuards);
@@ -5976,7 +5977,6 @@
@override
ExpressionInferenceResult visitSuperPropertyGet(
SuperPropertyGet node, DartType typeContext) {
- inferrer.flowAnalysis.thisOrSuperPropertyGet(node, node.name.name);
if (node.interfaceTarget != null) {
inferrer.instrumentation?.record(
inferrer.uriForInstrumentation,
@@ -6164,7 +6164,7 @@
ExpressionInferenceResult visitThisExpression(
ThisExpression node, DartType typeContext) {
- inferrer.flowAnalysis.thisOrSuper(node);
+ inferrer.flowAnalysis.thisOrSuper(node, inferrer.thisType);
return new ExpressionInferenceResult(inferrer.thisType, node);
}
@@ -6568,7 +6568,7 @@
DartType promotedType;
DartType declaredOrInferredType = variable.lateType ?? variable.type;
if (isExtensionThis(variable)) {
- inferrer.flowAnalysis.thisOrSuper(node);
+ inferrer.flowAnalysis.thisOrSuper(node, variable.type);
} else if (inferrer.isNonNullableByDefault) {
if (node.forNullGuardedAccess) {
DartType nonNullableType = inferrer.computeNonNullable(variable.type);
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart
index a95ec85..2e20f55 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart
@@ -274,9 +274,6 @@
TypeOperationsCfe(this.typeEnvironment);
@override
- DartType get topType => typeEnvironment.objectNullableRawType;
-
- @override
TypeClassification classifyType(DartType type) {
if (type == null) {
// Note: this can happen during top-level inference.
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
index b450ab3..d70f4c1 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
@@ -15,6 +15,7 @@
import 'package:front_end/src/fasta/kernel/internal_ast.dart';
import 'package:front_end/src/fasta/type_inference/type_demotion.dart';
import 'package:front_end/src/testing/id_extractor.dart';
+import 'package:front_end/src/testing/id_testing_utils.dart';
import 'package:kernel/ast.dart';
import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
@@ -317,9 +318,18 @@
LocatedMessage message = entry.value.accept(whyNotPromotedVisitor);
if (dataForTesting != null) {
String nonPromotionReasonText = entry.value.shortName;
+ List<String> args = <String>[];
if (whyNotPromotedVisitor.propertyReference != null) {
Id id = computeMemberId(whyNotPromotedVisitor.propertyReference);
- nonPromotionReasonText += '($id)';
+ args.add('target: $id');
+ }
+ if (whyNotPromotedVisitor.propertyType != null) {
+ String typeText = typeToText(whyNotPromotedVisitor.propertyType,
+ TypeRepresentation.analyzerNonNullableByDefault);
+ args.add('type: $typeText');
+ }
+ if (args.isNotEmpty) {
+ nonPromotionReasonText += '(${args.join(', ')})';
}
dataForTesting.flowAnalysisResult.nonPromotionReasons[expression] =
nonPromotionReasonText;
@@ -3393,7 +3403,7 @@
resultType: calleeType, interfaceTarget: originalTarget)
..fileOffset = fileOffset;
flowAnalysis.propertyGet(
- originalPropertyGet, originalReceiver, originalName.name);
+ originalPropertyGet, originalReceiver, originalName.name, calleeType);
} else {
originalPropertyGet =
new PropertyGet(originalReceiver, originalName, originalTarget)
@@ -3766,6 +3776,8 @@
if (member is Procedure && member.kind == ProcedureKind.Method) {
return instantiateTearOff(inferredType, typeContext, expression);
}
+ flowAnalysis.thisOrSuperPropertyGet(
+ expression, expression.name.name, inferredType);
return new ExpressionInferenceResult(inferredType, expression);
}
@@ -5007,13 +5019,15 @@
class _WhyNotPromotedVisitor
implements
NonPromotionReasonVisitor<LocatedMessage, Node, Expression,
- VariableDeclaration> {
+ VariableDeclaration, DartType> {
final TypeInferrerImpl inferrer;
final Expression receiver;
Member propertyReference;
+ DartType propertyType;
+
_WhyNotPromotedVisitor(this.inferrer, this.receiver);
@override
@@ -5055,6 +5069,7 @@
}
if (member != null) {
propertyReference = member;
+ propertyType = reason.staticType;
return templateFieldNotPromoted
.withArguments(reason.propertyName)
.withLocation(member.fileUri, member.fileOffset, noLength);
diff --git a/pkg/nnbd_migration/lib/src/decorated_type_operations.dart b/pkg/nnbd_migration/lib/src/decorated_type_operations.dart
index 0f9328a..4c776c8 100644
--- a/pkg/nnbd_migration/lib/src/decorated_type_operations.dart
+++ b/pkg/nnbd_migration/lib/src/decorated_type_operations.dart
@@ -21,14 +21,6 @@
this._typeSystem, this._variableRepository, this._graph);
@override
- DecoratedType get topType {
- // This is only needed for explaining to the user why fields aren't
- // promoted, functionality of flow analysis that we don't take advantage of
- // during migration. So this method should never be called.
- throw StateError('Unexpected call to topType');
- }
-
- @override
TypeClassification classifyType(DecoratedType type) {
if (type.type.isDartCoreNull) {
return TypeClassification.nullOrEquivalent;
diff --git a/pkg/vm_service/lib/src/snapshot_graph.dart b/pkg/vm_service/lib/src/snapshot_graph.dart
index e51c36b..14e5818 100644
--- a/pkg/vm_service/lib/src/snapshot_graph.dart
+++ b/pkg/vm_service/lib/src/snapshot_graph.dart
@@ -194,7 +194,7 @@
/// Data associated with this object.
dynamic get data => _data;
- /// A list of indicies into [HeapSnapshotGraph.objects].
+ /// A list of indices into [HeapSnapshotGraph.objects].
List<int> get references => _references;
/// The identity hash code of this object.
diff --git a/pkg/vm_service/test/rpc_error_test.dart b/pkg/vm_service/test/rpc_error_test.dart
index e6b5df5..c9cf1be 100644
--- a/pkg/vm_service/test/rpc_error_test.dart
+++ b/pkg/vm_service/test/rpc_error_test.dart
@@ -9,7 +9,7 @@
var tests = <VMTest>[
(VmService vm) async {
- // Invoke a non-existant RPC.
+ // Invoke a non-existent RPC.
try {
final res = await vm.callMethod('foo');
fail('Expected RPCError, got $res');
diff --git a/pkg/wasm/lib/src/function.dart b/pkg/wasm/lib/src/function.dart
index 82f07b8..8cff328 100644
--- a/pkg/wasm/lib/src/function.dart
+++ b/pkg/wasm/lib/src/function.dart
@@ -13,17 +13,16 @@
Pointer<WasmerFunc> _func;
List<int> _argTypes;
int _returnType;
- Pointer<WasmerValVec> _args = allocate<WasmerValVec>();
- Pointer<WasmerValVec> _results = allocate<WasmerValVec>();
+ Pointer<WasmerValVec> _args = calloc<WasmerValVec>();
+ Pointer<WasmerValVec> _results = calloc<WasmerValVec>();
WasmFunction(this._name, this._func, this._argTypes, this._returnType) {
_args.ref.length = _argTypes.length;
- _args.ref.data = _argTypes.length == 0
- ? nullptr
- : allocate<WasmerVal>(count: _argTypes.length);
+ _args.ref.data =
+ _argTypes.length == 0 ? nullptr : calloc<WasmerVal>(_argTypes.length);
_results.ref.length = _returnType == WasmerValKindVoid ? 0 : 1;
_results.ref.data =
- _returnType == WasmerValKindVoid ? nullptr : allocate<WasmerVal>();
+ _returnType == WasmerValKindVoid ? nullptr : calloc<WasmerVal>();
for (var i = 0; i < _argTypes.length; ++i) {
_args.ref.data[i].kind = _argTypes[i];
}
diff --git a/pkg/wasm/lib/src/module.dart b/pkg/wasm/lib/src/module.dart
index b06abb8..6eb4e12 100644
--- a/pkg/wasm/lib/src/module.dart
+++ b/pkg/wasm/lib/src/module.dart
@@ -62,7 +62,7 @@
void _wasmFnImportFinalizer(Pointer<_WasmFnImport> imp) {
_wasmFnImportToFn.remove(imp.address);
- free(imp);
+ calloc.free(imp);
}
final _wasmFnImportTrampolineNative = Pointer.fromFunction<
@@ -115,15 +115,14 @@
WasmModule _module;
late List<WasmImportDescriptor> _importDescs;
Map<String, int> _importIndex;
- Pointer<WasmerExternVec> _imports = allocate<WasmerExternVec>();
+ Pointer<WasmerExternVec> _imports = calloc<WasmerExternVec>();
Pointer<WasmerWasiEnv> _wasiEnv = nullptr;
Object _importOwner = Object();
WasmInstanceBuilder(this._module) : _importIndex = {} {
_importDescs = WasmRuntime().importDescriptors(_module._module);
_imports.ref.length = _importDescs.length;
- _imports.ref.data =
- allocate<Pointer<WasmerExtern>>(count: _importDescs.length);
+ _imports.ref.data = calloc<Pointer<WasmerExtern>>(_importDescs.length);
for (var i = 0; i < _importDescs.length; ++i) {
var imp = _importDescs[i];
_importIndex["${imp.moduleName}::${imp.name}"] = i;
@@ -166,7 +165,7 @@
var argTypes = runtime.getArgTypes(imp.funcType);
var returnType = runtime.getReturnType(imp.funcType);
- var wasmFnImport = allocate<_WasmFnImport>();
+ var wasmFnImport = calloc<_WasmFnImport>();
wasmFnImport.ref.returnType = returnType;
wasmFnImport.ref.store = _module._store;
_wasmFnImportToFn[wasmFnImport.address] = fn;
diff --git a/pkg/wasm/lib/src/runtime.dart b/pkg/wasm/lib/src/runtime.dart
index 777c6dc..c543752 100644
--- a/pkg/wasm/lib/src/runtime.dart
+++ b/pkg/wasm/lib/src/runtime.dart
@@ -435,18 +435,18 @@
Pointer<WasmerModule> compile(
Object owner, Pointer<WasmerStore> store, Uint8List data) {
- var dataPtr = allocate<Uint8>(count: data.length);
+ var dataPtr = calloc<Uint8>(data.length);
for (int i = 0; i < data.length; ++i) {
dataPtr[i] = data[i];
}
- var dataVec = allocate<WasmerByteVec>();
+ var dataVec = calloc<WasmerByteVec>();
dataVec.ref.data = dataPtr;
dataVec.ref.length = data.length;
var modulePtr = _module_new(store, dataVec);
- free(dataPtr);
- free(dataVec);
+ calloc.free(dataPtr);
+ calloc.free(dataVec);
_checkNotEqual(modulePtr, nullptr, "Wasm module compile failed.");
_set_finalizer_for_module(owner, modulePtr);
@@ -454,7 +454,7 @@
}
List<WasmExportDescriptor> exportDescriptors(Pointer<WasmerModule> module) {
- var exportsVec = allocate<WasmerExporttypeVec>();
+ var exportsVec = calloc<WasmerExporttypeVec>();
_module_exports(module, exportsVec);
var exps = <WasmExportDescriptor>[];
for (var i = 0; i < exportsVec.ref.length; ++i) {
@@ -467,12 +467,12 @@
exps.add(WasmExportDescriptor(
kind, _exporttype_name(exp).ref.toString(), fnType));
}
- free(exportsVec);
+ calloc.free(exportsVec);
return exps;
}
List<WasmImportDescriptor> importDescriptors(Pointer<WasmerModule> module) {
- var importsVec = allocate<WasmerImporttypeVec>();
+ var importsVec = calloc<WasmerImporttypeVec>();
_module_imports(module, importsVec);
var imps = <WasmImportDescriptor>[];
for (var i = 0; i < importsVec.ref.length; ++i) {
@@ -488,7 +488,7 @@
_importtype_name(imp).ref.toString(),
fnType));
}
- free(importsVec);
+ calloc.free(importsVec);
return imps;
}
@@ -504,11 +504,11 @@
traps.remove(entry);
throw entry.exception;
} else {
- var trapMessage = allocate<WasmerByteVec>();
+ var trapMessage = calloc<WasmerByteVec>();
_trap_message(trap, trapMessage);
var message = "Wasm trap when calling $source: ${trapMessage.ref}";
_byte_vec_delete(trapMessage);
- free(trapMessage);
+ calloc.free(trapMessage);
_trap_delete(trap);
throw Exception(message);
}
@@ -517,11 +517,11 @@
Pointer<WasmerInstance> instantiate(Object owner, Pointer<WasmerStore> store,
Pointer<WasmerModule> module, Pointer<WasmerExternVec> imports) {
- var trap = allocate<Pointer<WasmerTrap>>();
+ var trap = calloc<Pointer<WasmerTrap>>();
trap.value = nullptr;
var inst = _instance_new(store, module, imports, trap);
maybeThrowTrap(trap.value, "module initialization function");
- free(trap);
+ calloc.free(trap);
_checkNotEqual(inst, nullptr, "Wasm module instantiation failed.");
_set_finalizer_for_instance(owner, inst);
return inst;
@@ -529,14 +529,14 @@
// Clean up the exports after use, with deleteExports.
Pointer<WasmerExternVec> exports(Pointer<WasmerInstance> instancePtr) {
- var exports = allocate<WasmerExternVec>();
+ var exports = calloc<WasmerExternVec>();
_instance_exports(instancePtr, exports);
return exports;
}
void deleteExports(Pointer<WasmerExternVec> exports) {
_extern_vec_delete(exports);
- free(exports);
+ calloc.free(exports);
}
int externKind(Pointer<WasmerExtern> extern) {
@@ -585,11 +585,11 @@
Pointer<WasmerMemory> newMemory(
Object owner, Pointer<WasmerStore> store, int pages, int? maxPages) {
- var limPtr = allocate<WasmerLimits>();
+ var limPtr = calloc<WasmerLimits>();
limPtr.ref.min = pages;
limPtr.ref.max = maxPages ?? wasm_limits_max_default;
var memType = _memorytype_new(limPtr);
- free(limPtr);
+ calloc.free(limPtr);
_checkNotEqual(memType, nullptr, "Failed to create memory type.");
_set_finalizer_for_memorytype(owner, memType);
var memory = _checkNotEqual(
@@ -626,13 +626,13 @@
}
Pointer<WasmerTrap> newTrap(Pointer<WasmerStore> store, dynamic exception) {
- var msg = allocate<WasmerByteVec>();
- msg.ref.data = allocate<Uint8>();
+ var msg = calloc<WasmerByteVec>();
+ msg.ref.data = calloc<Uint8>();
msg.ref.data[0] = 0;
msg.ref.length = 0;
var trap = _trap_new(store, msg);
- free(msg.ref.data);
- free(msg);
+ calloc.free(msg.ref.data);
+ calloc.free(msg);
_checkNotEqual(trap, nullptr, "Failed to create trap.");
var entry = _WasmTrapsEntry(exception);
_set_finalizer_for_trap(entry, trap);
@@ -641,10 +641,10 @@
}
Pointer<WasmerWasiConfig> newWasiConfig() {
- var name = allocate<Uint8>();
+ var name = calloc<Uint8>();
name[0] = 0;
var config = _wasi_config_new(name);
- free(name);
+ calloc.free(name);
return _checkNotEqual(config, nullptr, "Failed to create WASI config.");
}
@@ -682,10 +682,10 @@
String _getLastError() {
var length = _wasmer_last_error_length();
- var buf = allocate<Uint8>(count: length);
+ var buf = calloc<Uint8>(length);
_wasmer_last_error_message(buf, length);
String message = utf8.decode(buf.asTypedList(length));
- free(buf);
+ calloc.free(buf);
return message;
}
@@ -707,7 +707,7 @@
static final int _bufferLength = 1024;
Pointer<WasmerWasiEnv> _env;
Function _reader;
- Pointer<Uint8> _buf = allocate<Uint8>(count: _bufferLength);
+ Pointer<Uint8> _buf = calloc<Uint8>(_bufferLength);
int _length = 0;
_WasiStreamIterator(this._env, this._reader) {}
diff --git a/pkg/wasm/lib/src/tools/generate_ffi_boilerplate.py b/pkg/wasm/lib/src/tools/generate_ffi_boilerplate.py
index 4feda0e..a6877a7 100755
--- a/pkg/wasm/lib/src/tools/generate_ffi_boilerplate.py
+++ b/pkg/wasm/lib/src/tools/generate_ffi_boilerplate.py
@@ -88,7 +88,7 @@
opaqueTypeTemplate = '''// %s_t
-class Wasmer%s extends Struct {}'''
+class Wasmer%s extends Opaque {}'''
vecTypeTemplate = '''// %s_vec_t
class Wasmer%sVec extends Struct {
diff --git a/pkg/wasm/lib/src/tools/runtime_template.dart b/pkg/wasm/lib/src/tools/runtime_template.dart
index 385004f..2757504 100644
--- a/pkg/wasm/lib/src/tools/runtime_template.dart
+++ b/pkg/wasm/lib/src/tools/runtime_template.dart
@@ -126,18 +126,18 @@
Pointer<WasmerModule> compile(
Object owner, Pointer<WasmerStore> store, Uint8List data) {
- var dataPtr = allocate<Uint8>(count: data.length);
+ var dataPtr = calloc<Uint8>(data.length);
for (int i = 0; i < data.length; ++i) {
dataPtr[i] = data[i];
}
- var dataVec = allocate<WasmerByteVec>();
+ var dataVec = calloc<WasmerByteVec>();
dataVec.ref.data = dataPtr;
dataVec.ref.length = data.length;
var modulePtr = _module_new(store, dataVec);
- free(dataPtr);
- free(dataVec);
+ calloc.free(dataPtr);
+ calloc.free(dataVec);
_checkNotEqual(modulePtr, nullptr, "Wasm module compile failed.");
_set_finalizer_for_module(owner, modulePtr);
@@ -145,7 +145,7 @@
}
List<WasmExportDescriptor> exportDescriptors(Pointer<WasmerModule> module) {
- var exportsVec = allocate<WasmerExporttypeVec>();
+ var exportsVec = calloc<WasmerExporttypeVec>();
_module_exports(module, exportsVec);
var exps = <WasmExportDescriptor>[];
for (var i = 0; i < exportsVec.ref.length; ++i) {
@@ -158,12 +158,12 @@
exps.add(WasmExportDescriptor(
kind, _exporttype_name(exp).ref.toString(), fnType));
}
- free(exportsVec);
+ calloc.free(exportsVec);
return exps;
}
List<WasmImportDescriptor> importDescriptors(Pointer<WasmerModule> module) {
- var importsVec = allocate<WasmerImporttypeVec>();
+ var importsVec = calloc<WasmerImporttypeVec>();
_module_imports(module, importsVec);
var imps = <WasmImportDescriptor>[];
for (var i = 0; i < importsVec.ref.length; ++i) {
@@ -179,7 +179,7 @@
_importtype_name(imp).ref.toString(),
fnType));
}
- free(importsVec);
+ calloc.free(importsVec);
return imps;
}
@@ -195,11 +195,11 @@
traps.remove(entry);
throw entry.exception;
} else {
- var trapMessage = allocate<WasmerByteVec>();
+ var trapMessage = calloc<WasmerByteVec>();
_trap_message(trap, trapMessage);
var message = "Wasm trap when calling $source: ${trapMessage.ref}";
_byte_vec_delete(trapMessage);
- free(trapMessage);
+ calloc.free(trapMessage);
_trap_delete(trap);
throw Exception(message);
}
@@ -208,11 +208,11 @@
Pointer<WasmerInstance> instantiate(Object owner, Pointer<WasmerStore> store,
Pointer<WasmerModule> module, Pointer<WasmerExternVec> imports) {
- var trap = allocate<Pointer<WasmerTrap>>();
+ var trap = calloc<Pointer<WasmerTrap>>();
trap.value = nullptr;
var inst = _instance_new(store, module, imports, trap);
maybeThrowTrap(trap.value, "module initialization function");
- free(trap);
+ calloc.free(trap);
_checkNotEqual(inst, nullptr, "Wasm module instantiation failed.");
_set_finalizer_for_instance(owner, inst);
return inst;
@@ -220,14 +220,14 @@
// Clean up the exports after use, with deleteExports.
Pointer<WasmerExternVec> exports(Pointer<WasmerInstance> instancePtr) {
- var exports = allocate<WasmerExternVec>();
+ var exports = calloc<WasmerExternVec>();
_instance_exports(instancePtr, exports);
return exports;
}
void deleteExports(Pointer<WasmerExternVec> exports) {
_extern_vec_delete(exports);
- free(exports);
+ calloc.free(exports);
}
int externKind(Pointer<WasmerExtern> extern) {
@@ -276,11 +276,11 @@
Pointer<WasmerMemory> newMemory(
Object owner, Pointer<WasmerStore> store, int pages, int? maxPages) {
- var limPtr = allocate<WasmerLimits>();
+ var limPtr = calloc<WasmerLimits>();
limPtr.ref.min = pages;
limPtr.ref.max = maxPages ?? wasm_limits_max_default;
var memType = _memorytype_new(limPtr);
- free(limPtr);
+ calloc.free(limPtr);
_checkNotEqual(memType, nullptr, "Failed to create memory type.");
_set_finalizer_for_memorytype(owner, memType);
var memory = _checkNotEqual(
@@ -317,13 +317,13 @@
}
Pointer<WasmerTrap> newTrap(Pointer<WasmerStore> store, dynamic exception) {
- var msg = allocate<WasmerByteVec>();
- msg.ref.data = allocate<Uint8>();
+ var msg = calloc<WasmerByteVec>();
+ msg.ref.data = calloc<Uint8>();
msg.ref.data[0] = 0;
msg.ref.length = 0;
var trap = _trap_new(store, msg);
- free(msg.ref.data);
- free(msg);
+ calloc.free(msg.ref.data);
+ calloc.free(msg);
_checkNotEqual(trap, nullptr, "Failed to create trap.");
var entry = _WasmTrapsEntry(exception);
_set_finalizer_for_trap(entry, trap);
@@ -332,10 +332,10 @@
}
Pointer<WasmerWasiConfig> newWasiConfig() {
- var name = allocate<Uint8>();
+ var name = calloc<Uint8>();
name[0] = 0;
var config = _wasi_config_new(name);
- free(name);
+ calloc.free(name);
return _checkNotEqual(config, nullptr, "Failed to create WASI config.");
}
@@ -373,10 +373,10 @@
String _getLastError() {
var length = _wasmer_last_error_length();
- var buf = allocate<Uint8>(count: length);
+ var buf = calloc<Uint8>(length);
_wasmer_last_error_message(buf, length);
String message = utf8.decode(buf.asTypedList(length));
- free(buf);
+ calloc.free(buf);
return message;
}
@@ -398,7 +398,7 @@
static final int _bufferLength = 1024;
Pointer<WasmerWasiEnv> _env;
Function _reader;
- Pointer<Uint8> _buf = allocate<Uint8>(count: _bufferLength);
+ Pointer<Uint8> _buf = calloc<Uint8>(_bufferLength);
int _length = 0;
_WasiStreamIterator(this._env, this._reader) {}
diff --git a/pkg/wasm/lib/src/wasmer_api.dart b/pkg/wasm/lib/src/wasmer_api.dart
index b95cf9a..8a28af1 100644
--- a/pkg/wasm/lib/src/wasmer_api.dart
+++ b/pkg/wasm/lib/src/wasmer_api.dart
@@ -116,52 +116,52 @@
const int wasm_limits_max_default = 0xffffffff;
// wasm_engine_t
-class WasmerEngine extends Struct {}
+class WasmerEngine extends Opaque {}
// wasm_exporttype_t
-class WasmerExporttype extends Struct {}
+class WasmerExporttype extends Opaque {}
// wasm_extern_t
-class WasmerExtern extends Struct {}
+class WasmerExtern extends Opaque {}
// wasm_externtype_t
-class WasmerExterntype extends Struct {}
+class WasmerExterntype extends Opaque {}
// wasm_func_t
-class WasmerFunc extends Struct {}
+class WasmerFunc extends Opaque {}
// wasm_functype_t
-class WasmerFunctype extends Struct {}
+class WasmerFunctype extends Opaque {}
// wasm_importtype_t
-class WasmerImporttype extends Struct {}
+class WasmerImporttype extends Opaque {}
// wasm_instance_t
-class WasmerInstance extends Struct {}
+class WasmerInstance extends Opaque {}
// wasm_memory_t
-class WasmerMemory extends Struct {}
+class WasmerMemory extends Opaque {}
// wasm_memorytype_t
-class WasmerMemorytype extends Struct {}
+class WasmerMemorytype extends Opaque {}
// wasm_module_t
-class WasmerModule extends Struct {}
+class WasmerModule extends Opaque {}
// wasm_store_t
-class WasmerStore extends Struct {}
+class WasmerStore extends Opaque {}
// wasm_trap_t
-class WasmerTrap extends Struct {}
+class WasmerTrap extends Opaque {}
// wasm_valtype_t
-class WasmerValtype extends Struct {}
+class WasmerValtype extends Opaque {}
// wasi_config_t
-class WasmerWasiConfig extends Struct {}
+class WasmerWasiConfig extends Opaque {}
// wasi_env_t
-class WasmerWasiEnv extends Struct {}
+class WasmerWasiEnv extends Opaque {}
// wasm_byte_vec_t
class WasmerByteVec extends Struct {
diff --git a/runtime/vm/compiler/assembler/assembler_arm64.cc b/runtime/vm/compiler/assembler/assembler_arm64.cc
index 503fa52..91c5e85 100644
--- a/runtime/vm/compiler/assembler/assembler_arm64.cc
+++ b/runtime/vm/compiler/assembler/assembler_arm64.cc
@@ -205,15 +205,10 @@
}
static int CountLeadingZeros(uint64_t value, int width) {
- ASSERT((width == 32) || (width == 64));
- if (value == 0) {
- return width;
- }
- int count = 0;
- do {
- count++;
- } while (value >>= 1);
- return width - count;
+ if (width == 64) return Utils::CountLeadingZeros64(value);
+ if (width == 32) return Utils::CountLeadingZeros32(value);
+ UNREACHABLE();
+ return 0;
}
static int CountOneBits(uint64_t value, int width) {
@@ -240,7 +235,9 @@
bool Operand::IsImmLogical(uint64_t value, uint8_t width, Operand* imm_op) {
ASSERT(imm_op != NULL);
ASSERT((width == kWRegSizeInBits) || (width == kXRegSizeInBits));
- ASSERT((width == kXRegSizeInBits) || (value <= 0xffffffffUL));
+ if (width == kWRegSizeInBits) {
+ value &= 0xffffffffUL;
+ }
uint8_t n = 0;
uint8_t imm_s = 0;
uint8_t imm_r = 0;
@@ -696,31 +693,19 @@
int64_t imm,
OperandSize sz) {
ASSERT(sz == kEightBytes || sz == kFourBytes);
+ int width = sz == kEightBytes ? kXRegSizeInBits : kWRegSizeInBits;
Operand op;
- if (Operand::CanHold(imm, kXRegSizeInBits, &op) == Operand::Immediate) {
+ if (Operand::CanHold(imm, width, &op) == Operand::Immediate) {
// Handles imm == kMinInt64.
- if (sz == kEightBytes) {
- adds(dest, rn, op);
- } else {
- addsw(dest, rn, op);
- }
- } else if (Operand::CanHold(-imm, kXRegSizeInBits, &op) ==
- Operand::Immediate) {
+ adds(dest, rn, op, sz);
+ } else if (Operand::CanHold(-imm, width, &op) == Operand::Immediate) {
ASSERT(imm != kMinInt64); // Would cause erroneous overflow detection.
- if (sz == kEightBytes) {
- subs(dest, rn, op);
- } else {
- subsw(dest, rn, op);
- }
+ subs(dest, rn, op, sz);
} else {
// TODO(zra): Try adding top 12 bits, then bottom 12 bits.
ASSERT(rn != TMP2);
LoadImmediate(TMP2, imm);
- if (sz == kEightBytes) {
- adds(dest, rn, Operand(TMP2));
- } else {
- addsw(dest, rn, Operand(TMP2));
- }
+ adds(dest, rn, Operand(TMP2), sz);
}
}
@@ -728,86 +713,93 @@
Register rn,
int64_t imm,
OperandSize sz) {
- Operand op;
ASSERT(sz == kEightBytes || sz == kFourBytes);
- if (Operand::CanHold(imm, kXRegSizeInBits, &op) == Operand::Immediate) {
+ int width = sz == kEightBytes ? kXRegSizeInBits : kWRegSizeInBits;
+ Operand op;
+ if (Operand::CanHold(imm, width, &op) == Operand::Immediate) {
// Handles imm == kMinInt64.
- if (sz == kEightBytes) {
- subs(dest, rn, op);
- } else {
- subsw(dest, rn, op);
- }
- } else if (Operand::CanHold(-imm, kXRegSizeInBits, &op) ==
- Operand::Immediate) {
+ subs(dest, rn, op, sz);
+ } else if (Operand::CanHold(-imm, width, &op) == Operand::Immediate) {
ASSERT(imm != kMinInt64); // Would cause erroneous overflow detection.
- if (sz == kEightBytes) {
- adds(dest, rn, op);
- } else {
- addsw(dest, rn, op);
- }
+ adds(dest, rn, op, sz);
} else {
// TODO(zra): Try subtracting top 12 bits, then bottom 12 bits.
ASSERT(rn != TMP2);
LoadImmediate(TMP2, imm);
- if (sz == kEightBytes) {
- subs(dest, rn, Operand(TMP2));
- } else {
- subsw(dest, rn, Operand(TMP2));
- }
+ subs(dest, rn, Operand(TMP2), sz);
}
}
-void Assembler::AndImmediate(Register rd, Register rn, int64_t imm) {
+void Assembler::AndImmediate(Register rd,
+ Register rn,
+ int64_t imm,
+ OperandSize sz) {
+ ASSERT(sz == kEightBytes || sz == kFourBytes);
+ int width = sz == kEightBytes ? kXRegSizeInBits : kWRegSizeInBits;
Operand imm_op;
- if (Operand::IsImmLogical(imm, kXRegSizeInBits, &imm_op)) {
- andi(rd, rn, Immediate(imm));
+ if (Operand::IsImmLogical(imm, width, &imm_op)) {
+ andi(rd, rn, Immediate(imm), sz);
} else {
LoadImmediate(TMP, imm);
- and_(rd, rn, Operand(TMP));
+ and_(rd, rn, Operand(TMP), sz);
}
}
-void Assembler::OrImmediate(Register rd, Register rn, int64_t imm) {
+void Assembler::OrImmediate(Register rd,
+ Register rn,
+ int64_t imm,
+ OperandSize sz) {
+ ASSERT(sz == kEightBytes || sz == kFourBytes);
+ int width = sz == kEightBytes ? kXRegSizeInBits : kWRegSizeInBits;
Operand imm_op;
- if (Operand::IsImmLogical(imm, kXRegSizeInBits, &imm_op)) {
- orri(rd, rn, Immediate(imm));
+ if (Operand::IsImmLogical(imm, width, &imm_op)) {
+ orri(rd, rn, Immediate(imm), sz);
} else {
LoadImmediate(TMP, imm);
- orr(rd, rn, Operand(TMP));
+ orr(rd, rn, Operand(TMP), sz);
}
}
-void Assembler::XorImmediate(Register rd, Register rn, int64_t imm) {
+void Assembler::XorImmediate(Register rd,
+ Register rn,
+ int64_t imm,
+ OperandSize sz) {
+ ASSERT(sz == kEightBytes || sz == kFourBytes);
+ int width = sz == kEightBytes ? kXRegSizeInBits : kWRegSizeInBits;
Operand imm_op;
- if (Operand::IsImmLogical(imm, kXRegSizeInBits, &imm_op)) {
- eori(rd, rn, Immediate(imm));
+ if (Operand::IsImmLogical(imm, width, &imm_op)) {
+ eori(rd, rn, Immediate(imm), sz);
} else {
LoadImmediate(TMP, imm);
- eor(rd, rn, Operand(TMP));
+ eor(rd, rn, Operand(TMP), sz);
}
}
-void Assembler::TestImmediate(Register rn, int64_t imm) {
+void Assembler::TestImmediate(Register rn, int64_t imm, OperandSize sz) {
+ ASSERT(sz == kEightBytes || sz == kFourBytes);
+ int width = sz == kEightBytes ? kXRegSizeInBits : kWRegSizeInBits;
Operand imm_op;
- if (Operand::IsImmLogical(imm, kXRegSizeInBits, &imm_op)) {
- tsti(rn, Immediate(imm));
+ if (Operand::IsImmLogical(imm, width, &imm_op)) {
+ tsti(rn, Immediate(imm), sz);
} else {
LoadImmediate(TMP, imm);
tst(rn, Operand(TMP));
}
}
-void Assembler::CompareImmediate(Register rn, int64_t imm) {
+void Assembler::CompareImmediate(Register rn, int64_t imm, OperandSize sz) {
+ ASSERT(sz == kEightBytes || sz == kFourBytes);
+ int width = sz == kEightBytes ? kXRegSizeInBits : kWRegSizeInBits;
Operand op;
- if (Operand::CanHold(imm, kXRegSizeInBits, &op) == Operand::Immediate) {
- cmp(rn, op);
- } else if (Operand::CanHold(-static_cast<uint64_t>(imm), kXRegSizeInBits,
- &op) == Operand::Immediate) {
- cmn(rn, op);
+ if (Operand::CanHold(imm, width, &op) == Operand::Immediate) {
+ cmp(rn, op, sz);
+ } else if (Operand::CanHold(-static_cast<uint64_t>(imm), width, &op) ==
+ Operand::Immediate) {
+ cmn(rn, op, sz);
} else {
ASSERT(rn != TMP2);
LoadImmediate(TMP2, imm);
- cmp(rn, Operand(TMP2));
+ cmp(rn, Operand(TMP2), sz);
}
}
diff --git a/runtime/vm/compiler/assembler/assembler_arm64.h b/runtime/vm/compiler/assembler/assembler_arm64.h
index 79eff28..14ac5aa 100644
--- a/runtime/vm/compiler/assembler/assembler_arm64.h
+++ b/runtime/vm/compiler/assembler/assembler_arm64.h
@@ -628,29 +628,25 @@
// Addition and subtraction.
// For add and sub, to use CSP for rn, o must be of type Operand::Extend.
// For an unmodified rm in this case, use Operand(rm, UXTX, 0);
- void add(Register rd, Register rn, Operand o) {
- AddSubHelper(kEightBytes, false, false, rd, rn, o);
+ void add(Register rd, Register rn, Operand o, OperandSize sz = kEightBytes) {
+ AddSubHelper(sz, false, false, rd, rn, o);
}
- void adds(Register rd, Register rn, Operand o) {
- AddSubHelper(kEightBytes, true, false, rd, rn, o);
+ void adds(Register rd, Register rn, Operand o, OperandSize sz = kEightBytes) {
+ AddSubHelper(sz, true, false, rd, rn, o);
}
- void addw(Register rd, Register rn, Operand o) {
- AddSubHelper(kFourBytes, false, false, rd, rn, o);
+ void sub(Register rd, Register rn, Operand o, OperandSize sz = kEightBytes) {
+ AddSubHelper(sz, false, true, rd, rn, o);
}
+ void subs(Register rd, Register rn, Operand o, OperandSize sz = kEightBytes) {
+ AddSubHelper(sz, true, true, rd, rn, o);
+ }
+ void addw(Register rd, Register rn, Operand o) { add(rd, rn, o, kFourBytes); }
void addsw(Register rd, Register rn, Operand o) {
- AddSubHelper(kFourBytes, true, false, rd, rn, o);
+ adds(rd, rn, o, kFourBytes);
}
- void sub(Register rd, Register rn, Operand o) {
- AddSubHelper(kEightBytes, false, true, rd, rn, o);
- }
- void subs(Register rd, Register rn, Operand o) {
- AddSubHelper(kEightBytes, true, true, rd, rn, o);
- }
- void subw(Register rd, Register rn, Operand o) {
- AddSubHelper(kFourBytes, false, true, rd, rn, o);
- }
+ void subw(Register rd, Register rn, Operand o) { sub(rd, rn, o, kFourBytes); }
void subsw(Register rd, Register rn, Operand o) {
- AddSubHelper(kFourBytes, true, true, rd, rn, o);
+ subs(rd, rn, o, kFourBytes);
}
// Addition and subtraction with carry.
@@ -810,72 +806,82 @@
}
// Logical immediate operations.
- void andi(Register rd, Register rn, const Immediate& imm) {
+ void andi(Register rd,
+ Register rn,
+ const Immediate& imm,
+ OperandSize sz = kEightBytes) {
+ ASSERT(sz == kEightBytes || sz == kFourBytes);
+ int width = sz == kEightBytes ? kXRegSizeInBits : kWRegSizeInBits;
Operand imm_op;
- const bool immok =
- Operand::IsImmLogical(imm.value(), kXRegSizeInBits, &imm_op);
+ const bool immok = Operand::IsImmLogical(imm.value(), width, &imm_op);
ASSERT(immok);
- EmitLogicalImmOp(ANDI, rd, rn, imm_op, kEightBytes);
+ EmitLogicalImmOp(ANDI, rd, rn, imm_op, sz);
}
- void orri(Register rd, Register rn, const Immediate& imm) {
+ void orri(Register rd,
+ Register rn,
+ const Immediate& imm,
+ OperandSize sz = kEightBytes) {
+ ASSERT(sz == kEightBytes || sz == kFourBytes);
+ int width = sz == kEightBytes ? kXRegSizeInBits : kWRegSizeInBits;
Operand imm_op;
- const bool immok =
- Operand::IsImmLogical(imm.value(), kXRegSizeInBits, &imm_op);
+ const bool immok = Operand::IsImmLogical(imm.value(), width, &imm_op);
ASSERT(immok);
- EmitLogicalImmOp(ORRI, rd, rn, imm_op, kEightBytes);
+ EmitLogicalImmOp(ORRI, rd, rn, imm_op, sz);
}
- void eori(Register rd, Register rn, const Immediate& imm) {
+ void eori(Register rd,
+ Register rn,
+ const Immediate& imm,
+ OperandSize sz = kEightBytes) {
+ ASSERT(sz == kEightBytes || sz == kFourBytes);
+ int width = sz == kEightBytes ? kXRegSizeInBits : kWRegSizeInBits;
Operand imm_op;
- const bool immok =
- Operand::IsImmLogical(imm.value(), kXRegSizeInBits, &imm_op);
+ const bool immok = Operand::IsImmLogical(imm.value(), width, &imm_op);
ASSERT(immok);
- EmitLogicalImmOp(EORI, rd, rn, imm_op, kEightBytes);
+ EmitLogicalImmOp(EORI, rd, rn, imm_op, sz);
}
- void andis(Register rd, Register rn, const Immediate& imm) {
+ void andis(Register rd,
+ Register rn,
+ const Immediate& imm,
+ OperandSize sz = kEightBytes) {
+ ASSERT(sz == kEightBytes || sz == kFourBytes);
+ int width = sz == kEightBytes ? kXRegSizeInBits : kWRegSizeInBits;
Operand imm_op;
- const bool immok =
- Operand::IsImmLogical(imm.value(), kXRegSizeInBits, &imm_op);
+ const bool immok = Operand::IsImmLogical(imm.value(), width, &imm_op);
ASSERT(immok);
- EmitLogicalImmOp(ANDIS, rd, rn, imm_op, kEightBytes);
+ EmitLogicalImmOp(ANDIS, rd, rn, imm_op, sz);
}
// Logical (shifted) register operations.
- void and_(Register rd, Register rn, Operand o) {
- EmitLogicalShiftOp(AND, rd, rn, o, kEightBytes);
+ void and_(Register rd, Register rn, Operand o, OperandSize sz = kEightBytes) {
+ EmitLogicalShiftOp(AND, rd, rn, o, sz);
+ }
+ void bic(Register rd, Register rn, Operand o, OperandSize sz = kEightBytes) {
+ EmitLogicalShiftOp(BIC, rd, rn, o, sz);
+ }
+ void orr(Register rd, Register rn, Operand o, OperandSize sz = kEightBytes) {
+ EmitLogicalShiftOp(ORR, rd, rn, o, sz);
+ }
+ void orn(Register rd, Register rn, Operand o, OperandSize sz = kEightBytes) {
+ EmitLogicalShiftOp(ORN, rd, rn, o, sz);
+ }
+ void eor(Register rd, Register rn, Operand o, OperandSize sz = kEightBytes) {
+ EmitLogicalShiftOp(EOR, rd, rn, o, sz);
+ }
+ void eon(Register rd, Register rn, Operand o, OperandSize sz = kEightBytes) {
+ EmitLogicalShiftOp(EON, rd, rn, o, sz);
+ }
+ void ands(Register rd, Register rn, Operand o, OperandSize sz = kEightBytes) {
+ EmitLogicalShiftOp(ANDS, rd, rn, o, sz);
+ }
+ void bics(Register rd, Register rn, Operand o, OperandSize sz = kEightBytes) {
+ EmitLogicalShiftOp(BICS, rd, rn, o, sz);
}
void andw_(Register rd, Register rn, Operand o) {
- EmitLogicalShiftOp(AND, rd, rn, o, kFourBytes);
+ and_(rd, rn, o, kFourBytes);
}
- void bic(Register rd, Register rn, Operand o) {
- EmitLogicalShiftOp(BIC, rd, rn, o, kEightBytes);
- }
- void orr(Register rd, Register rn, Operand o) {
- EmitLogicalShiftOp(ORR, rd, rn, o, kEightBytes);
- }
- void orrw(Register rd, Register rn, Operand o) {
- EmitLogicalShiftOp(ORR, rd, rn, o, kFourBytes);
- }
- void orn(Register rd, Register rn, Operand o) {
- EmitLogicalShiftOp(ORN, rd, rn, o, kEightBytes);
- }
- void ornw(Register rd, Register rn, Operand o) {
- EmitLogicalShiftOp(ORN, rd, rn, o, kFourBytes);
- }
- void eor(Register rd, Register rn, Operand o) {
- EmitLogicalShiftOp(EOR, rd, rn, o, kEightBytes);
- }
- void eorw(Register rd, Register rn, Operand o) {
- EmitLogicalShiftOp(EOR, rd, rn, o, kFourBytes);
- }
- void eon(Register rd, Register rn, Operand o) {
- EmitLogicalShiftOp(EON, rd, rn, o, kEightBytes);
- }
- void ands(Register rd, Register rn, Operand o) {
- EmitLogicalShiftOp(ANDS, rd, rn, o, kEightBytes);
- }
- void bics(Register rd, Register rn, Operand o) {
- EmitLogicalShiftOp(BICS, rd, rn, o, kEightBytes);
- }
+ void orrw(Register rd, Register rn, Operand o) { orr(rd, rn, o, kFourBytes); }
+ void ornw(Register rd, Register rn, Operand o) { orn(rd, rn, o, kFourBytes); }
+ void eorw(Register rd, Register rn, Operand o) { eor(rd, rn, o, kFourBytes); }
// Count leading zero bits.
void clz(Register rd, Register rn) {
@@ -1090,10 +1096,14 @@
// rn cmp o.
// For add and sub, to use CSP for rn, o must be of type Operand::Extend.
// For an unmodified rm in this case, use Operand(rm, UXTX, 0);
- void cmp(Register rn, Operand o) { subs(ZR, rn, o); }
- void cmpw(Register rn, Operand o) { subsw(ZR, rn, o); }
+ void cmp(Register rn, Operand o, OperandSize sz = kEightBytes) {
+ subs(ZR, rn, o, sz);
+ }
+ void cmpw(Register rn, Operand o) { cmp(rn, o, kFourBytes); }
// rn cmp -o.
- void cmn(Register rn, Operand o) { adds(ZR, rn, o); }
+ void cmn(Register rn, Operand o, OperandSize sz = kEightBytes) {
+ adds(ZR, rn, o, sz);
+ }
void CompareRegisters(Register rn, Register rm) {
if (rn == CSP) {
@@ -1490,8 +1500,12 @@
// The caller of PopAndUntagPP() must explicitly allow use of popped PP.
set_constant_pool_allowed(false);
}
- void tst(Register rn, Operand o) { ands(ZR, rn, o); }
- void tsti(Register rn, const Immediate& imm) { andis(ZR, rn, imm); }
+ void tst(Register rn, Operand o, OperandSize sz = kEightBytes) {
+ ands(ZR, rn, o, sz);
+ }
+ void tsti(Register rn, const Immediate& imm, OperandSize sz = kEightBytes) {
+ andis(ZR, rn, imm, sz);
+ }
void LslImmediate(Register rd,
Register rn,
@@ -1612,11 +1626,20 @@
Register rn,
int64_t imm,
OperandSize sz = kEightBytes);
- void AndImmediate(Register rd, Register rn, int64_t imm);
- void OrImmediate(Register rd, Register rn, int64_t imm);
- void XorImmediate(Register rd, Register rn, int64_t imm);
- void TestImmediate(Register rn, int64_t imm);
- void CompareImmediate(Register rn, int64_t imm);
+ void AndImmediate(Register rd,
+ Register rn,
+ int64_t imm,
+ OperandSize sz = kEightBytes);
+ void OrImmediate(Register rd,
+ Register rn,
+ int64_t imm,
+ OperandSize sz = kEightBytes);
+ void XorImmediate(Register rd,
+ Register rn,
+ int64_t imm,
+ OperandSize sz = kEightBytes);
+ void TestImmediate(Register rn, int64_t imm, OperandSize sz = kEightBytes);
+ void CompareImmediate(Register rn, int64_t imm, OperandSize sz = kEightBytes);
void LoadFromOffset(Register dest,
const Address& address,
diff --git a/runtime/vm/compiler/assembler/assembler_arm64_test.cc b/runtime/vm/compiler/assembler/assembler_arm64_test.cc
index 62129c2..4451d4f 100644
--- a/runtime/vm/compiler/assembler/assembler_arm64_test.cc
+++ b/runtime/vm/compiler/assembler/assembler_arm64_test.cc
@@ -4773,6 +4773,91 @@
EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
}
+ASSEMBLER_TEST_GENERATE(AndImmediate32Negative, assembler) {
+ __ AndImmediate(R0, R0, -512, kFourBytes);
+ __ ret();
+}
+
+ASSEMBLER_TEST_RUN(AndImmediate32Negative, test) {
+ typedef intptr_t (*IntPtrReturn)(intptr_t) DART_UNUSED;
+ EXPECT_EQ(0xfffffe00,
+ EXECUTE_TEST_CODE_INTPTR_INTPTR(IntPtrReturn, test->entry(), -42));
+ EXPECT_EQ(0, EXECUTE_TEST_CODE_INTPTR_INTPTR(IntPtrReturn, test->entry(), 0));
+ EXPECT_EQ(0,
+ EXECUTE_TEST_CODE_INTPTR_INTPTR(IntPtrReturn, test->entry(), 42));
+}
+
+ASSEMBLER_TEST_GENERATE(OrImmediate32Negative, assembler) {
+ __ OrImmediate(R0, R0, -512, kFourBytes);
+ __ ret();
+}
+
+ASSEMBLER_TEST_RUN(OrImmediate32Negative, test) {
+ typedef intptr_t (*IntPtrReturn)(intptr_t) DART_UNUSED;
+ EXPECT_EQ(0xffffffd6,
+ EXECUTE_TEST_CODE_INTPTR_INTPTR(IntPtrReturn, test->entry(), -42));
+ EXPECT_EQ(0xfffffe00,
+ EXECUTE_TEST_CODE_INTPTR_INTPTR(IntPtrReturn, test->entry(), 0));
+ EXPECT_EQ(0xfffffe2a,
+ EXECUTE_TEST_CODE_INTPTR_INTPTR(IntPtrReturn, test->entry(), 42));
+}
+
+ASSEMBLER_TEST_GENERATE(XorImmediate32Negative, assembler) {
+ __ XorImmediate(R0, R0, -512, kFourBytes);
+ __ ret();
+}
+
+ASSEMBLER_TEST_RUN(XorImmediate32Negative, test) {
+ typedef intptr_t (*IntPtrReturn)(intptr_t) DART_UNUSED;
+ EXPECT_EQ(0x1d6,
+ EXECUTE_TEST_CODE_INTPTR_INTPTR(IntPtrReturn, test->entry(), -42));
+ EXPECT_EQ(0xfffffe00,
+ EXECUTE_TEST_CODE_INTPTR_INTPTR(IntPtrReturn, test->entry(), 0));
+ EXPECT_EQ(0xfffffe2a,
+ EXECUTE_TEST_CODE_INTPTR_INTPTR(IntPtrReturn, test->entry(), 42));
+}
+
+ASSEMBLER_TEST_GENERATE(TestImmediate32Negative, assembler) {
+ Label on_zero;
+ __ TestImmediate(R0, -512, kFourBytes);
+ __ b(&on_zero, EQ);
+ __ LoadImmediate(R0, 1);
+ __ ret();
+ __ Bind(&on_zero);
+ __ LoadImmediate(R0, 0);
+ __ ret();
+}
+
+ASSEMBLER_TEST_RUN(TestImmediate32Negative, test) {
+ typedef intptr_t (*IntPtrReturn)(intptr_t) DART_UNUSED;
+ EXPECT_EQ(1,
+ EXECUTE_TEST_CODE_INTPTR_INTPTR(IntPtrReturn, test->entry(), -42));
+ EXPECT_EQ(0, EXECUTE_TEST_CODE_INTPTR_INTPTR(IntPtrReturn, test->entry(), 0));
+ EXPECT_EQ(0,
+ EXECUTE_TEST_CODE_INTPTR_INTPTR(IntPtrReturn, test->entry(), 42));
+}
+
+ASSEMBLER_TEST_GENERATE(CompareImmediate32Negative, assembler) {
+ Label on_zero;
+ __ CompareImmediate(R0, -512, kFourBytes);
+ __ b(&on_zero, LT);
+ __ LoadImmediate(R0, 0);
+ __ ret();
+ __ Bind(&on_zero);
+ __ LoadImmediate(R0, 1);
+ __ ret();
+}
+
+ASSEMBLER_TEST_RUN(CompareImmediate32Negative, test) {
+ typedef intptr_t (*IntPtrReturn)(intptr_t) DART_UNUSED;
+ EXPECT_EQ(1,
+ EXECUTE_TEST_CODE_INTPTR_INTPTR(IntPtrReturn, test->entry(), -513));
+ EXPECT_EQ(0,
+ EXECUTE_TEST_CODE_INTPTR_INTPTR(IntPtrReturn, test->entry(), -512));
+ EXPECT_EQ(0,
+ EXECUTE_TEST_CODE_INTPTR_INTPTR(IntPtrReturn, test->entry(), -511));
+}
+
} // namespace compiler
} // namespace dart
diff --git a/runtime/vm/exceptions.cc b/runtime/vm/exceptions.cc
index 363fd1e..db937ad 100644
--- a/runtime/vm/exceptions.cc
+++ b/runtime/vm/exceptions.cc
@@ -648,14 +648,8 @@
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
auto isolate_group = thread->isolate_group();
- Class& error_class =
+ const auto& error_class =
Class::Handle(zone, isolate_group->object_store()->error_class());
- if (error_class.IsNull()) {
- const Library& core_lib = Library::Handle(zone, Library::CoreLibrary());
- error_class = core_lib.LookupClass(Symbols::Error());
- ASSERT(!error_class.IsNull());
- isolate_group->object_store()->set_error_class(error_class);
- }
// If instance class extends 'class Error' return '_stackTrace' field.
Class& test_class = Class::Handle(zone, instance.clazz());
AbstractType& type = AbstractType::Handle(zone, AbstractType::null());
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 208f123..dbe84b2 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -722,7 +722,7 @@
cls.set_is_type_finalized();
cls.set_type_arguments_field_offset_in_words(Class::kNoTypeArguments,
RTN::Class::kNoTypeArguments);
- cls.set_num_type_arguments(0);
+ cls.set_num_type_arguments_unsafe(0);
cls.set_num_native_fields(0);
cls.InitEmptyFields();
isolate_group->class_table()->Register(cls);
@@ -730,12 +730,12 @@
// Allocate and initialize the null class.
cls = Class::New<Instance, RTN::Instance>(kNullCid, isolate_group);
- cls.set_num_type_arguments(0);
+ cls.set_num_type_arguments_unsafe(0);
isolate_group->object_store()->set_null_class(cls);
// Allocate and initialize Never class.
cls = Class::New<Instance, RTN::Instance>(kNeverCid, isolate_group);
- cls.set_num_type_arguments(0);
+ cls.set_num_type_arguments_unsafe(0);
cls.set_is_allocate_finalized();
cls.set_is_declaration_loaded();
cls.set_is_type_finalized();
@@ -745,7 +745,7 @@
cls = Class::New<FreeListElement::FakeInstance,
RTN::FreeListElement::FakeInstance>(kFreeListElement,
isolate_group);
- cls.set_num_type_arguments(0);
+ cls.set_num_type_arguments_unsafe(0);
cls.set_is_allocate_finalized();
cls.set_is_declaration_loaded();
cls.set_is_type_finalized();
@@ -754,7 +754,7 @@
cls = Class::New<ForwardingCorpse::FakeInstance,
RTN::ForwardingCorpse::FakeInstance>(kForwardingCorpse,
isolate_group);
- cls.set_num_type_arguments(0);
+ cls.set_num_type_arguments_unsafe(0);
cls.set_is_allocate_finalized();
cls.set_is_declaration_loaded();
cls.set_is_type_finalized();
@@ -889,19 +889,19 @@
isolate_group->object_store()->set_array_class(cls);
cls.set_type_arguments_field_offset(Array::type_arguments_offset(),
RTN::Array::type_arguments_offset());
- cls.set_num_type_arguments(1);
+ cls.set_num_type_arguments_unsafe(1);
cls = Class::New<Array, RTN::Array>(kImmutableArrayCid, isolate_group);
isolate_group->object_store()->set_immutable_array_class(cls);
cls.set_type_arguments_field_offset(Array::type_arguments_offset(),
RTN::Array::type_arguments_offset());
- cls.set_num_type_arguments(1);
+ cls.set_num_type_arguments_unsafe(1);
cls =
Class::New<GrowableObjectArray, RTN::GrowableObjectArray>(isolate_group);
isolate_group->object_store()->set_growable_object_array_class(cls);
cls.set_type_arguments_field_offset(
GrowableObjectArray::type_arguments_offset(),
RTN::GrowableObjectArray::type_arguments_offset());
- cls.set_num_type_arguments(1);
+ cls.set_num_type_arguments_unsafe(1);
cls = Class::NewStringClass(kOneByteStringCid, isolate_group);
isolate_group->object_store()->set_one_byte_string_class(cls);
cls = Class::NewStringClass(kTwoByteStringCid, isolate_group);
@@ -1045,14 +1045,14 @@
cls = Class::New<Instance, RTN::Instance>(kDynamicCid, isolate_group);
cls.set_is_abstract();
- cls.set_num_type_arguments(0);
+ cls.set_num_type_arguments_unsafe(0);
cls.set_is_allocate_finalized();
cls.set_is_declaration_loaded();
cls.set_is_type_finalized();
dynamic_class_ = cls.ptr();
cls = Class::New<Instance, RTN::Instance>(kVoidCid, isolate_group);
- cls.set_num_type_arguments(0);
+ cls.set_num_type_arguments_unsafe(0);
cls.set_is_allocate_finalized();
cls.set_is_declaration_loaded();
cls.set_is_type_finalized();
@@ -1599,7 +1599,7 @@
// respective Raw* classes.
cls.set_type_arguments_field_offset(Array::type_arguments_offset(),
RTN::Array::type_arguments_offset());
- cls.set_num_type_arguments(1);
+ cls.set_num_type_arguments_unsafe(1);
// Set up the growable object array class (Has to be done after the array
// class is setup as one of its field is an array object).
@@ -1609,7 +1609,7 @@
cls.set_type_arguments_field_offset(
GrowableObjectArray::type_arguments_offset(),
RTN::GrowableObjectArray::type_arguments_offset());
- cls.set_num_type_arguments(1);
+ cls.set_num_type_arguments_unsafe(1);
// Initialize hash set for canonical types.
const intptr_t kInitialCanonicalTypeSize = 16;
@@ -1704,7 +1704,7 @@
object_store->set_immutable_array_class(cls);
cls.set_type_arguments_field_offset(Array::type_arguments_offset(),
RTN::Array::type_arguments_offset());
- cls.set_num_type_arguments(1);
+ cls.set_num_type_arguments_unsafe(1);
ASSERT(object_store->immutable_array_class() !=
object_store->array_class());
cls.set_is_prefinalized();
@@ -1778,7 +1778,7 @@
cls = Class::New<Instance, RTN::Instance>(kInstanceCid, isolate_group);
object_store->set_object_class(cls);
cls.set_name(Symbols::Object());
- cls.set_num_type_arguments(0);
+ cls.set_num_type_arguments_unsafe(0);
cls.set_is_prefinalized();
cls.set_is_const();
core_lib.AddClass(cls);
@@ -1803,13 +1803,13 @@
cls = Class::New<Instance, RTN::Instance>(kNullCid, isolate_group);
object_store->set_null_class(cls);
- cls.set_num_type_arguments(0);
+ cls.set_num_type_arguments_unsafe(0);
cls.set_is_prefinalized();
RegisterClass(cls, Symbols::Null(), core_lib);
pending_classes.Add(cls);
cls = Class::New<Instance, RTN::Instance>(kNeverCid, isolate_group);
- cls.set_num_type_arguments(0);
+ cls.set_num_type_arguments_unsafe(0);
cls.set_is_allocate_finalized();
cls.set_is_declaration_loaded();
cls.set_is_type_finalized();
@@ -1896,7 +1896,7 @@
cls.set_type_arguments_field_offset(
LinkedHashMap::type_arguments_offset(),
RTN::LinkedHashMap::type_arguments_offset());
- cls.set_num_type_arguments(2);
+ cls.set_num_type_arguments_unsafe(2);
RegisterPrivateClass(cls, Symbols::_LinkedHashMap(), lib);
pending_classes.Add(cls);
@@ -1914,7 +1914,7 @@
cls = Class::New<FutureOr, RTN::FutureOr>(isolate_group);
cls.set_type_arguments_field_offset(FutureOr::type_arguments_offset(),
RTN::FutureOr::type_arguments_offset());
- cls.set_num_type_arguments(1);
+ cls.set_num_type_arguments_unsafe(1);
RegisterClass(cls, Symbols::FutureOr(), lib);
pending_classes.Add(cls);
@@ -1993,7 +1993,7 @@
/*register_class=*/true,
/*is_abstract=*/true);
RegisterClass(cls, Symbols::Float32x4(), lib);
- cls.set_num_type_arguments(0);
+ cls.set_num_type_arguments_unsafe(0);
cls.set_is_prefinalized();
type = Type::NewNonParameterizedType(cls);
object_store->set_float32x4_type(type);
@@ -2007,7 +2007,7 @@
/*register_class=*/true,
/*is_abstract=*/true);
RegisterClass(cls, Symbols::Int32x4(), lib);
- cls.set_num_type_arguments(0);
+ cls.set_num_type_arguments_unsafe(0);
cls.set_is_prefinalized();
type = Type::NewNonParameterizedType(cls);
object_store->set_int32x4_type(type);
@@ -2021,7 +2021,7 @@
/*register_class=*/true,
/*is_abstract=*/true);
RegisterClass(cls, Symbols::Float64x2(), lib);
- cls.set_num_type_arguments(0);
+ cls.set_num_type_arguments_unsafe(0);
cls.set_is_prefinalized();
type = Type::NewNonParameterizedType(cls);
object_store->set_float64x2_type(type);
@@ -2036,7 +2036,7 @@
cls = Class::New<Instance, RTN::Instance>(kIllegalCid, isolate_group,
/*register_class=*/true,
/*is_abstract=*/true);
- cls.set_num_type_arguments(0);
+ cls.set_num_type_arguments_unsafe(0);
cls.set_is_prefinalized();
RegisterClass(cls, Symbols::Type(), core_lib);
pending_classes.Add(cls);
@@ -2047,7 +2047,7 @@
cls = Class::New<Instance, RTN::Instance>(kIllegalCid, isolate_group,
/*register_class=*/true,
/*is_abstract=*/true);
- cls.set_num_type_arguments(0);
+ cls.set_num_type_arguments_unsafe(0);
cls.set_is_prefinalized();
RegisterClass(cls, Symbols::Function(), core_lib);
pending_classes.Add(cls);
@@ -2072,7 +2072,7 @@
/*register_class=*/true,
/*is_abstract=*/true);
RegisterClass(cls, Symbols::Int(), core_lib);
- cls.set_num_type_arguments(0);
+ cls.set_num_type_arguments_unsafe(0);
cls.set_is_prefinalized();
pending_classes.Add(cls);
type = Type::NewNonParameterizedType(cls);
@@ -2088,7 +2088,7 @@
/*register_class=*/true,
/*is_abstract=*/true);
RegisterClass(cls, Symbols::Double(), core_lib);
- cls.set_num_type_arguments(0);
+ cls.set_num_type_arguments_unsafe(0);
cls.set_is_prefinalized();
pending_classes.Add(cls);
type = Type::NewNonParameterizedType(cls);
@@ -2105,7 +2105,7 @@
/*register_class=*/true,
/*is_abstract=*/true);
RegisterClass(cls, name, core_lib);
- cls.set_num_type_arguments(0);
+ cls.set_num_type_arguments_unsafe(0);
cls.set_is_prefinalized();
pending_classes.Add(cls);
type = Type::NewNonParameterizedType(cls);
@@ -2262,7 +2262,7 @@
object_store->set_bootstrap_library(ObjectStore::kFfi, lib);
cls = Class::New<Instance, RTN::Instance>(kFfiNativeTypeCid, isolate_group);
- cls.set_num_type_arguments(0);
+ cls.set_num_type_arguments_unsafe(0);
cls.set_is_prefinalized();
pending_classes.Add(cls);
object_store->set_ffi_native_type_class(cls);
@@ -2270,7 +2270,7 @@
#define REGISTER_FFI_TYPE_MARKER(clazz) \
cls = Class::New<Instance, RTN::Instance>(kFfi##clazz##Cid, isolate_group); \
- cls.set_num_type_arguments(0); \
+ cls.set_num_type_arguments_unsafe(0); \
cls.set_is_prefinalized(); \
pending_classes.Add(cls); \
RegisterClass(cls, Symbols::Ffi##clazz(), lib);
@@ -2281,7 +2281,7 @@
isolate_group);
cls.set_type_arguments_field_offset(Pointer::type_arguments_offset(),
RTN::Pointer::type_arguments_offset());
- cls.set_num_type_arguments(1);
+ cls.set_num_type_arguments_unsafe(1);
cls.set_is_prefinalized();
pending_classes.Add(cls);
RegisterClass(cls, Symbols::FfiNativeFunction(), lib);
@@ -2811,7 +2811,7 @@
target_next_field_offset);
COMPILE_ASSERT((FakeObject::kClassId != kInstanceCid));
result.set_id(FakeObject::kClassId);
- result.set_num_type_arguments(0);
+ result.set_num_type_arguments_unsafe(0);
result.set_num_native_fields(0);
result.set_state_bits(0);
if ((FakeObject::kClassId < kInstanceCid) ||
@@ -2847,6 +2847,15 @@
if (!Utils::IsInt(16, value)) {
ReportTooManyTypeArguments(*this);
}
+ // We allow concurrent calculation of the number of type arguments. If two
+ // threads perform this operation it doesn't matter which one wins.
+ DEBUG_ONLY(intptr_t old_value = num_type_arguments());
+ DEBUG_ASSERT(old_value == kUnknownNumTypeArguments || old_value == value);
+ StoreNonPointer<int16_t, int16_t, std::memory_order_relaxed>(
+ &untag()->num_type_arguments_, value);
+}
+
+void Class::set_num_type_arguments_unsafe(intptr_t value) const {
StoreNonPointer(&untag()->num_type_arguments_, value);
}
@@ -4509,7 +4518,7 @@
result.set_next_field_offset(host_next_field_offset,
target_next_field_offset);
result.set_id(index);
- result.set_num_type_arguments(kUnknownNumTypeArguments);
+ result.set_num_type_arguments_unsafe(kUnknownNumTypeArguments);
result.set_num_native_fields(0);
result.set_state_bits(0);
NOT_IN_PRECOMPILED(result.set_kernel_offset(0));
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 7704001..01cfb33 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -1677,7 +1677,10 @@
// Initial value for the cached number of type arguments.
static const intptr_t kUnknownNumTypeArguments = -1;
- int16_t num_type_arguments() const { return untag()->num_type_arguments_; }
+ int16_t num_type_arguments() const {
+ return LoadNonPointer<int16_t, std::memory_order_relaxed>(
+ &untag()->num_type_arguments_);
+ }
uint32_t state_bits() const {
// Ensure any following load instructions do not get performed before this
@@ -1688,6 +1691,7 @@
public:
void set_num_type_arguments(intptr_t value) const;
+ void set_num_type_arguments_unsafe(intptr_t value) const;
bool has_pragma() const { return HasPragmaBit::decode(state_bits()); }
void set_has_pragma(bool has_pragma) const;
diff --git a/runtime/vm/object_store.cc b/runtime/vm/object_store.cc
index 57343da..1f75699 100644
--- a/runtime/vm/object_store.cc
+++ b/runtime/vm/object_store.cc
@@ -281,6 +281,10 @@
cls.LookupFactoryAllowPrivate(Symbols::_GrowableListFactory());
ASSERT(growable_list_factory_ != Function::null());
+ cls = core_lib.LookupClassAllowPrivate(Symbols::Error());
+ ASSERT(!cls.IsNull());
+ set_error_class(cls);
+
// Cache the core private functions used for fast instance of checks.
simple_instance_of_function_ =
PrivateObjectLookup(Symbols::_simpleInstanceOf());
diff --git a/runtime/vm/virtual_memory_compressed.h b/runtime/vm/virtual_memory_compressed.h
index 9b55243..95f4d52 100644
--- a/runtime/vm/virtual_memory_compressed.h
+++ b/runtime/vm/virtual_memory_compressed.h
@@ -5,18 +5,13 @@
#ifndef RUNTIME_VM_VIRTUAL_MEMORY_COMPRESSED_H_
#define RUNTIME_VM_VIRTUAL_MEMORY_COMPRESSED_H_
-#if defined(DART_COMPRESSED_POINTERS) && !defined(HOST_OS_FUCHSIA)
-#define DART_COMPRESSED_HEAP
-#endif // defined(DART_COMPRESSED_POINTERS) && !defined(HOST_OS_FUCHSIA)
-
-#if defined(DART_COMPRESSED_HEAP)
-
#include "vm/globals.h"
#include "vm/heap/pages.h"
#include "vm/memory_region.h"
namespace dart {
+#if defined(DART_COMPRESSED_POINTERS)
static constexpr intptr_t kCompressedHeapSize = 2 * GB;
static constexpr intptr_t kCompressedHeapAlignment = 4 * GB;
static constexpr intptr_t kCompressedHeapPageSize = kOldPageSize;
@@ -25,6 +20,13 @@
static constexpr intptr_t kCompressedHeapBitmapSize =
kCompressedHeapNumPages / 8;
+#if !defined(HOST_OS_FUCHSIA)
+#define DART_COMPRESSED_HEAP
+#endif // !defined(HOST_OS_FUCHSIA)
+#endif // defined(DART_COMPRESSED_POINTERS)
+
+#if defined(DART_COMPRESSED_HEAP)
+
// Utilities for allocating memory within a contiguous region of memory, for use
// with compressed pointers.
class VirtualMemoryCompressedHeap : public AllStatic {
@@ -61,8 +63,8 @@
static Mutex* mutex_;
};
-} // namespace dart
-
#endif // defined(DART_COMPRESSED_HEAP)
+} // namespace dart
+
#endif // RUNTIME_VM_VIRTUAL_MEMORY_COMPRESSED_H_
diff --git a/runtime/vm/virtual_memory_fuchsia.cc b/runtime/vm/virtual_memory_fuchsia.cc
index a5a6d14..731b86d 100644
--- a/runtime/vm/virtual_memory_fuchsia.cc
+++ b/runtime/vm/virtual_memory_fuchsia.cc
@@ -21,6 +21,7 @@
#include "vm/memory_region.h"
#include "vm/os.h"
#include "vm/os_thread.h"
+#include "vm/virtual_memory_compressed.h"
// #define VIRTUAL_MEMORY_LOGGING 1
#if defined(VIRTUAL_MEMORY_LOGGING)
@@ -40,6 +41,11 @@
uword VirtualMemory::page_size_ = 0;
+#if defined(DART_COMPRESSED_POINTERS)
+static zx_handle_t compressed_heap_vmar_ = ZX_HANDLE_INVALID;
+static uword compressed_heap_base_ = 0;
+#endif // defined(DART_COMPRESSED_POINTERS)
+
intptr_t VirtualMemory::CalculatePageSize() {
const intptr_t page_size = getpagesize();
ASSERT(page_size != 0);
@@ -48,10 +54,45 @@
}
void VirtualMemory::Init() {
+#if defined(DART_COMPRESSED_POINTERS)
+ if (compressed_heap_vmar_ == ZX_HANDLE_INVALID) {
+ const zx_vm_option_t align_flag =
+ Utils::ShiftForPowerOfTwo(kCompressedHeapAlignment) << ZX_VM_ALIGN_BASE;
+ const zx_vm_option_t options = ZX_VM_CAN_MAP_READ | ZX_VM_CAN_MAP_WRITE |
+ ZX_VM_CAN_MAP_SPECIFIC | align_flag;
+ zx_vaddr_t region;
+ zx_status_t status =
+ zx_vmar_allocate(zx_vmar_root_self(), options, 0, kCompressedHeapSize,
+ &compressed_heap_vmar_, ®ion);
+ if (status != ZX_OK) {
+ LOG_ERR("zx_vmar_allocate(0x%lx) failed: %s\n", kCompressedHeapSize,
+ zx_status_get_string(status));
+ } else {
+ compressed_heap_base_ = reinterpret_cast<uword>(region);
+ ASSERT(Utils::IsAligned(compressed_heap_base_, kCompressedHeapAlignment));
+ }
+ }
+#endif // defined(DART_COMPRESSED_POINTERS)
+
page_size_ = CalculatePageSize();
}
-void VirtualMemory::Cleanup() {}
+void VirtualMemory::Cleanup() {
+#if defined(DART_COMPRESSED_POINTERS)
+ zx_vmar_destroy(compressed_heap_vmar_);
+ compressed_heap_vmar_ = ZX_HANDLE_INVALID;
+ compressed_heap_base_ = 0;
+#endif // defined(DART_COMPRESSED_POINTERS)
+}
+
+static zx_handle_t getVmarForAddress(uword address) {
+#if defined(DART_COMPRESSED_POINTERS)
+ if (address - compressed_heap_base_ < kCompressedHeapSize) {
+ return compressed_heap_vmar_;
+ }
+#endif // defined(DART_COMPRESSED_POINTERS)
+ return zx_vmar_root_self();
+}
static void Unmap(zx_handle_t vmar, uword start, uword end) {
ASSERT(start <= end);
@@ -94,7 +135,12 @@
<< ZX_VM_ALIGN_BASE;
ASSERT((ZX_VM_ALIGN_1KB <= align_flag) && (align_flag <= ZX_VM_ALIGN_4GB));
+#if defined(DART_COMPRESSED_POINTERS)
+ zx_handle_t vmar =
+ is_executable ? zx_vmar_root_self() : compressed_heap_vmar_;
+#else
zx_handle_t vmar = zx_vmar_root_self();
+#endif // defined(DART_COMPRESSED_POINTERS)
zx_handle_t vmo = ZX_HANDLE_INVALID;
zx_status_t status = zx_vmo_create(size, 0u, &vmo);
if (status != ZX_OK) {
@@ -156,20 +202,29 @@
result = new VirtualMemory(region, region, region);
}
zx_handle_close(vmo);
+
+#if defined(DART_COMPRESSED_POINTERS)
+ if (!is_executable) {
+ uword offset = result->start() - compressed_heap_base_;
+ ASSERT(offset < kCompressedHeapSize);
+ }
+#endif // defined(DART_COMPRESSED_POINTERS)
+
return result;
}
VirtualMemory::~VirtualMemory() {
// Reserved region may be empty due to VirtualMemory::Truncate.
if (vm_owns_region() && reserved_.size() != 0) {
- Unmap(zx_vmar_root_self(), reserved_.start(), reserved_.end());
+ Unmap(getVmarForAddress(reserved_.start()), reserved_.start(),
+ reserved_.end());
LOG_INFO("zx_vmar_unmap(0x%lx, 0x%lx) success\n", reserved_.start(),
reserved_.size());
const intptr_t alias_offset = AliasOffset();
if (alias_offset != 0) {
- Unmap(zx_vmar_root_self(), reserved_.start() + alias_offset,
- reserved_.end() + alias_offset);
+ Unmap(getVmarForAddress(reserved_.start()),
+ reserved_.start() + alias_offset, reserved_.end() + alias_offset);
LOG_INFO("zx_vmar_unmap(0x%lx, 0x%lx) success\n",
reserved_.start() + alias_offset, reserved_.size());
}
@@ -178,7 +233,7 @@
bool VirtualMemory::FreeSubSegment(void* address, intptr_t size) {
const uword start = reinterpret_cast<uword>(address);
- Unmap(zx_vmar_root_self(), start, start + size);
+ Unmap(getVmarForAddress(start), start, start + size);
LOG_INFO("zx_vmar_unmap(0x%p, 0x%lx) success\n", address, size);
return true;
}
@@ -211,8 +266,9 @@
prot = ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_PERM_EXECUTE;
break;
}
- zx_status_t status = zx_vmar_protect(zx_vmar_root_self(), prot, page_address,
- end_address - page_address);
+ zx_status_t status =
+ zx_vmar_protect(getVmarForAddress(page_address), prot, page_address,
+ end_address - page_address);
LOG_INFO("zx_vmar_protect(%u, 0x%lx, 0x%lx)\n", prot, page_address,
end_address - page_address);
if (status != ZX_OK) {
diff --git a/tools/VERSION b/tools/VERSION
index 176ee19..e1365df 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 13
PATCH 0
-PRERELEASE 101
+PRERELEASE 102
PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/gn.py b/tools/gn.py
index 336b1df..6f2b0c1 100755
--- a/tools/gn.py
+++ b/tools/gn.py
@@ -331,7 +331,10 @@
"Cross-compilation to %s is not supported on host os %s." %
(os_name, HOST_OS))
return False
- if not arch in ['ia32', 'x64', 'arm', 'arm_x64', 'armv6', 'arm64']:
+ if not arch in [
+ 'ia32', 'x64', 'arm', 'arm_x64', 'armv6', 'arm64', 'x64c',
+ 'arm64c'
+ ]:
print(
"Cross-compilation to %s is not supported for architecture %s."
% (os_name, arch))
@@ -342,7 +345,7 @@
"Cross-compilation to %s is not supported on host os %s." %
(os_name, HOST_OS))
return False
- if arch != 'x64' and arch != 'arm64':
+ if not arch in ['x64', 'arm64', 'x64c', 'arm64c']:
print(
"Cross-compilation to %s is not supported for architecture %s."
% (os_name, arch))