mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 09:31:58 +00:00
[cfe] Split ensureAssignableResult into coersion and error reporting
It allows to use coersion without error reporting in the inference of record literals, which makes the difference when the record patterns are involved. Closes https://github.com/dart-lang/sdk/issues/51587 Part of https://github.com/dart-lang/sdk/issues/49749 Change-Id: I64ea7e82eb3bc14d4410a47c6ed6ef278e092496 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/290529 Reviewed-by: Johnni Winther <johnniwinther@google.com> Commit-Queue: Chloe Stefantsova <cstefantsova@google.com>
This commit is contained in:
parent
6b4878b55f
commit
2eba00fabb
|
@ -9146,7 +9146,8 @@ class InferenceVisitorImpl extends InferenceVisitorBase
|
|||
inferExpression(expression, contextType);
|
||||
if (contextType is! UnknownType) {
|
||||
expressionResult =
|
||||
ensureAssignableResult(contextType, expressionResult);
|
||||
coerceExpressionForAssignment(contextType, expressionResult) ??
|
||||
expressionResult;
|
||||
}
|
||||
|
||||
positionalTypes.add(
|
||||
|
@ -9194,7 +9195,8 @@ class InferenceVisitorImpl extends InferenceVisitorBase
|
|||
inferExpression(element.value, contextType);
|
||||
if (contextType is! UnknownType) {
|
||||
expressionResult =
|
||||
ensureAssignableResult(contextType, expressionResult);
|
||||
coerceExpressionForAssignment(contextType, expressionResult) ??
|
||||
expressionResult;
|
||||
}
|
||||
Expression expression = expressionResult.expression;
|
||||
DartType type = expressionResult.postCoercionType ??
|
||||
|
@ -9225,7 +9227,8 @@ class InferenceVisitorImpl extends InferenceVisitorBase
|
|||
inferExpression(element as Expression, contextType);
|
||||
if (contextType is! UnknownType) {
|
||||
expressionResult =
|
||||
ensureAssignableResult(contextType, expressionResult);
|
||||
coerceExpressionForAssignment(contextType, expressionResult) ??
|
||||
expressionResult;
|
||||
}
|
||||
Expression expression = expressionResult.expression;
|
||||
DartType type = expressionResult.postCoercionType ??
|
||||
|
|
|
@ -445,16 +445,102 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
|
|||
.expression;
|
||||
}
|
||||
|
||||
/// Same as [ensureAssignable], but accepts an [ExpressionInferenceResult]
|
||||
/// rather than an expression and a type separately. If no change is made,
|
||||
/// [inferenceResult] is returned unchanged.
|
||||
ExpressionInferenceResult ensureAssignableResult(
|
||||
/// Coerces expression ensuring its assignability to [contextType]
|
||||
///
|
||||
/// If the expression is assignable without coercion, [inferenceResult]
|
||||
/// is returned unchanged. If no coercion is possible for the given types,
|
||||
/// `null` is returned.
|
||||
ExpressionInferenceResult? coerceExpressionForAssignment(
|
||||
DartType contextType, ExpressionInferenceResult inferenceResult,
|
||||
{int? fileOffset,
|
||||
DartType? declaredContextType,
|
||||
DartType? runtimeCheckedType,
|
||||
bool isVoidAllowed = false,
|
||||
bool coerceExpression = true,
|
||||
bool coerceExpression = true}) {
|
||||
// ignore: unnecessary_null_comparison
|
||||
assert(contextType != null);
|
||||
|
||||
fileOffset ??= inferenceResult.expression.fileOffset;
|
||||
contextType = computeGreatestClosure(contextType);
|
||||
|
||||
DartType initialContextType = runtimeCheckedType ?? contextType;
|
||||
|
||||
Template<Message Function(DartType, DartType, bool)>?
|
||||
preciseTypeErrorTemplate =
|
||||
_getPreciseTypeErrorTemplate(inferenceResult.expression);
|
||||
AssignabilityResult assignabilityResult = _computeAssignabilityKind(
|
||||
contextType, inferenceResult.inferredType,
|
||||
isNonNullableByDefault: isNonNullableByDefault,
|
||||
isVoidAllowed: isVoidAllowed,
|
||||
isExpressionTypePrecise: preciseTypeErrorTemplate != null,
|
||||
coerceExpression: coerceExpression);
|
||||
|
||||
if (assignabilityResult.needsTearOff) {
|
||||
TypedTearoff typedTearoff = _tearOffCall(inferenceResult.expression,
|
||||
inferenceResult.inferredType as InterfaceType, fileOffset);
|
||||
inferenceResult = new ExpressionInferenceResult(
|
||||
typedTearoff.tearoffType, typedTearoff.tearoff);
|
||||
}
|
||||
if (assignabilityResult.implicitInstantiation != null) {
|
||||
inferenceResult = _applyImplicitInstantiation(
|
||||
assignabilityResult.implicitInstantiation,
|
||||
inferenceResult.inferredType,
|
||||
inferenceResult.expression);
|
||||
}
|
||||
|
||||
DartType expressionType = inferenceResult.inferredType;
|
||||
Expression expression = inferenceResult.expression;
|
||||
switch (assignabilityResult.kind) {
|
||||
case AssignabilityKind.assignable:
|
||||
return inferenceResult;
|
||||
case AssignabilityKind.assignableCast:
|
||||
// Insert an implicit downcast.
|
||||
Expression asExpression =
|
||||
new AsExpression(expression, initialContextType)
|
||||
..isTypeError = true
|
||||
..isForNonNullableByDefault = isNonNullableByDefault
|
||||
..isForDynamic = expressionType is DynamicType
|
||||
..fileOffset = fileOffset;
|
||||
flowAnalysis.forwardExpression(asExpression, expression);
|
||||
return new ExpressionInferenceResult(expressionType, asExpression,
|
||||
postCoercionType: initialContextType);
|
||||
case AssignabilityKind.unassignable:
|
||||
// Error: not assignable. Perform error recovery.
|
||||
return null;
|
||||
case AssignabilityKind.unassignableVoid:
|
||||
// Error: not assignable. Perform error recovery.
|
||||
return null;
|
||||
case AssignabilityKind.unassignablePrecise:
|
||||
// The type of the expression is known precisely, so an implicit
|
||||
// downcast is guaranteed to fail. Insert a compile-time error.
|
||||
return null;
|
||||
case AssignabilityKind.unassignableCantTearoff:
|
||||
return null;
|
||||
case AssignabilityKind.unassignableNullability:
|
||||
return null;
|
||||
default:
|
||||
return unhandled("${assignabilityResult}", "ensureAssignable",
|
||||
fileOffset, helper.uri);
|
||||
}
|
||||
}
|
||||
|
||||
/// Performs assignability checks on an expression
|
||||
///
|
||||
/// [inferenceResult.expression] of type [inferenceResult.inferredType] is
|
||||
/// checked for assignability to [contextType]. The errors are reported on the
|
||||
/// current library and the expression wrapped in an [InvalidExpression], if
|
||||
/// needed. If no change is made, [inferenceResult] is returned unchanged.
|
||||
///
|
||||
/// If [isCoercionAllowed] is `true`, the assignability check is made
|
||||
/// accounting for a possible coercion that may adjust the type of the
|
||||
/// expression.
|
||||
ExpressionInferenceResult reportAssignabilityErrors(
|
||||
DartType contextType, ExpressionInferenceResult inferenceResult,
|
||||
{int? fileOffset,
|
||||
DartType? declaredContextType,
|
||||
DartType? runtimeCheckedType,
|
||||
bool isVoidAllowed = false,
|
||||
bool isCoercionAllowed = true,
|
||||
Template<Message Function(DartType, DartType, bool)>? errorTemplate,
|
||||
Template<Message Function(DartType, DartType, bool)>?
|
||||
nullabilityErrorTemplate,
|
||||
|
@ -492,8 +578,6 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
|
|||
fileOffset ??= inferenceResult.expression.fileOffset;
|
||||
contextType = computeGreatestClosure(contextType);
|
||||
|
||||
DartType initialContextType = runtimeCheckedType ?? contextType;
|
||||
|
||||
Template<Message Function(DartType, DartType, bool)>?
|
||||
preciseTypeErrorTemplate =
|
||||
_getPreciseTypeErrorTemplate(inferenceResult.expression);
|
||||
|
@ -502,7 +586,7 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
|
|||
isNonNullableByDefault: isNonNullableByDefault,
|
||||
isVoidAllowed: isVoidAllowed,
|
||||
isExpressionTypePrecise: preciseTypeErrorTemplate != null,
|
||||
coerceExpression: coerceExpression);
|
||||
coerceExpression: isCoercionAllowed);
|
||||
|
||||
if (assignabilityResult.needsTearOff) {
|
||||
TypedTearoff typedTearoff = _tearOffCall(inferenceResult.expression,
|
||||
|
@ -519,20 +603,12 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
|
|||
|
||||
DartType expressionType = inferenceResult.inferredType;
|
||||
Expression expression = inferenceResult.expression;
|
||||
Expression result;
|
||||
DartType? postCoercionType;
|
||||
DartType? postCoercionType = inferenceResult.postCoercionType;
|
||||
Expression? result;
|
||||
switch (assignabilityResult.kind) {
|
||||
case AssignabilityKind.assignable:
|
||||
result = expression;
|
||||
break;
|
||||
case AssignabilityKind.assignableCast:
|
||||
// Insert an implicit downcast.
|
||||
result = new AsExpression(expression, initialContextType)
|
||||
..isTypeError = true
|
||||
..isForNonNullableByDefault = isNonNullableByDefault
|
||||
..isForDynamic = expressionType is DynamicType
|
||||
..fileOffset = fileOffset;
|
||||
postCoercionType = initialContextType;
|
||||
break;
|
||||
case AssignabilityKind.unassignable:
|
||||
// Error: not assignable. Perform error recovery.
|
||||
|
@ -615,7 +691,7 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
|
|||
fileOffset, helper.uri);
|
||||
}
|
||||
|
||||
if (!identical(result, expression)) {
|
||||
if (result != null) {
|
||||
flowAnalysis.forwardExpression(result, expression);
|
||||
return new ExpressionInferenceResult(expressionType, result,
|
||||
postCoercionType: postCoercionType);
|
||||
|
@ -624,6 +700,57 @@ abstract class InferenceVisitorBase implements InferenceVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
/// Same as [ensureAssignable], but accepts an [ExpressionInferenceResult]
|
||||
/// rather than an expression and a type separately. If no change is made,
|
||||
/// [inferenceResult] is returned unchanged.
|
||||
ExpressionInferenceResult ensureAssignableResult(
|
||||
DartType contextType, ExpressionInferenceResult inferenceResult,
|
||||
{int? fileOffset,
|
||||
DartType? declaredContextType,
|
||||
DartType? runtimeCheckedType,
|
||||
bool isVoidAllowed = false,
|
||||
bool coerceExpression = true,
|
||||
Template<Message Function(DartType, DartType, bool)>? errorTemplate,
|
||||
Template<Message Function(DartType, DartType, bool)>?
|
||||
nullabilityErrorTemplate,
|
||||
Template<Message Function(DartType, bool)>? nullabilityNullErrorTemplate,
|
||||
Template<Message Function(DartType, DartType, bool)>?
|
||||
nullabilityNullTypeErrorTemplate,
|
||||
Template<Message Function(DartType, DartType, DartType, DartType, bool)>?
|
||||
nullabilityPartErrorTemplate,
|
||||
Map<DartType, NonPromotionReason> Function()? whyNotPromoted}) {
|
||||
// ignore: unnecessary_null_comparison
|
||||
assert(contextType != null);
|
||||
|
||||
if (coerceExpression) {
|
||||
ExpressionInferenceResult? coercionResult = coerceExpressionForAssignment(
|
||||
contextType, inferenceResult,
|
||||
fileOffset: fileOffset,
|
||||
declaredContextType: declaredContextType,
|
||||
runtimeCheckedType: runtimeCheckedType,
|
||||
isVoidAllowed: isVoidAllowed,
|
||||
coerceExpression: coerceExpression);
|
||||
if (coercionResult != null) {
|
||||
return coercionResult;
|
||||
}
|
||||
}
|
||||
|
||||
inferenceResult = reportAssignabilityErrors(contextType, inferenceResult,
|
||||
fileOffset: fileOffset,
|
||||
declaredContextType: declaredContextType,
|
||||
runtimeCheckedType: runtimeCheckedType,
|
||||
isVoidAllowed: isVoidAllowed,
|
||||
isCoercionAllowed: coerceExpression,
|
||||
errorTemplate: errorTemplate,
|
||||
nullabilityErrorTemplate: nullabilityErrorTemplate,
|
||||
nullabilityNullErrorTemplate: nullabilityNullErrorTemplate,
|
||||
nullabilityNullTypeErrorTemplate: nullabilityNullTypeErrorTemplate,
|
||||
nullabilityPartErrorTemplate: nullabilityPartErrorTemplate,
|
||||
whyNotPromoted: whyNotPromoted);
|
||||
|
||||
return inferenceResult;
|
||||
}
|
||||
|
||||
Expression _wrapTearoffErrorExpression(Expression expression,
|
||||
DartType contextType, Template<Message Function(String)> template) {
|
||||
// ignore: unnecessary_null_comparison
|
||||
|
|
|
@ -495,6 +495,7 @@ clue
|
|||
code
|
||||
coerce
|
||||
coerced
|
||||
coerces
|
||||
coercing
|
||||
coercion
|
||||
coincides
|
||||
|
|
27
pkg/front_end/testcases/patterns/issue51587.dart
Normal file
27
pkg/front_end/testcases/patterns/issue51587.dart
Normal file
|
@ -0,0 +1,27 @@
|
|||
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
test1() {
|
||||
num b = 0;
|
||||
b as int;
|
||||
b.isEven;
|
||||
(b,) = (3.14,);
|
||||
return b;
|
||||
}
|
||||
|
||||
test2() {
|
||||
num b = 0;
|
||||
b as int;
|
||||
b.isEven;
|
||||
(b, foo: _) = (3.14, foo: "foo");
|
||||
return b;
|
||||
}
|
||||
|
||||
test3() {
|
||||
num b = 0;
|
||||
b as int;
|
||||
b.isEven;
|
||||
(foo: b) = (foo: 3.14);
|
||||
return b;
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
library /*isNonNullableByDefault*/;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
import "dart:_internal" as _in;
|
||||
|
||||
static method test1() → dynamic {
|
||||
core::num b = 0;
|
||||
b as{ForNonNullableByDefault} core::int;
|
||||
b{core::int}.{core::int::isEven}{core::bool};
|
||||
block {
|
||||
final synthesized dynamic #0#0 = (3.14);
|
||||
if(!(let final dynamic #t1 = b = #0#0{(core::double)}.$1{core::double} in true))
|
||||
throw new _in::ReachabilityError::•();
|
||||
} =>#0#0;
|
||||
return b;
|
||||
}
|
||||
static method test2() → dynamic {
|
||||
core::num b = 0;
|
||||
b as{ForNonNullableByDefault} core::int;
|
||||
b{core::int}.{core::int::isEven}{core::bool};
|
||||
block {
|
||||
final synthesized dynamic #0#0 = (3.14, {foo: "foo"});
|
||||
if(!((let final dynamic #t2 = b = #0#0{(core::double, {foo: core::String})}.$1{core::double} in true) && true))
|
||||
throw new _in::ReachabilityError::•();
|
||||
} =>#0#0;
|
||||
return b;
|
||||
}
|
||||
static method test3() → dynamic {
|
||||
core::num b = 0;
|
||||
b as{ForNonNullableByDefault} core::int;
|
||||
b{core::int}.{core::int::isEven}{core::bool};
|
||||
block {
|
||||
final synthesized dynamic #0#0 = ({foo: 3.14});
|
||||
if(!(let final dynamic #t3 = b = #0#0{({foo: core::double})}.foo{core::double} in true))
|
||||
throw new _in::ReachabilityError::•();
|
||||
} =>#0#0;
|
||||
return b;
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
library /*isNonNullableByDefault*/;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
import "dart:_internal" as _in;
|
||||
|
||||
static method test1() → dynamic {
|
||||
core::num b = 0;
|
||||
b as{ForNonNullableByDefault} core::int;
|
||||
b{core::int}.{core::int::isEven}{core::bool};
|
||||
block {
|
||||
final synthesized dynamic #0#0 = (3.14);
|
||||
if(!(let final core::double #t1 = b = #0#0{(core::double)}.$1{core::double} in true))
|
||||
throw new _in::ReachabilityError::•();
|
||||
} =>#0#0;
|
||||
return b;
|
||||
}
|
||||
static method test2() → dynamic {
|
||||
core::num b = 0;
|
||||
b as{ForNonNullableByDefault} core::int;
|
||||
b{core::int}.{core::int::isEven}{core::bool};
|
||||
block {
|
||||
final synthesized dynamic #0#0 = (3.14, {foo: "foo"});
|
||||
if(!((let final core::double #t2 = b = #0#0{(core::double, {foo: core::String})}.$1{core::double} in true) && true))
|
||||
throw new _in::ReachabilityError::•();
|
||||
} =>#0#0;
|
||||
return b;
|
||||
}
|
||||
static method test3() → dynamic {
|
||||
core::num b = 0;
|
||||
b as{ForNonNullableByDefault} core::int;
|
||||
b{core::int}.{core::int::isEven}{core::bool};
|
||||
block {
|
||||
final synthesized dynamic #0#0 = ({foo: 3.14});
|
||||
if(!(let final core::double #t3 = b = #0#0{({foo: core::double})}.foo{core::double} in true))
|
||||
throw new _in::ReachabilityError::•();
|
||||
} =>#0#0;
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
Extra constant evaluation status:
|
||||
Evaluated: RecordLiteral @ org-dartlang-testcase:///issue51587.dart:9:10 -> RecordConstant(const (3.14))
|
||||
Evaluated: RecordLiteral @ org-dartlang-testcase:///issue51587.dart:17:17 -> RecordConstant(const (3.14, {foo: "foo"}))
|
||||
Evaluated: RecordLiteral @ org-dartlang-testcase:///issue51587.dart:25:14 -> RecordConstant(const ({foo: 3.14}))
|
||||
Extra constant evaluation: evaluated: 46, effectively constant: 3
|
|
@ -0,0 +1,3 @@
|
|||
test1() {}
|
||||
test2() {}
|
||||
test3() {}
|
|
@ -0,0 +1,3 @@
|
|||
test1() {}
|
||||
test2() {}
|
||||
test3() {}
|
38
pkg/front_end/testcases/patterns/issue51587.dart.weak.expect
Normal file
38
pkg/front_end/testcases/patterns/issue51587.dart.weak.expect
Normal file
|
@ -0,0 +1,38 @@
|
|||
library /*isNonNullableByDefault*/;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
import "dart:_internal" as _in;
|
||||
|
||||
static method test1() → dynamic {
|
||||
core::num b = 0;
|
||||
b as{ForNonNullableByDefault} core::int;
|
||||
b{core::int}.{core::int::isEven}{core::bool};
|
||||
block {
|
||||
final synthesized dynamic #0#0 = (3.14);
|
||||
if(!(let final dynamic #t1 = b = #0#0{(core::double)}.$1{core::double} in true))
|
||||
throw new _in::ReachabilityError::•();
|
||||
} =>#0#0;
|
||||
return b;
|
||||
}
|
||||
static method test2() → dynamic {
|
||||
core::num b = 0;
|
||||
b as{ForNonNullableByDefault} core::int;
|
||||
b{core::int}.{core::int::isEven}{core::bool};
|
||||
block {
|
||||
final synthesized dynamic #0#0 = (3.14, {foo: "foo"});
|
||||
if(!((let final dynamic #t2 = b = #0#0{(core::double, {foo: core::String})}.$1{core::double} in true) && true))
|
||||
throw new _in::ReachabilityError::•();
|
||||
} =>#0#0;
|
||||
return b;
|
||||
}
|
||||
static method test3() → dynamic {
|
||||
core::num b = 0;
|
||||
b as{ForNonNullableByDefault} core::int;
|
||||
b{core::int}.{core::int::isEven}{core::bool};
|
||||
block {
|
||||
final synthesized dynamic #0#0 = ({foo: 3.14});
|
||||
if(!(let final dynamic #t3 = b = #0#0{({foo: core::double})}.foo{core::double} in true))
|
||||
throw new _in::ReachabilityError::•();
|
||||
} =>#0#0;
|
||||
return b;
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
library /*isNonNullableByDefault*/;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
import "dart:_internal" as _in;
|
||||
|
||||
static method test1() → dynamic {
|
||||
core::num b = 0;
|
||||
b as{ForNonNullableByDefault} core::int;
|
||||
b{core::int}.{core::int::isEven}{core::bool};
|
||||
block {
|
||||
final synthesized dynamic #0#0 = (3.14);
|
||||
if(!(let final dynamic #t1 = b = #0#0{(core::double)}.$1{core::double} in true))
|
||||
throw new _in::ReachabilityError::•();
|
||||
} =>#0#0;
|
||||
return b;
|
||||
}
|
||||
static method test2() → dynamic {
|
||||
core::num b = 0;
|
||||
b as{ForNonNullableByDefault} core::int;
|
||||
b{core::int}.{core::int::isEven}{core::bool};
|
||||
block {
|
||||
final synthesized dynamic #0#0 = (3.14, {foo: "foo"});
|
||||
if(!((let final dynamic #t2 = b = #0#0{(core::double, {foo: core::String})}.$1{core::double} in true) && true))
|
||||
throw new _in::ReachabilityError::•();
|
||||
} =>#0#0;
|
||||
return b;
|
||||
}
|
||||
static method test3() → dynamic {
|
||||
core::num b = 0;
|
||||
b as{ForNonNullableByDefault} core::int;
|
||||
b{core::int}.{core::int::isEven}{core::bool};
|
||||
block {
|
||||
final synthesized dynamic #0#0 = ({foo: 3.14});
|
||||
if(!(let final dynamic #t3 = b = #0#0{({foo: core::double})}.foo{core::double} in true))
|
||||
throw new _in::ReachabilityError::•();
|
||||
} =>#0#0;
|
||||
return b;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
library /*isNonNullableByDefault*/;
|
||||
import self as self;
|
||||
|
||||
static method test1() → dynamic
|
||||
;
|
||||
static method test2() → dynamic
|
||||
;
|
||||
static method test3() → dynamic
|
||||
;
|
|
@ -0,0 +1,45 @@
|
|||
library /*isNonNullableByDefault*/;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
import "dart:_internal" as _in;
|
||||
|
||||
static method test1() → dynamic {
|
||||
core::num b = 0;
|
||||
b as{ForNonNullableByDefault} core::int;
|
||||
b{core::int}.{core::int::isEven}{core::bool};
|
||||
block {
|
||||
final synthesized dynamic #0#0 = (3.14);
|
||||
if(!(let final core::double #t1 = b = #0#0{(core::double)}.$1{core::double} in true))
|
||||
throw new _in::ReachabilityError::•();
|
||||
} =>#0#0;
|
||||
return b;
|
||||
}
|
||||
static method test2() → dynamic {
|
||||
core::num b = 0;
|
||||
b as{ForNonNullableByDefault} core::int;
|
||||
b{core::int}.{core::int::isEven}{core::bool};
|
||||
block {
|
||||
final synthesized dynamic #0#0 = (3.14, {foo: "foo"});
|
||||
if(!((let final core::double #t2 = b = #0#0{(core::double, {foo: core::String})}.$1{core::double} in true) && true))
|
||||
throw new _in::ReachabilityError::•();
|
||||
} =>#0#0;
|
||||
return b;
|
||||
}
|
||||
static method test3() → dynamic {
|
||||
core::num b = 0;
|
||||
b as{ForNonNullableByDefault} core::int;
|
||||
b{core::int}.{core::int::isEven}{core::bool};
|
||||
block {
|
||||
final synthesized dynamic #0#0 = ({foo: 3.14});
|
||||
if(!(let final core::double #t3 = b = #0#0{({foo: core::double})}.foo{core::double} in true))
|
||||
throw new _in::ReachabilityError::•();
|
||||
} =>#0#0;
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
Extra constant evaluation status:
|
||||
Evaluated: RecordLiteral @ org-dartlang-testcase:///issue51587.dart:9:10 -> RecordConstant(const (3.14))
|
||||
Evaluated: RecordLiteral @ org-dartlang-testcase:///issue51587.dart:17:17 -> RecordConstant(const (3.14, {foo: "foo"}))
|
||||
Evaluated: RecordLiteral @ org-dartlang-testcase:///issue51587.dart:25:14 -> RecordConstant(const ({foo: 3.14}))
|
||||
Extra constant evaluation: evaluated: 46, effectively constant: 3
|
Loading…
Reference in a new issue