diff --git a/pkg/front_end/lib/src/type_inference/inference_visitor.dart b/pkg/front_end/lib/src/type_inference/inference_visitor.dart index 4fc0b16c997..09af5a8a16a 100644 --- a/pkg/front_end/lib/src/type_inference/inference_visitor.dart +++ b/pkg/front_end/lib/src/type_inference/inference_visitor.dart @@ -15004,77 +15004,70 @@ class InferenceVisitorImpl extends InferenceVisitorBase requiredType: requiredType, ); - DartType lookupType; if (node.needsCheck) { - lookupType = node.lookupType = requiredType; + node.lookupType = requiredType; } else { - lookupType = node.lookupType = matchedValueType; + node.lookupType = matchedValueType; } ObjectAccessTarget lengthTarget = findInterfaceMember( - lookupType, + requiredType, lengthName, node.fileOffset, includeExtensionMethods: true, isSetter: false, ); - DartType lengthType; - if (lengthTarget.isNever) { - lengthType = const NeverType.nonNullable(); - node.isNeverPattern = true; - } else { - assert(lengthTarget.isInstanceMember); + assert(lengthTarget.isInstanceMember); - lengthType = node.lengthType = lengthTarget.getGetterType(this); - node.lengthTarget = lengthTarget.classMember!; + DartType lengthType = node.lengthType = lengthTarget.getGetterType(this); + node.lengthTarget = lengthTarget.classMember!; - ObjectAccessTarget sublistInvokeTarget = findInterfaceMember( - lookupType, - sublistName, - node.fileOffset, - includeExtensionMethods: true, - isSetter: false, - ); - assert(sublistInvokeTarget.isInstanceMember); + ObjectAccessTarget sublistInvokeTarget = findInterfaceMember( + requiredType, + sublistName, + node.fileOffset, + includeExtensionMethods: true, + isSetter: false, + ); + assert(sublistInvokeTarget.isInstanceMember); - node.sublistTarget = sublistInvokeTarget.classMember as Procedure; - node.sublistType = sublistInvokeTarget - .getFunctionType(this) - .sublistFunctionType; + node.sublistTarget = sublistInvokeTarget.classMember as Procedure; + node.sublistType = sublistInvokeTarget + .getFunctionType(this) + .sublistFunctionType; - ObjectAccessTarget minusTarget = findInterfaceMember( + ObjectAccessTarget minusTarget = findInterfaceMember( + lengthType, + minusName, + node.fileOffset, + includeExtensionMethods: true, + isSetter: false, + ); + assert(minusTarget.isInstanceMember); + assert(minusTarget.isSpecialCasedBinaryOperator(this)); + + node.minusTarget = minusTarget.classMember as Procedure; + node.minusType = replaceReturnType( + minusTarget.getFunctionType(this).minusFunctionType, + typeSchemaEnvironment.getTypeOfSpecialCasedBinaryOperator( lengthType, - minusName, - node.fileOffset, - includeExtensionMethods: true, - isSetter: false, - ); - assert(minusTarget.isInstanceMember); - assert(minusTarget.isSpecialCasedBinaryOperator(this)); + coreTypes.intNonNullableRawType, + ), + ); - node.minusTarget = minusTarget.classMember as Procedure; - node.minusType = replaceReturnType( - minusTarget.getFunctionType(this).minusFunctionType, - typeSchemaEnvironment.getTypeOfSpecialCasedBinaryOperator( - lengthType, - coreTypes.intNonNullableRawType, - ), - ); + ObjectAccessTarget indexGetTarget = findInterfaceMember( + requiredType, + indexGetName, + node.fileOffset, + includeExtensionMethods: true, + isSetter: false, + ); + assert(indexGetTarget.isInstanceMember); - ObjectAccessTarget indexGetTarget = findInterfaceMember( - lookupType, - indexGetName, - node.fileOffset, - includeExtensionMethods: true, - isSetter: false, - ); - assert(indexGetTarget.isInstanceMember); - - node.indexGetTarget = indexGetTarget.classMember as Procedure; - node.indexGetType = indexGetTarget - .getFunctionType(this) - .indexGetFunctionType; - } + node.indexGetTarget = indexGetTarget.classMember as Procedure; + node.indexGetType = indexGetTarget + .getFunctionType(this) + .indexGetFunctionType; for (Pattern pattern in node.patterns) { if (pattern is RestPattern) { @@ -15083,52 +15076,50 @@ class InferenceVisitorImpl extends InferenceVisitorBase } } - if (!node.isNeverPattern) { - if (node.hasRestPattern) { - ObjectAccessTarget greaterThanOrEqualTarget = findInterfaceMember( - lengthType, - greaterThanOrEqualsName, - node.fileOffset, - includeExtensionMethods: true, - isSetter: false, - ); - assert(greaterThanOrEqualTarget.isInstanceMember); + if (node.hasRestPattern) { + ObjectAccessTarget greaterThanOrEqualTarget = findInterfaceMember( + lengthType, + greaterThanOrEqualsName, + node.fileOffset, + includeExtensionMethods: true, + isSetter: false, + ); + assert(greaterThanOrEqualTarget.isInstanceMember); - node.lengthCheckTarget = - greaterThanOrEqualTarget.classMember as Procedure; - node.lengthCheckType = greaterThanOrEqualTarget - .getFunctionType(this) - .greaterThanOrEqualsFunctionType; - } else if (node.patterns.isEmpty) { - ObjectAccessTarget lessThanOrEqualsInvokeTarget = findInterfaceMember( - lengthType, - lessThanOrEqualsName, - node.fileOffset, - includeExtensionMethods: true, - isSetter: false, - ); - assert(lessThanOrEqualsInvokeTarget.isInstanceMember); + node.lengthCheckTarget = + greaterThanOrEqualTarget.classMember as Procedure; + node.lengthCheckType = greaterThanOrEqualTarget + .getFunctionType(this) + .greaterThanOrEqualsFunctionType; + } else if (node.patterns.isEmpty) { + ObjectAccessTarget lessThanOrEqualsInvokeTarget = findInterfaceMember( + lengthType, + lessThanOrEqualsName, + node.fileOffset, + includeExtensionMethods: true, + isSetter: false, + ); + assert(lessThanOrEqualsInvokeTarget.isInstanceMember); - node.lengthCheckTarget = - lessThanOrEqualsInvokeTarget.classMember as Procedure; - node.lengthCheckType = lessThanOrEqualsInvokeTarget - .getFunctionType(this) - .lessThanOrEqualsFunctionType; - } else { - ObjectAccessTarget equalsInvokeTarget = findInterfaceMember( - lengthType, - equalsName, - node.fileOffset, - includeExtensionMethods: true, - isSetter: false, - ); - assert(equalsInvokeTarget.isInstanceMember); + node.lengthCheckTarget = + lessThanOrEqualsInvokeTarget.classMember as Procedure; + node.lengthCheckType = lessThanOrEqualsInvokeTarget + .getFunctionType(this) + .lessThanOrEqualsFunctionType; + } else { + ObjectAccessTarget equalsInvokeTarget = findInterfaceMember( + lengthType, + equalsName, + node.fileOffset, + includeExtensionMethods: true, + isSetter: false, + ); + assert(equalsInvokeTarget.isInstanceMember); - node.lengthCheckTarget = equalsInvokeTarget.classMember as Procedure; - node.lengthCheckType = equalsInvokeTarget - .getFunctionType(this) - .equalsFunctionType; - } + node.lengthCheckTarget = equalsInvokeTarget.classMember as Procedure; + node.lengthCheckType = equalsInvokeTarget + .getFunctionType(this) + .equalsFunctionType; } pushRewrite(replacement ?? node); @@ -15583,44 +15574,40 @@ class InferenceVisitorImpl extends InferenceVisitorBase requiredType: requiredType, ); - DartType lookupType; if (node.needsCheck) { - lookupType = node.lookupType = requiredType; + node.lookupType = requiredType; } else { - lookupType = node.lookupType = matchedValueType; + node.lookupType = matchedValueType; } ObjectAccessTarget containsKeyTarget = findInterfaceMember( - lookupType, + requiredType, containsKeyName, node.fileOffset, includeExtensionMethods: true, isSetter: false, ); - if (containsKeyTarget.isNever) { - node.isNeverPattern = true; - } else { - assert(containsKeyTarget.isInstanceMember); - node.containsKeyTarget = containsKeyTarget.classMember as Procedure; - node.containsKeyType = containsKeyTarget - .getFunctionType(this) - .containsKeyFunctionType; + assert(containsKeyTarget.isInstanceMember); - ObjectAccessTarget indexGetTarget = findInterfaceMember( - lookupType, - indexGetName, - node.fileOffset, - includeExtensionMethods: true, - isSetter: false, - ); - assert(indexGetTarget.isInstanceMember); + node.containsKeyTarget = containsKeyTarget.classMember as Procedure; + node.containsKeyType = containsKeyTarget + .getFunctionType(this) + .containsKeyFunctionType; - node.indexGetTarget = indexGetTarget.classMember as Procedure; - node.indexGetType = indexGetTarget - .getFunctionType(this) - .indexGetFunctionType; - } + ObjectAccessTarget indexGetTarget = findInterfaceMember( + requiredType, + indexGetName, + node.fileOffset, + includeExtensionMethods: true, + isSetter: false, + ); + assert(indexGetTarget.isInstanceMember); + + node.indexGetTarget = indexGetTarget.classMember as Procedure; + node.indexGetType = indexGetTarget + .getFunctionType(this) + .indexGetFunctionType; assert( checkStack(node, stackBase, [ diff --git a/pkg/front_end/lib/src/type_inference/matching_expressions.dart b/pkg/front_end/lib/src/type_inference/matching_expressions.dart index ee15fbcbfa7..0ae0f83370d 100644 --- a/pkg/front_end/lib/src/type_inference/matching_expressions.dart +++ b/pkg/front_end/lib/src/type_inference/matching_expressions.dart @@ -119,221 +119,212 @@ class MatchingExpressionVisitor ListPattern node, CacheableExpression matchedExpression, ) { - if (node.isNeverPattern) { - return matchedExpression; + matchedExpression = matchedExpression.promote(node.matchedValueType!); + + CacheableExpression? isExpression; + CacheableExpression typedMatchedExpression; + if (node.needsCheck) { + isExpression = matchingCache.createIsExpression( + matchedExpression, + node.requiredType!, + fileOffset: node.fileOffset, + ); + typedMatchedExpression = new PromotedCacheableExpression( + matchedExpression, + node.requiredType!, + ); } else { - matchedExpression = matchedExpression.promote(node.matchedValueType!); + typedMatchedExpression = matchedExpression; + } - CacheableExpression? isExpression; - CacheableExpression typedMatchedExpression; - if (node.needsCheck) { - isExpression = matchingCache.createIsExpression( - matchedExpression, - node.requiredType!, - fileOffset: node.fileOffset, - ); - typedMatchedExpression = new PromotedCacheableExpression( - matchedExpression, - node.requiredType!, - ); - } else { - typedMatchedExpression = matchedExpression; - } - - CacheableExpression lengthGet = matchingCache.createPropertyGetExpression( + CacheableExpression lengthGet = matchingCache.createPropertyGetExpression( + typedMatchedExpression, + lengthName.text, + new DelayedInstanceGet( typedMatchedExpression, - lengthName.text, - new DelayedInstanceGet( - typedMatchedExpression, - node.lengthTarget, - node.lengthType!, + node.lengthTarget, + node.lengthType!, + fileOffset: node.fileOffset, + ), + fileOffset: node.fileOffset, + ); + + CacheableExpression? lengthCheck; + if (node.hasRestPattern) { + int minLength = node.patterns.length - 1; + if (minLength > 0) { + CacheableExpression constExpression = matchingCache.createIntConstant( + minLength, fileOffset: node.fileOffset, - ), + ); + + lengthCheck = matchingCache.createComparisonExpression( + lengthGet, + greaterThanOrEqualsName.text, + constExpression, + new DelayedInstanceInvocation( + lengthGet, + node.lengthCheckTarget, + node.lengthCheckType!, + [constExpression], + fileOffset: node.fileOffset, + ), + fileOffset: node.fileOffset, + ); + } + } else { + int length = node.patterns.length; + CacheableExpression constExpression = matchingCache.createIntConstant( + length, fileOffset: node.fileOffset, ); - CacheableExpression? lengthCheck; - if (node.hasRestPattern) { - int minLength = node.patterns.length - 1; - if (minLength > 0) { - CacheableExpression constExpression = matchingCache.createIntConstant( - minLength, + if (length == 0) { + lengthCheck = matchingCache.createComparisonExpression( + lengthGet, + lessThanOrEqualsName.text, + constExpression, + new DelayedInstanceInvocation( + lengthGet, + node.lengthCheckTarget, + node.lengthCheckType!, + [constExpression], + fileOffset: node.fileOffset, + ), + fileOffset: node.fileOffset, + ); + } else { + lengthCheck = matchingCache.createEqualsExpression( + lengthGet, + constExpression, + new DelayedEqualsExpression( + lengthGet, + constExpression, + node.lengthCheckTarget, + node.lengthCheckType!, + fileOffset: node.fileOffset, + ), + fileOffset: node.fileOffset, + ); + } + } + + DelayedExpression? matchingExpression; + if (isExpression != null && lengthCheck != null) { + matchingExpression = matchingCache.createAndExpression( + isExpression, + lengthCheck, + fileOffset: node.fileOffset, + ); + } else if (isExpression != null) { + matchingExpression = isExpression; + } else if (lengthCheck != null) { + matchingExpression = lengthCheck; + } + + bool hasSeenRestPattern = false; + for (int i = 0; i < node.patterns.length; i++) { + CacheableExpression elementExpression; + Pattern elementPattern = node.patterns[i]; + if (elementPattern is RestPattern) { + hasSeenRestPattern = true; + Pattern? subPattern = elementPattern.subPattern; + if (subPattern == null) { + continue; + } + + int nextIndex = i + 1; + int headSize = i; + int tailSize = node.patterns.length - nextIndex; + + DelayedExpression expression; + if (tailSize > 0) { + expression = new DelayedInstanceInvocation( + typedMatchedExpression, + node.sublistTarget, + node.sublistType!, + [ + new IntegerExpression(headSize, fileOffset: node.fileOffset), + new DelayedInstanceInvocation( + lengthGet, + node.minusTarget, + node.minusType!, + [new IntegerExpression(tailSize, fileOffset: node.fileOffset)], + fileOffset: node.fileOffset, + ), + ], fileOffset: node.fileOffset, ); - - lengthCheck = matchingCache.createComparisonExpression( - lengthGet, - greaterThanOrEqualsName.text, - constExpression, - new DelayedInstanceInvocation( - lengthGet, - node.lengthCheckTarget, - node.lengthCheckType!, - [constExpression], - fileOffset: node.fileOffset, - ), + } else { + expression = new DelayedInstanceInvocation( + typedMatchedExpression, + node.sublistTarget, + node.sublistType!, + [new IntegerExpression(headSize, fileOffset: node.fileOffset)], fileOffset: node.fileOffset, ); } - } else { - int length = node.patterns.length; - CacheableExpression constExpression = matchingCache.createIntConstant( - length, + elementExpression = matchingCache.createSublistExpression( + typedMatchedExpression, + lengthGet, + headSize, + tailSize, + expression, fileOffset: node.fileOffset, ); - - if (length == 0) { - lengthCheck = matchingCache.createComparisonExpression( - lengthGet, - lessThanOrEqualsName.text, - constExpression, + } else { + if (!hasSeenRestPattern) { + int index = i; + elementExpression = matchingCache.createHeadIndexExpression( + typedMatchedExpression, + index, new DelayedInstanceInvocation( - lengthGet, - node.lengthCheckTarget, - node.lengthCheckType!, - [constExpression], + typedMatchedExpression, + node.indexGetTarget, + node.indexGetType!, + [new IntegerExpression(index, fileOffset: node.fileOffset)], fileOffset: node.fileOffset, ), fileOffset: node.fileOffset, ); } else { - lengthCheck = matchingCache.createEqualsExpression( + int index = node.patterns.length - i; + elementExpression = matchingCache.createTailIndexExpression( + typedMatchedExpression, lengthGet, - constExpression, - new DelayedEqualsExpression( - lengthGet, - constExpression, - node.lengthCheckTarget, - node.lengthCheckType!, - fileOffset: node.fileOffset, - ), - fileOffset: node.fileOffset, - ); - } - } - - DelayedExpression? matchingExpression; - if (isExpression != null && lengthCheck != null) { - matchingExpression = matchingCache.createAndExpression( - isExpression, - lengthCheck, - fileOffset: node.fileOffset, - ); - } else if (isExpression != null) { - matchingExpression = isExpression; - } else if (lengthCheck != null) { - matchingExpression = lengthCheck; - } - - bool hasSeenRestPattern = false; - for (int i = 0; i < node.patterns.length; i++) { - CacheableExpression elementExpression; - Pattern elementPattern = node.patterns[i]; - if (elementPattern is RestPattern) { - hasSeenRestPattern = true; - Pattern? subPattern = elementPattern.subPattern; - if (subPattern == null) { - continue; - } - - int nextIndex = i + 1; - int headSize = i; - int tailSize = node.patterns.length - nextIndex; - - DelayedExpression expression; - if (tailSize > 0) { - expression = new DelayedInstanceInvocation( + index, + new DelayedInstanceInvocation( typedMatchedExpression, - node.sublistTarget, - node.sublistType!, + node.indexGetTarget, + node.indexGetType!, [ - new IntegerExpression(headSize, fileOffset: node.fileOffset), new DelayedInstanceInvocation( lengthGet, node.minusTarget, node.minusType!, - [ - new IntegerExpression( - tailSize, - fileOffset: node.fileOffset, - ), - ], + [new IntegerExpression(index, fileOffset: node.fileOffset)], fileOffset: node.fileOffset, ), ], fileOffset: node.fileOffset, - ); - } else { - expression = new DelayedInstanceInvocation( - typedMatchedExpression, - node.sublistTarget, - node.sublistType!, - [new IntegerExpression(headSize, fileOffset: node.fileOffset)], - fileOffset: node.fileOffset, - ); - } - elementExpression = matchingCache.createSublistExpression( - typedMatchedExpression, - lengthGet, - headSize, - tailSize, - expression, + ), fileOffset: node.fileOffset, ); - } else { - if (!hasSeenRestPattern) { - int index = i; - elementExpression = matchingCache.createHeadIndexExpression( - typedMatchedExpression, - index, - new DelayedInstanceInvocation( - typedMatchedExpression, - node.indexGetTarget, - node.indexGetType!, - [new IntegerExpression(index, fileOffset: node.fileOffset)], - fileOffset: node.fileOffset, - ), - fileOffset: node.fileOffset, - ); - } else { - int index = node.patterns.length - i; - elementExpression = matchingCache.createTailIndexExpression( - typedMatchedExpression, - lengthGet, - index, - new DelayedInstanceInvocation( - typedMatchedExpression, - node.indexGetTarget, - node.indexGetType!, - [ - new DelayedInstanceInvocation( - lengthGet, - node.minusTarget, - node.minusType!, - [new IntegerExpression(index, fileOffset: node.fileOffset)], - fileOffset: node.fileOffset, - ), - ], - fileOffset: node.fileOffset, - ), - fileOffset: node.fileOffset, - ); - } } - - DelayedExpression elementMatcher = visitPattern( - elementPattern, - elementExpression, - ); - matchingExpression = DelayedAndExpression.merge( - matchingExpression, - elementMatcher, - fileOffset: node.fileOffset, - ); } - return matchingExpression ?? - new BooleanExpression(true, fileOffset: node.fileOffset); + + DelayedExpression elementMatcher = visitPattern( + elementPattern, + elementExpression, + ); + matchingExpression = DelayedAndExpression.merge( + matchingExpression, + elementMatcher, + fileOffset: node.fileOffset, + ); } + return matchingExpression ?? + new BooleanExpression(true, fileOffset: node.fileOffset); } @override @@ -341,123 +332,118 @@ class MatchingExpressionVisitor MapPattern node, CacheableExpression matchedExpression, ) { - if (node.isNeverPattern) { - return matchedExpression; - } else { - matchedExpression = matchedExpression.promote(node.matchedValueType!); + matchedExpression = matchedExpression.promote(node.matchedValueType!); - CacheableExpression? isExpression; - CacheableExpression typedMatchedExpression; - if (node.needsCheck) { - isExpression = matchingCache.createIsExpression( - matchedExpression, - node.requiredType!, - fileOffset: node.fileOffset, - ); - typedMatchedExpression = new PromotedCacheableExpression( - matchedExpression, - node.requiredType!, - ); - } else { - typedMatchedExpression = matchedExpression; - } - - DelayedExpression? matchingExpression; - if (isExpression != null) { - matchingExpression = isExpression; - } - - InterfaceType requiredType = node.requiredType as InterfaceType; - assert( - requiredType.classNode == coreTypes.mapClass && - requiredType.typeArguments.length == 2, + CacheableExpression? isExpression; + CacheableExpression typedMatchedExpression; + if (node.needsCheck) { + isExpression = matchingCache.createIsExpression( + matchedExpression, + node.requiredType!, + fileOffset: node.fileOffset, ); - DartType valueType = requiredType.typeArguments[1]; - for (MapPatternEntry entry in node.entries) { - if (entry is MapPatternRestEntry) continue; - CacheableExpression keyExpression = matchingCache - .createConstantExpression( - entry.keyValue!, - entry.keyType!, - fileOffset: entry.key.fileOffset, - ); - CacheableExpression containsExpression = matchingCache - .createContainsKeyExpression( + typedMatchedExpression = new PromotedCacheableExpression( + matchedExpression, + node.requiredType!, + ); + } else { + typedMatchedExpression = matchedExpression; + } + + DelayedExpression? matchingExpression; + if (isExpression != null) { + matchingExpression = isExpression; + } + + InterfaceType requiredType = node.requiredType as InterfaceType; + assert( + requiredType.classNode == coreTypes.mapClass && + requiredType.typeArguments.length == 2, + ); + DartType valueType = requiredType.typeArguments[1]; + for (MapPatternEntry entry in node.entries) { + if (entry is MapPatternRestEntry) continue; + CacheableExpression keyExpression = matchingCache + .createConstantExpression( + entry.keyValue!, + entry.keyType!, + fileOffset: entry.key.fileOffset, + ); + CacheableExpression containsExpression = matchingCache + .createContainsKeyExpression( + typedMatchedExpression, + keyExpression, + new DelayedInstanceInvocation( typedMatchedExpression, - keyExpression, - new DelayedInstanceInvocation( - typedMatchedExpression, - node.containsKeyTarget, - node.containsKeyType!, - [keyExpression], - fileOffset: entry.fileOffset, - ), - fileOffset: entry.fileOffset, - ); - CacheableExpression valueExpression = matchingCache - .createIndexExpression( - typedMatchedExpression, - keyExpression, - new DelayedInstanceInvocation( - typedMatchedExpression, - node.indexGetTarget, - node.indexGetType!, - [keyExpression], - fileOffset: entry.fileOffset, - ), - fileOffset: entry.fileOffset, - ); - matchingExpression = DelayedAndExpression.merge( - matchingExpression, - new DelayedOrExpression( - new DelayedNullCheckExpression( - valueExpression, - fileOffset: entry.fileOffset, - ), - new DelayedAndExpression( - new DelayedIsExpression( - new FixedExpression( - createNullLiteral(fileOffset: entry.fileOffset), - const NullType(), - ), - valueType, - fileOffset: entry.fileOffset, - ), - containsExpression, + node.containsKeyTarget, + node.containsKeyType!, + [keyExpression], fileOffset: entry.fileOffset, ), fileOffset: entry.fileOffset, + ); + CacheableExpression valueExpression = matchingCache.createIndexExpression( + typedMatchedExpression, + keyExpression, + new DelayedInstanceInvocation( + typedMatchedExpression, + node.indexGetTarget, + node.indexGetType!, + [keyExpression], + fileOffset: entry.fileOffset, + ), + fileOffset: entry.fileOffset, + ); + matchingExpression = DelayedAndExpression.merge( + matchingExpression, + new DelayedOrExpression( + new DelayedNullCheckExpression( + valueExpression, + fileOffset: entry.fileOffset, + ), + new DelayedAndExpression( + new DelayedIsExpression( + new FixedExpression( + createNullLiteral(fileOffset: entry.fileOffset), + const NullType(), + ), + valueType, + fileOffset: entry.fileOffset, + ), + containsExpression, + fileOffset: entry.fileOffset, ), fileOffset: entry.fileOffset, - ); - valueExpression = new PromotedCacheableExpression( - valueExpression, - valueType, - ); + ), + fileOffset: entry.fileOffset, + ); + valueExpression = new PromotedCacheableExpression( + valueExpression, + valueType, + ); - DelayedExpression subExpression = visitPattern( - entry.value, - valueExpression, + DelayedExpression subExpression = visitPattern( + entry.value, + valueExpression, + ); + if (!subExpression.uses(valueExpression)) { + // Ensure that we perform the lookup even if we don't use the result. + matchingExpression = DelayedAndExpression.merge( + matchingExpression, + new EffectExpression(valueExpression, subExpression), + fileOffset: node.fileOffset, + ); + } else { + matchingExpression = DelayedAndExpression.merge( + matchingExpression, + subExpression, + fileOffset: node.fileOffset, ); - if (!subExpression.uses(valueExpression)) { - // Ensure that we perform the lookup even if we don't use the result. - matchingExpression = DelayedAndExpression.merge( - matchingExpression, - new EffectExpression(valueExpression, subExpression), - fileOffset: node.fileOffset, - ); - } else { - matchingExpression = DelayedAndExpression.merge( - matchingExpression, - subExpression, - fileOffset: node.fileOffset, - ); - } } - // Coverage-ignore(suite): Not run. - return matchingExpression ?? - new BooleanExpression(true, fileOffset: node.fileOffset); } + // Coverage-ignore(suite): Not run. + return matchingExpression ?? + new BooleanExpression(true, fileOffset: node.fileOffset); } @override diff --git a/pkg/front_end/testcases/patterns/effect_only.dart.strong.expect b/pkg/front_end/testcases/patterns/effect_only.dart.strong.expect index 62ad878e754..812cb36470b 100644 --- a/pkg/front_end/testcases/patterns/effect_only.dart.strong.expect +++ b/pkg/front_end/testcases/patterns/effect_only.dart.strong.expect @@ -7,7 +7,7 @@ static method test(core::List list) → dynamic { { final synthesized core::List #0#0 = list; final const synthesized core::int #0#3 = #C1; - if(!(let final dynamic #t1 = #0#0 as core::List in (#0#0 as core::List).{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (let final dynamic #t2 = v = (#0#0 as core::List).{core::List::[]}(0){(core::int) → core::int} in true))) + if(!(let final dynamic #t1 = #0#0 as core::List in (#0#0 as core::List).{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (let final dynamic #t2 = v = (#0#0 as core::List).{core::List::[]}(0){(core::int) → core::num} in true))) throw{for-error-handling} new core::StateError::•("Pattern matching error"); } self::expect(42, v); diff --git a/pkg/front_end/testcases/patterns/effect_only.dart.strong.modular.expect b/pkg/front_end/testcases/patterns/effect_only.dart.strong.modular.expect index 62ad878e754..812cb36470b 100644 --- a/pkg/front_end/testcases/patterns/effect_only.dart.strong.modular.expect +++ b/pkg/front_end/testcases/patterns/effect_only.dart.strong.modular.expect @@ -7,7 +7,7 @@ static method test(core::List list) → dynamic { { final synthesized core::List #0#0 = list; final const synthesized core::int #0#3 = #C1; - if(!(let final dynamic #t1 = #0#0 as core::List in (#0#0 as core::List).{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (let final dynamic #t2 = v = (#0#0 as core::List).{core::List::[]}(0){(core::int) → core::int} in true))) + if(!(let final dynamic #t1 = #0#0 as core::List in (#0#0 as core::List).{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (let final dynamic #t2 = v = (#0#0 as core::List).{core::List::[]}(0){(core::int) → core::num} in true))) throw{for-error-handling} new core::StateError::•("Pattern matching error"); } self::expect(42, v); diff --git a/pkg/front_end/testcases/patterns/effect_only.dart.strong.transformed.expect b/pkg/front_end/testcases/patterns/effect_only.dart.strong.transformed.expect index f16a28e138f..60c364a1846 100644 --- a/pkg/front_end/testcases/patterns/effect_only.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/patterns/effect_only.dart.strong.transformed.expect @@ -7,7 +7,7 @@ static method test(core::List list) → dynamic { { final synthesized core::List #0#0 = list; final const synthesized core::int #0#3 = #C1; - if(!(let final dynamic #t1 = #0#0 as{Unchecked} core::List in (#0#0 as{Unchecked} core::List).{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (let final dynamic #t2 = v = (#0#0 as{Unchecked} core::List).{core::List::[]}(0){(core::int) → core::int} in true))) + if(!(let final dynamic #t1 = #0#0 as{Unchecked} core::List in (#0#0 as{Unchecked} core::List).{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (let final dynamic #t2 = v = (#0#0 as{Unchecked} core::List).{core::List::[]}(0){(core::int) → core::num} in true))) throw{for-error-handling} new core::StateError::•("Pattern matching error"); } self::expect(42, v); diff --git a/pkg/front_end/testcases/patterns/issue56138.dart.strong.expect b/pkg/front_end/testcases/patterns/issue56138.dart.strong.expect index 6235e5a8da6..368fa0c16d8 100644 --- a/pkg/front_end/testcases/patterns/issue56138.dart.strong.expect +++ b/pkg/front_end/testcases/patterns/issue56138.dart.strong.expect @@ -6,7 +6,8 @@ static method main() → void { try { { final synthesized Never #0#0 = throw "A"; - if(!#0#0) + final const synthesized core::int #0#2 = #C1; + if(!#0#0.{core::List::length}{core::int}.{core::num::<=}(#C1){(core::num) → core::bool}) throw{for-error-handling} new core::StateError::•("Pattern matching error"); } } @@ -16,3 +17,7 @@ static method main() → void { } throw "Missing exception"; } + +constants { + #C1 = 0 +} diff --git a/pkg/front_end/testcases/patterns/issue56138.dart.strong.modular.expect b/pkg/front_end/testcases/patterns/issue56138.dart.strong.modular.expect index 6235e5a8da6..368fa0c16d8 100644 --- a/pkg/front_end/testcases/patterns/issue56138.dart.strong.modular.expect +++ b/pkg/front_end/testcases/patterns/issue56138.dart.strong.modular.expect @@ -6,7 +6,8 @@ static method main() → void { try { { final synthesized Never #0#0 = throw "A"; - if(!#0#0) + final const synthesized core::int #0#2 = #C1; + if(!#0#0.{core::List::length}{core::int}.{core::num::<=}(#C1){(core::num) → core::bool}) throw{for-error-handling} new core::StateError::•("Pattern matching error"); } } @@ -16,3 +17,7 @@ static method main() → void { } throw "Missing exception"; } + +constants { + #C1 = 0 +} diff --git a/pkg/front_end/testcases/patterns/issue56138.dart.strong.transformed.expect b/pkg/front_end/testcases/patterns/issue56138.dart.strong.transformed.expect index 6235e5a8da6..368fa0c16d8 100644 --- a/pkg/front_end/testcases/patterns/issue56138.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/patterns/issue56138.dart.strong.transformed.expect @@ -6,7 +6,8 @@ static method main() → void { try { { final synthesized Never #0#0 = throw "A"; - if(!#0#0) + final const synthesized core::int #0#2 = #C1; + if(!#0#0.{core::List::length}{core::int}.{core::num::<=}(#C1){(core::num) → core::bool}) throw{for-error-handling} new core::StateError::•("Pattern matching error"); } } @@ -16,3 +17,7 @@ static method main() → void { } throw "Missing exception"; } + +constants { + #C1 = 0 +} diff --git a/pkg/front_end/testcases/patterns/issue63315.dart b/pkg/front_end/testcases/patterns/issue63315.dart new file mode 100644 index 00000000000..34fd065a67c --- /dev/null +++ b/pkg/front_end/testcases/patterns/issue63315.dart @@ -0,0 +1,54 @@ +// Copyright (c) 2026, 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. + +extension type JsonMap1(Map _) + implements Map { + T operator [](String key) => _[key] as T; +} + +void parseJson1(JsonMap1 map) { + if (map case {"key": "value"}) print("ok"); +} + +extension type JsonMap2(Map _) + implements Map { + bool containsKey(String key) => _.containsKey(key); +} + +void parseJson2(JsonMap2 map) { + if (map case {"key": "value"}) print("ok"); +} + +extension type JsonMap3(Map _) + implements Map { + int get length => _.length; +} + +void parseJson3(JsonMap3 map) { + if (map case {"key": "value"}) print("ok"); +} + +extension type JsonList1(List _) implements List { + T operator [](int index) => _[index] as T; +} + +void parseJson4(JsonList1 list) { + if (list case ["value"]) print("ok"); +} + +extension type JsonList2(List _) implements List { + int get length => _.length; +} + +void parseJson5(JsonList2 list) { + if (list case ["value"]) print("ok"); +} + +extension type JsonList3(List _) implements List { + List sublist(int start, [int? end]) => _.sublist(start, end).cast(); +} + +void parseJson6(JsonList3 list) { + if (list case ["value"]) print("ok"); +} diff --git a/pkg/front_end/testcases/patterns/issue63315.dart.strong.expect b/pkg/front_end/testcases/patterns/issue63315.dart.strong.expect new file mode 100644 index 00000000000..8d5f0f2e7e9 --- /dev/null +++ b/pkg/front_end/testcases/patterns/issue63315.dart.strong.expect @@ -0,0 +1,161 @@ +library; +import self as self; +import "dart:core" as core; + +extension type JsonMap1(core::Map _) implements core::Map { + abstract extension-type-member representation-field get _() → core::Map; + operator [] = self::JsonMap1|[]; + constructor • = self::JsonMap1|constructor#; + constructor tearoff • = self::JsonMap1|constructor#_#new#tearOff; +} +extension type JsonMap2(core::Map _) implements core::Map { + abstract extension-type-member representation-field get _() → core::Map; + method containsKey = self::JsonMap2|containsKey; + method tearoff containsKey = self::JsonMap2|get#containsKey; + constructor • = self::JsonMap2|constructor#; + constructor tearoff • = self::JsonMap2|constructor#_#new#tearOff; +} +extension type JsonMap3(core::Map _) implements core::Map { + abstract extension-type-member representation-field get _() → core::Map; + get length = self::JsonMap3|get#length; + constructor • = self::JsonMap3|constructor#; + constructor tearoff • = self::JsonMap3|constructor#_#new#tearOff; +} +extension type JsonList1(core::List _) implements core::List { + abstract extension-type-member representation-field get _() → core::List; + operator [] = self::JsonList1|[]; + constructor • = self::JsonList1|constructor#; + constructor tearoff • = self::JsonList1|constructor#_#new#tearOff; +} +extension type JsonList2(core::List _) implements core::List { + abstract extension-type-member representation-field get _() → core::List; + get length = self::JsonList2|get#length; + constructor • = self::JsonList2|constructor#; + constructor tearoff • = self::JsonList2|constructor#_#new#tearOff; +} +extension type JsonList3(core::List _) implements core::List { + abstract extension-type-member representation-field get _() → core::List; + method sublist = self::JsonList3|sublist; + method tearoff sublist = self::JsonList3|get#sublist; + constructor • = self::JsonList3|constructor#; + constructor tearoff • = self::JsonList3|constructor#_#new#tearOff; +} +static extension-type-member method JsonMap1|constructor#(wildcard initializing-formal core::Map _#wc0#formal) → self::JsonMap1 /* erasure=core::Map */ { + lowered final self::JsonMap1 /* erasure=core::Map */ #this = _#wc0#formal; + return #this; +} +static extension-type-member synthetic method JsonMap1|constructor#_#new#tearOff(core::Map _#wc0#formal) → self::JsonMap1 /* erasure=core::Map */ + return self::JsonMap1|constructor#(_#wc0#formal); +static extension-type-member method JsonMap1|[](lowered final self::JsonMap1 /* erasure=core::Map */ #this, core::String key) → self::JsonMap1|[]::T% + return (#this as{Unchecked} core::Map).{core::Map::[]}(key){(core::Object?) → core::Object?} as self::JsonMap1|[]::T%; +static method parseJson1(self::JsonMap1 /* erasure=core::Map */ map) → void { + { + final synthesized self::JsonMap1 /* erasure=core::Map */ #0#0 = map; + synthesized core::Object? #0#3; + synthesized core::bool #0#3#isSet = false; + final const synthesized core::String #0#1 = #C1; + final const synthesized core::String #0#4 = #C2; + if((!((#0#3#isSet ?{core::Object?} #0#3 : let final dynamic #t1 = #0#3#isSet = true in #0#3 = #0#0.{core::Map::[]}(#C1){(core::Object?) → core::Object?}) == null) || null is core::Object? && #0#0.{core::Map::containsKey}(#C1){(core::Object?) → core::bool}) && #C2 =={core::String::==}{(core::Object) → core::bool} (#0#3#isSet ?{core::Object?} #0#3 : let final dynamic #t2 = #0#3#isSet = true in #0#3 = #0#0.{core::Map::[]}(#C1){(core::Object?) → core::Object?})) + core::print("ok"); + } +} +static extension-type-member method JsonMap2|constructor#(wildcard initializing-formal core::Map _#wc1#formal) → self::JsonMap2 /* erasure=core::Map */ { + lowered final self::JsonMap2 /* erasure=core::Map */ #this = _#wc1#formal; + return #this; +} +static extension-type-member synthetic method JsonMap2|constructor#_#new#tearOff(core::Map _#wc1#formal) → self::JsonMap2 /* erasure=core::Map */ + return self::JsonMap2|constructor#(_#wc1#formal); +static extension-type-member method JsonMap2|containsKey(lowered final self::JsonMap2 /* erasure=core::Map */ #this, core::String key) → core::bool + return (#this as{Unchecked} core::Map).{core::Map::containsKey}(key){(core::Object?) → core::bool}; +static extension-type-member method JsonMap2|get#containsKey(lowered final self::JsonMap2 /* erasure=core::Map */ #this) → (core::String) → core::bool + return (core::String key) → core::bool => self::JsonMap2|containsKey(#this, key); +static method parseJson2(self::JsonMap2 /* erasure=core::Map */ map) → void { + { + final synthesized self::JsonMap2 /* erasure=core::Map */ #0#0 = map; + synthesized core::Object? #0#3; + synthesized core::bool #0#3#isSet = false; + final const synthesized core::String #0#1 = #C1; + final const synthesized core::String #0#4 = #C2; + if((!((#0#3#isSet ?{core::Object?} #0#3 : let final dynamic #t3 = #0#3#isSet = true in #0#3 = #0#0.{core::Map::[]}(#C1){(core::Object?) → core::Object?}) == null) || null is core::Object? && #0#0.{core::Map::containsKey}(#C1){(core::Object?) → core::bool}) && #C2 =={core::String::==}{(core::Object) → core::bool} (#0#3#isSet ?{core::Object?} #0#3 : let final dynamic #t4 = #0#3#isSet = true in #0#3 = #0#0.{core::Map::[]}(#C1){(core::Object?) → core::Object?})) + core::print("ok"); + } +} +static extension-type-member method JsonMap3|constructor#(wildcard initializing-formal core::Map _#wc2#formal) → self::JsonMap3 /* erasure=core::Map */ { + lowered final self::JsonMap3 /* erasure=core::Map */ #this = _#wc2#formal; + return #this; +} +static extension-type-member synthetic method JsonMap3|constructor#_#new#tearOff(core::Map _#wc2#formal) → self::JsonMap3 /* erasure=core::Map */ + return self::JsonMap3|constructor#(_#wc2#formal); +static extension-type-member method JsonMap3|get#length(lowered final self::JsonMap3 /* erasure=core::Map */ #this) → core::int + return (#this as{Unchecked} core::Map).{core::Map::length}{core::int}; +static method parseJson3(self::JsonMap3 /* erasure=core::Map */ map) → void { + { + final synthesized self::JsonMap3 /* erasure=core::Map */ #0#0 = map; + synthesized core::Object? #0#3; + synthesized core::bool #0#3#isSet = false; + final const synthesized core::String #0#1 = #C1; + final const synthesized core::String #0#4 = #C2; + if((!((#0#3#isSet ?{core::Object?} #0#3 : let final dynamic #t5 = #0#3#isSet = true in #0#3 = #0#0.{core::Map::[]}(#C1){(core::Object?) → core::Object?}) == null) || null is core::Object? && #0#0.{core::Map::containsKey}(#C1){(core::Object?) → core::bool}) && #C2 =={core::String::==}{(core::Object) → core::bool} (#0#3#isSet ?{core::Object?} #0#3 : let final dynamic #t6 = #0#3#isSet = true in #0#3 = #0#0.{core::Map::[]}(#C1){(core::Object?) → core::Object?})) + core::print("ok"); + } +} +static extension-type-member method JsonList1|constructor#(wildcard initializing-formal core::List _#wc3#formal) → self::JsonList1 /* erasure=core::List */ { + lowered final self::JsonList1 /* erasure=core::List */ #this = _#wc3#formal; + return #this; +} +static extension-type-member synthetic method JsonList1|constructor#_#new#tearOff(core::List _#wc3#formal) → self::JsonList1 /* erasure=core::List */ + return self::JsonList1|constructor#(_#wc3#formal); +static extension-type-member method JsonList1|[](lowered final self::JsonList1 /* erasure=core::List */ #this, core::int index) → self::JsonList1|[]::T% + return (#this as{Unchecked} core::List).{core::List::[]}(index){(core::int) → core::Object?} as self::JsonList1|[]::T%; +static method parseJson4(self::JsonList1 /* erasure=core::List */ list) → void { + { + final synthesized self::JsonList1 /* erasure=core::List */ #0#0 = list; + final const synthesized core::int #0#2 = #C3; + final const synthesized core::String #0#5 = #C2; + if(#0#0.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C3 && #C2 =={core::String::==}{(core::Object) → core::bool} #0#0.{core::List::[]}(0){(core::int) → core::Object?}) + core::print("ok"); + } +} +static extension-type-member method JsonList2|constructor#(wildcard initializing-formal core::List _#wc4#formal) → self::JsonList2 /* erasure=core::List */ { + lowered final self::JsonList2 /* erasure=core::List */ #this = _#wc4#formal; + return #this; +} +static extension-type-member synthetic method JsonList2|constructor#_#new#tearOff(core::List _#wc4#formal) → self::JsonList2 /* erasure=core::List */ + return self::JsonList2|constructor#(_#wc4#formal); +static extension-type-member method JsonList2|get#length(lowered final self::JsonList2 /* erasure=core::List */ #this) → core::int + return (#this as{Unchecked} core::List).{core::List::length}{core::int}; +static method parseJson5(self::JsonList2 /* erasure=core::List */ list) → void { + { + final synthesized self::JsonList2 /* erasure=core::List */ #0#0 = list; + final const synthesized core::int #0#2 = #C3; + final const synthesized core::String #0#5 = #C2; + if(#0#0.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C3 && #C2 =={core::String::==}{(core::Object) → core::bool} #0#0.{core::List::[]}(0){(core::int) → core::Object?}) + core::print("ok"); + } +} +static extension-type-member method JsonList3|constructor#(wildcard initializing-formal core::List _#wc5#formal) → self::JsonList3 /* erasure=core::List */ { + lowered final self::JsonList3 /* erasure=core::List */ #this = _#wc5#formal; + return #this; +} +static extension-type-member synthetic method JsonList3|constructor#_#new#tearOff(core::List _#wc5#formal) → self::JsonList3 /* erasure=core::List */ + return self::JsonList3|constructor#(_#wc5#formal); +static extension-type-member method JsonList3|sublist(lowered final self::JsonList3 /* erasure=core::List */ #this, core::int start, [core::int? end = #C4]) → core::List + return (#this as{Unchecked} core::List).{core::List::sublist}(start, end){(core::int, [core::int?]) → core::List}.{core::List::cast}(){() → core::List}; +static extension-type-member method JsonList3|get#sublist(lowered final self::JsonList3 /* erasure=core::List */ #this) → (core::int, [core::int?]) → core::List + return (core::int start, [core::int? end = #C4]) → core::List => self::JsonList3|sublist(#this, start, end); +static method parseJson6(self::JsonList3 /* erasure=core::List */ list) → void { + { + final synthesized self::JsonList3 /* erasure=core::List */ #0#0 = list; + final const synthesized core::int #0#2 = #C3; + final const synthesized core::String #0#5 = #C2; + if(#0#0.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C3 && #C2 =={core::String::==}{(core::Object) → core::bool} #0#0.{core::List::[]}(0){(core::int) → core::Object?}) + core::print("ok"); + } +} + +constants { + #C1 = "key" + #C2 = "value" + #C3 = 1 + #C4 = null +} diff --git a/pkg/front_end/testcases/patterns/issue63315.dart.strong.modular.expect b/pkg/front_end/testcases/patterns/issue63315.dart.strong.modular.expect new file mode 100644 index 00000000000..8d5f0f2e7e9 --- /dev/null +++ b/pkg/front_end/testcases/patterns/issue63315.dart.strong.modular.expect @@ -0,0 +1,161 @@ +library; +import self as self; +import "dart:core" as core; + +extension type JsonMap1(core::Map _) implements core::Map { + abstract extension-type-member representation-field get _() → core::Map; + operator [] = self::JsonMap1|[]; + constructor • = self::JsonMap1|constructor#; + constructor tearoff • = self::JsonMap1|constructor#_#new#tearOff; +} +extension type JsonMap2(core::Map _) implements core::Map { + abstract extension-type-member representation-field get _() → core::Map; + method containsKey = self::JsonMap2|containsKey; + method tearoff containsKey = self::JsonMap2|get#containsKey; + constructor • = self::JsonMap2|constructor#; + constructor tearoff • = self::JsonMap2|constructor#_#new#tearOff; +} +extension type JsonMap3(core::Map _) implements core::Map { + abstract extension-type-member representation-field get _() → core::Map; + get length = self::JsonMap3|get#length; + constructor • = self::JsonMap3|constructor#; + constructor tearoff • = self::JsonMap3|constructor#_#new#tearOff; +} +extension type JsonList1(core::List _) implements core::List { + abstract extension-type-member representation-field get _() → core::List; + operator [] = self::JsonList1|[]; + constructor • = self::JsonList1|constructor#; + constructor tearoff • = self::JsonList1|constructor#_#new#tearOff; +} +extension type JsonList2(core::List _) implements core::List { + abstract extension-type-member representation-field get _() → core::List; + get length = self::JsonList2|get#length; + constructor • = self::JsonList2|constructor#; + constructor tearoff • = self::JsonList2|constructor#_#new#tearOff; +} +extension type JsonList3(core::List _) implements core::List { + abstract extension-type-member representation-field get _() → core::List; + method sublist = self::JsonList3|sublist; + method tearoff sublist = self::JsonList3|get#sublist; + constructor • = self::JsonList3|constructor#; + constructor tearoff • = self::JsonList3|constructor#_#new#tearOff; +} +static extension-type-member method JsonMap1|constructor#(wildcard initializing-formal core::Map _#wc0#formal) → self::JsonMap1 /* erasure=core::Map */ { + lowered final self::JsonMap1 /* erasure=core::Map */ #this = _#wc0#formal; + return #this; +} +static extension-type-member synthetic method JsonMap1|constructor#_#new#tearOff(core::Map _#wc0#formal) → self::JsonMap1 /* erasure=core::Map */ + return self::JsonMap1|constructor#(_#wc0#formal); +static extension-type-member method JsonMap1|[](lowered final self::JsonMap1 /* erasure=core::Map */ #this, core::String key) → self::JsonMap1|[]::T% + return (#this as{Unchecked} core::Map).{core::Map::[]}(key){(core::Object?) → core::Object?} as self::JsonMap1|[]::T%; +static method parseJson1(self::JsonMap1 /* erasure=core::Map */ map) → void { + { + final synthesized self::JsonMap1 /* erasure=core::Map */ #0#0 = map; + synthesized core::Object? #0#3; + synthesized core::bool #0#3#isSet = false; + final const synthesized core::String #0#1 = #C1; + final const synthesized core::String #0#4 = #C2; + if((!((#0#3#isSet ?{core::Object?} #0#3 : let final dynamic #t1 = #0#3#isSet = true in #0#3 = #0#0.{core::Map::[]}(#C1){(core::Object?) → core::Object?}) == null) || null is core::Object? && #0#0.{core::Map::containsKey}(#C1){(core::Object?) → core::bool}) && #C2 =={core::String::==}{(core::Object) → core::bool} (#0#3#isSet ?{core::Object?} #0#3 : let final dynamic #t2 = #0#3#isSet = true in #0#3 = #0#0.{core::Map::[]}(#C1){(core::Object?) → core::Object?})) + core::print("ok"); + } +} +static extension-type-member method JsonMap2|constructor#(wildcard initializing-formal core::Map _#wc1#formal) → self::JsonMap2 /* erasure=core::Map */ { + lowered final self::JsonMap2 /* erasure=core::Map */ #this = _#wc1#formal; + return #this; +} +static extension-type-member synthetic method JsonMap2|constructor#_#new#tearOff(core::Map _#wc1#formal) → self::JsonMap2 /* erasure=core::Map */ + return self::JsonMap2|constructor#(_#wc1#formal); +static extension-type-member method JsonMap2|containsKey(lowered final self::JsonMap2 /* erasure=core::Map */ #this, core::String key) → core::bool + return (#this as{Unchecked} core::Map).{core::Map::containsKey}(key){(core::Object?) → core::bool}; +static extension-type-member method JsonMap2|get#containsKey(lowered final self::JsonMap2 /* erasure=core::Map */ #this) → (core::String) → core::bool + return (core::String key) → core::bool => self::JsonMap2|containsKey(#this, key); +static method parseJson2(self::JsonMap2 /* erasure=core::Map */ map) → void { + { + final synthesized self::JsonMap2 /* erasure=core::Map */ #0#0 = map; + synthesized core::Object? #0#3; + synthesized core::bool #0#3#isSet = false; + final const synthesized core::String #0#1 = #C1; + final const synthesized core::String #0#4 = #C2; + if((!((#0#3#isSet ?{core::Object?} #0#3 : let final dynamic #t3 = #0#3#isSet = true in #0#3 = #0#0.{core::Map::[]}(#C1){(core::Object?) → core::Object?}) == null) || null is core::Object? && #0#0.{core::Map::containsKey}(#C1){(core::Object?) → core::bool}) && #C2 =={core::String::==}{(core::Object) → core::bool} (#0#3#isSet ?{core::Object?} #0#3 : let final dynamic #t4 = #0#3#isSet = true in #0#3 = #0#0.{core::Map::[]}(#C1){(core::Object?) → core::Object?})) + core::print("ok"); + } +} +static extension-type-member method JsonMap3|constructor#(wildcard initializing-formal core::Map _#wc2#formal) → self::JsonMap3 /* erasure=core::Map */ { + lowered final self::JsonMap3 /* erasure=core::Map */ #this = _#wc2#formal; + return #this; +} +static extension-type-member synthetic method JsonMap3|constructor#_#new#tearOff(core::Map _#wc2#formal) → self::JsonMap3 /* erasure=core::Map */ + return self::JsonMap3|constructor#(_#wc2#formal); +static extension-type-member method JsonMap3|get#length(lowered final self::JsonMap3 /* erasure=core::Map */ #this) → core::int + return (#this as{Unchecked} core::Map).{core::Map::length}{core::int}; +static method parseJson3(self::JsonMap3 /* erasure=core::Map */ map) → void { + { + final synthesized self::JsonMap3 /* erasure=core::Map */ #0#0 = map; + synthesized core::Object? #0#3; + synthesized core::bool #0#3#isSet = false; + final const synthesized core::String #0#1 = #C1; + final const synthesized core::String #0#4 = #C2; + if((!((#0#3#isSet ?{core::Object?} #0#3 : let final dynamic #t5 = #0#3#isSet = true in #0#3 = #0#0.{core::Map::[]}(#C1){(core::Object?) → core::Object?}) == null) || null is core::Object? && #0#0.{core::Map::containsKey}(#C1){(core::Object?) → core::bool}) && #C2 =={core::String::==}{(core::Object) → core::bool} (#0#3#isSet ?{core::Object?} #0#3 : let final dynamic #t6 = #0#3#isSet = true in #0#3 = #0#0.{core::Map::[]}(#C1){(core::Object?) → core::Object?})) + core::print("ok"); + } +} +static extension-type-member method JsonList1|constructor#(wildcard initializing-formal core::List _#wc3#formal) → self::JsonList1 /* erasure=core::List */ { + lowered final self::JsonList1 /* erasure=core::List */ #this = _#wc3#formal; + return #this; +} +static extension-type-member synthetic method JsonList1|constructor#_#new#tearOff(core::List _#wc3#formal) → self::JsonList1 /* erasure=core::List */ + return self::JsonList1|constructor#(_#wc3#formal); +static extension-type-member method JsonList1|[](lowered final self::JsonList1 /* erasure=core::List */ #this, core::int index) → self::JsonList1|[]::T% + return (#this as{Unchecked} core::List).{core::List::[]}(index){(core::int) → core::Object?} as self::JsonList1|[]::T%; +static method parseJson4(self::JsonList1 /* erasure=core::List */ list) → void { + { + final synthesized self::JsonList1 /* erasure=core::List */ #0#0 = list; + final const synthesized core::int #0#2 = #C3; + final const synthesized core::String #0#5 = #C2; + if(#0#0.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C3 && #C2 =={core::String::==}{(core::Object) → core::bool} #0#0.{core::List::[]}(0){(core::int) → core::Object?}) + core::print("ok"); + } +} +static extension-type-member method JsonList2|constructor#(wildcard initializing-formal core::List _#wc4#formal) → self::JsonList2 /* erasure=core::List */ { + lowered final self::JsonList2 /* erasure=core::List */ #this = _#wc4#formal; + return #this; +} +static extension-type-member synthetic method JsonList2|constructor#_#new#tearOff(core::List _#wc4#formal) → self::JsonList2 /* erasure=core::List */ + return self::JsonList2|constructor#(_#wc4#formal); +static extension-type-member method JsonList2|get#length(lowered final self::JsonList2 /* erasure=core::List */ #this) → core::int + return (#this as{Unchecked} core::List).{core::List::length}{core::int}; +static method parseJson5(self::JsonList2 /* erasure=core::List */ list) → void { + { + final synthesized self::JsonList2 /* erasure=core::List */ #0#0 = list; + final const synthesized core::int #0#2 = #C3; + final const synthesized core::String #0#5 = #C2; + if(#0#0.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C3 && #C2 =={core::String::==}{(core::Object) → core::bool} #0#0.{core::List::[]}(0){(core::int) → core::Object?}) + core::print("ok"); + } +} +static extension-type-member method JsonList3|constructor#(wildcard initializing-formal core::List _#wc5#formal) → self::JsonList3 /* erasure=core::List */ { + lowered final self::JsonList3 /* erasure=core::List */ #this = _#wc5#formal; + return #this; +} +static extension-type-member synthetic method JsonList3|constructor#_#new#tearOff(core::List _#wc5#formal) → self::JsonList3 /* erasure=core::List */ + return self::JsonList3|constructor#(_#wc5#formal); +static extension-type-member method JsonList3|sublist(lowered final self::JsonList3 /* erasure=core::List */ #this, core::int start, [core::int? end = #C4]) → core::List + return (#this as{Unchecked} core::List).{core::List::sublist}(start, end){(core::int, [core::int?]) → core::List}.{core::List::cast}(){() → core::List}; +static extension-type-member method JsonList3|get#sublist(lowered final self::JsonList3 /* erasure=core::List */ #this) → (core::int, [core::int?]) → core::List + return (core::int start, [core::int? end = #C4]) → core::List => self::JsonList3|sublist(#this, start, end); +static method parseJson6(self::JsonList3 /* erasure=core::List */ list) → void { + { + final synthesized self::JsonList3 /* erasure=core::List */ #0#0 = list; + final const synthesized core::int #0#2 = #C3; + final const synthesized core::String #0#5 = #C2; + if(#0#0.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C3 && #C2 =={core::String::==}{(core::Object) → core::bool} #0#0.{core::List::[]}(0){(core::int) → core::Object?}) + core::print("ok"); + } +} + +constants { + #C1 = "key" + #C2 = "value" + #C3 = 1 + #C4 = null +} diff --git a/pkg/front_end/testcases/patterns/issue63315.dart.strong.outline.expect b/pkg/front_end/testcases/patterns/issue63315.dart.strong.outline.expect new file mode 100644 index 00000000000..b94ed815c2f --- /dev/null +++ b/pkg/front_end/testcases/patterns/issue63315.dart.strong.outline.expect @@ -0,0 +1,94 @@ +library; +import self as self; +import "dart:core" as core; + +extension type JsonMap1(core::Map _) implements core::Map { + abstract extension-type-member representation-field get _() → core::Map; + operator [] = self::JsonMap1|[]; + constructor • = self::JsonMap1|constructor#; + constructor tearoff • = self::JsonMap1|constructor#_#new#tearOff; +} +extension type JsonMap2(core::Map _) implements core::Map { + abstract extension-type-member representation-field get _() → core::Map; + method containsKey = self::JsonMap2|containsKey; + method tearoff containsKey = self::JsonMap2|get#containsKey; + constructor • = self::JsonMap2|constructor#; + constructor tearoff • = self::JsonMap2|constructor#_#new#tearOff; +} +extension type JsonMap3(core::Map _) implements core::Map { + abstract extension-type-member representation-field get _() → core::Map; + get length = self::JsonMap3|get#length; + constructor • = self::JsonMap3|constructor#; + constructor tearoff • = self::JsonMap3|constructor#_#new#tearOff; +} +extension type JsonList1(core::List _) implements core::List { + abstract extension-type-member representation-field get _() → core::List; + operator [] = self::JsonList1|[]; + constructor • = self::JsonList1|constructor#; + constructor tearoff • = self::JsonList1|constructor#_#new#tearOff; +} +extension type JsonList2(core::List _) implements core::List { + abstract extension-type-member representation-field get _() → core::List; + get length = self::JsonList2|get#length; + constructor • = self::JsonList2|constructor#; + constructor tearoff • = self::JsonList2|constructor#_#new#tearOff; +} +extension type JsonList3(core::List _) implements core::List { + abstract extension-type-member representation-field get _() → core::List; + method sublist = self::JsonList3|sublist; + method tearoff sublist = self::JsonList3|get#sublist; + constructor • = self::JsonList3|constructor#; + constructor tearoff • = self::JsonList3|constructor#_#new#tearOff; +} +static extension-type-member method JsonMap1|constructor#(wildcard initializing-formal core::Map _#wc0#formal) → self::JsonMap1 /* erasure=core::Map */ + ; +static extension-type-member synthetic method JsonMap1|constructor#_#new#tearOff(core::Map _#wc0#formal) → self::JsonMap1 /* erasure=core::Map */ + return self::JsonMap1|constructor#(_#wc0#formal); +static extension-type-member method JsonMap1|[](lowered final self::JsonMap1 /* erasure=core::Map */ #this, core::String key) → self::JsonMap1|[]::T% + ; +static method parseJson1(self::JsonMap1 /* erasure=core::Map */ map) → void + ; +static extension-type-member method JsonMap2|constructor#(wildcard initializing-formal core::Map _#wc1#formal) → self::JsonMap2 /* erasure=core::Map */ + ; +static extension-type-member synthetic method JsonMap2|constructor#_#new#tearOff(core::Map _#wc1#formal) → self::JsonMap2 /* erasure=core::Map */ + return self::JsonMap2|constructor#(_#wc1#formal); +static extension-type-member method JsonMap2|containsKey(lowered final self::JsonMap2 /* erasure=core::Map */ #this, core::String key) → core::bool + ; +static extension-type-member method JsonMap2|get#containsKey(lowered final self::JsonMap2 /* erasure=core::Map */ #this) → (core::String) → core::bool + return (core::String key) → core::bool => self::JsonMap2|containsKey(#this, key); +static method parseJson2(self::JsonMap2 /* erasure=core::Map */ map) → void + ; +static extension-type-member method JsonMap3|constructor#(wildcard initializing-formal core::Map _#wc2#formal) → self::JsonMap3 /* erasure=core::Map */ + ; +static extension-type-member synthetic method JsonMap3|constructor#_#new#tearOff(core::Map _#wc2#formal) → self::JsonMap3 /* erasure=core::Map */ + return self::JsonMap3|constructor#(_#wc2#formal); +static extension-type-member method JsonMap3|get#length(lowered final self::JsonMap3 /* erasure=core::Map */ #this) → core::int + ; +static method parseJson3(self::JsonMap3 /* erasure=core::Map */ map) → void + ; +static extension-type-member method JsonList1|constructor#(wildcard initializing-formal core::List _#wc3#formal) → self::JsonList1 /* erasure=core::List */ + ; +static extension-type-member synthetic method JsonList1|constructor#_#new#tearOff(core::List _#wc3#formal) → self::JsonList1 /* erasure=core::List */ + return self::JsonList1|constructor#(_#wc3#formal); +static extension-type-member method JsonList1|[](lowered final self::JsonList1 /* erasure=core::List */ #this, core::int index) → self::JsonList1|[]::T% + ; +static method parseJson4(self::JsonList1 /* erasure=core::List */ list) → void + ; +static extension-type-member method JsonList2|constructor#(wildcard initializing-formal core::List _#wc4#formal) → self::JsonList2 /* erasure=core::List */ + ; +static extension-type-member synthetic method JsonList2|constructor#_#new#tearOff(core::List _#wc4#formal) → self::JsonList2 /* erasure=core::List */ + return self::JsonList2|constructor#(_#wc4#formal); +static extension-type-member method JsonList2|get#length(lowered final self::JsonList2 /* erasure=core::List */ #this) → core::int + ; +static method parseJson5(self::JsonList2 /* erasure=core::List */ list) → void + ; +static extension-type-member method JsonList3|constructor#(wildcard initializing-formal core::List _#wc5#formal) → self::JsonList3 /* erasure=core::List */ + ; +static extension-type-member synthetic method JsonList3|constructor#_#new#tearOff(core::List _#wc5#formal) → self::JsonList3 /* erasure=core::List */ + return self::JsonList3|constructor#(_#wc5#formal); +static extension-type-member method JsonList3|sublist(lowered final self::JsonList3 /* erasure=core::List */ #this, core::int start, [core::int? end]) → core::List + ; +static extension-type-member method JsonList3|get#sublist(lowered final self::JsonList3 /* erasure=core::List */ #this) → (core::int, [core::int?]) → core::List + return (core::int start, [core::int? end]) → core::List => self::JsonList3|sublist(#this, start, end); +static method parseJson6(self::JsonList3 /* erasure=core::List */ list) → void + ; diff --git a/pkg/front_end/testcases/patterns/issue63315.dart.strong.transformed.expect b/pkg/front_end/testcases/patterns/issue63315.dart.strong.transformed.expect new file mode 100644 index 00000000000..2115f8de4d4 --- /dev/null +++ b/pkg/front_end/testcases/patterns/issue63315.dart.strong.transformed.expect @@ -0,0 +1,167 @@ +library; +import self as self; +import "dart:core" as core; + +extension type JsonMap1(core::Map _) implements core::Map { + abstract extension-type-member representation-field get _() → core::Map; + operator [] = self::JsonMap1|[]; + constructor • = self::JsonMap1|constructor#; + constructor tearoff • = self::JsonMap1|constructor#_#new#tearOff; +} +extension type JsonMap2(core::Map _) implements core::Map { + abstract extension-type-member representation-field get _() → core::Map; + method containsKey = self::JsonMap2|containsKey; + method tearoff containsKey = self::JsonMap2|get#containsKey; + constructor • = self::JsonMap2|constructor#; + constructor tearoff • = self::JsonMap2|constructor#_#new#tearOff; +} +extension type JsonMap3(core::Map _) implements core::Map { + abstract extension-type-member representation-field get _() → core::Map; + get length = self::JsonMap3|get#length; + constructor • = self::JsonMap3|constructor#; + constructor tearoff • = self::JsonMap3|constructor#_#new#tearOff; +} +extension type JsonList1(core::List _) implements core::List { + abstract extension-type-member representation-field get _() → core::List; + operator [] = self::JsonList1|[]; + constructor • = self::JsonList1|constructor#; + constructor tearoff • = self::JsonList1|constructor#_#new#tearOff; +} +extension type JsonList2(core::List _) implements core::List { + abstract extension-type-member representation-field get _() → core::List; + get length = self::JsonList2|get#length; + constructor • = self::JsonList2|constructor#; + constructor tearoff • = self::JsonList2|constructor#_#new#tearOff; +} +extension type JsonList3(core::List _) implements core::List { + abstract extension-type-member representation-field get _() → core::List; + method sublist = self::JsonList3|sublist; + method tearoff sublist = self::JsonList3|get#sublist; + constructor • = self::JsonList3|constructor#; + constructor tearoff • = self::JsonList3|constructor#_#new#tearOff; +} +static extension-type-member method JsonMap1|constructor#(wildcard initializing-formal core::Map _#wc0#formal) → self::JsonMap1 /* erasure=core::Map */ { + lowered final self::JsonMap1 /* erasure=core::Map */ #this = _#wc0#formal; + return #this; +} +static extension-type-member synthetic method JsonMap1|constructor#_#new#tearOff(core::Map _#wc0#formal) → self::JsonMap1 /* erasure=core::Map */ + return self::JsonMap1|constructor#(_#wc0#formal); +static extension-type-member method JsonMap1|[](lowered final self::JsonMap1 /* erasure=core::Map */ #this, core::String key) → self::JsonMap1|[]::T% + return (#this as{Unchecked} core::Map).{core::Map::[]}(key){(core::Object?) → core::Object?} as self::JsonMap1|[]::T%; +static method parseJson1(self::JsonMap1 /* erasure=core::Map */ map) → void { + { + final synthesized self::JsonMap1 /* erasure=core::Map */ #0#0 = map; + synthesized core::Object? #0#3; + synthesized core::bool #0#3#isSet = false; + final const synthesized core::String #0#1 = #C1; + final const synthesized core::String #0#4 = #C2; + if((!((#0#3#isSet ?{core::Object?} #0#3 : let final dynamic #t1 = #0#3#isSet = true in #0#3 = #0#0.{core::Map::[]}(#C1){(core::Object?) → core::Object?}) == null) || null is core::Object? && #0#0.{core::Map::containsKey}(#C1){(core::Object?) → core::bool}) && #C2 =={core::String::==}{(core::Object) → core::bool} (#0#3#isSet ?{core::Object?} #0#3 : let final dynamic #t2 = #0#3#isSet = true in #0#3 = #0#0.{core::Map::[]}(#C1){(core::Object?) → core::Object?})) + core::print("ok"); + } +} +static extension-type-member method JsonMap2|constructor#(wildcard initializing-formal core::Map _#wc1#formal) → self::JsonMap2 /* erasure=core::Map */ { + lowered final self::JsonMap2 /* erasure=core::Map */ #this = _#wc1#formal; + return #this; +} +static extension-type-member synthetic method JsonMap2|constructor#_#new#tearOff(core::Map _#wc1#formal) → self::JsonMap2 /* erasure=core::Map */ + return self::JsonMap2|constructor#(_#wc1#formal); +static extension-type-member method JsonMap2|containsKey(lowered final self::JsonMap2 /* erasure=core::Map */ #this, core::String key) → core::bool + return (#this as{Unchecked} core::Map).{core::Map::containsKey}(key){(core::Object?) → core::bool}; +static extension-type-member method JsonMap2|get#containsKey(lowered final self::JsonMap2 /* erasure=core::Map */ #this) → (core::String) → core::bool + return (core::String key) → core::bool => self::JsonMap2|containsKey(#this, key); +static method parseJson2(self::JsonMap2 /* erasure=core::Map */ map) → void { + { + final synthesized self::JsonMap2 /* erasure=core::Map */ #0#0 = map; + synthesized core::Object? #0#3; + synthesized core::bool #0#3#isSet = false; + final const synthesized core::String #0#1 = #C1; + final const synthesized core::String #0#4 = #C2; + if((!((#0#3#isSet ?{core::Object?} #0#3 : let final dynamic #t3 = #0#3#isSet = true in #0#3 = #0#0.{core::Map::[]}(#C1){(core::Object?) → core::Object?}) == null) || null is core::Object? && #0#0.{core::Map::containsKey}(#C1){(core::Object?) → core::bool}) && #C2 =={core::String::==}{(core::Object) → core::bool} (#0#3#isSet ?{core::Object?} #0#3 : let final dynamic #t4 = #0#3#isSet = true in #0#3 = #0#0.{core::Map::[]}(#C1){(core::Object?) → core::Object?})) + core::print("ok"); + } +} +static extension-type-member method JsonMap3|constructor#(wildcard initializing-formal core::Map _#wc2#formal) → self::JsonMap3 /* erasure=core::Map */ { + lowered final self::JsonMap3 /* erasure=core::Map */ #this = _#wc2#formal; + return #this; +} +static extension-type-member synthetic method JsonMap3|constructor#_#new#tearOff(core::Map _#wc2#formal) → self::JsonMap3 /* erasure=core::Map */ + return self::JsonMap3|constructor#(_#wc2#formal); +static extension-type-member method JsonMap3|get#length(lowered final self::JsonMap3 /* erasure=core::Map */ #this) → core::int + return (#this as{Unchecked} core::Map).{core::Map::length}{core::int}; +static method parseJson3(self::JsonMap3 /* erasure=core::Map */ map) → void { + { + final synthesized self::JsonMap3 /* erasure=core::Map */ #0#0 = map; + synthesized core::Object? #0#3; + synthesized core::bool #0#3#isSet = false; + final const synthesized core::String #0#1 = #C1; + final const synthesized core::String #0#4 = #C2; + if((!((#0#3#isSet ?{core::Object?} #0#3 : let final dynamic #t5 = #0#3#isSet = true in #0#3 = #0#0.{core::Map::[]}(#C1){(core::Object?) → core::Object?}) == null) || null is core::Object? && #0#0.{core::Map::containsKey}(#C1){(core::Object?) → core::bool}) && #C2 =={core::String::==}{(core::Object) → core::bool} (#0#3#isSet ?{core::Object?} #0#3 : let final dynamic #t6 = #0#3#isSet = true in #0#3 = #0#0.{core::Map::[]}(#C1){(core::Object?) → core::Object?})) + core::print("ok"); + } +} +static extension-type-member method JsonList1|constructor#(wildcard initializing-formal core::List _#wc3#formal) → self::JsonList1 /* erasure=core::List */ { + lowered final self::JsonList1 /* erasure=core::List */ #this = _#wc3#formal; + return #this; +} +static extension-type-member synthetic method JsonList1|constructor#_#new#tearOff(core::List _#wc3#formal) → self::JsonList1 /* erasure=core::List */ + return self::JsonList1|constructor#(_#wc3#formal); +static extension-type-member method JsonList1|[](lowered final self::JsonList1 /* erasure=core::List */ #this, core::int index) → self::JsonList1|[]::T% + return (#this as{Unchecked} core::List).{core::List::[]}(index){(core::int) → core::Object?} as self::JsonList1|[]::T%; +static method parseJson4(self::JsonList1 /* erasure=core::List */ list) → void { + { + final synthesized self::JsonList1 /* erasure=core::List */ #0#0 = list; + final const synthesized core::int #0#2 = #C3; + final const synthesized core::String #0#5 = #C2; + if(#0#0.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C3 && #C2 =={core::String::==}{(core::Object) → core::bool} #0#0.{core::List::[]}(0){(core::int) → core::Object?}) + core::print("ok"); + } +} +static extension-type-member method JsonList2|constructor#(wildcard initializing-formal core::List _#wc4#formal) → self::JsonList2 /* erasure=core::List */ { + lowered final self::JsonList2 /* erasure=core::List */ #this = _#wc4#formal; + return #this; +} +static extension-type-member synthetic method JsonList2|constructor#_#new#tearOff(core::List _#wc4#formal) → self::JsonList2 /* erasure=core::List */ + return self::JsonList2|constructor#(_#wc4#formal); +static extension-type-member method JsonList2|get#length(lowered final self::JsonList2 /* erasure=core::List */ #this) → core::int + return (#this as{Unchecked} core::List).{core::List::length}{core::int}; +static method parseJson5(self::JsonList2 /* erasure=core::List */ list) → void { + { + final synthesized self::JsonList2 /* erasure=core::List */ #0#0 = list; + final const synthesized core::int #0#2 = #C3; + final const synthesized core::String #0#5 = #C2; + if(#0#0.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C3 && #C2 =={core::String::==}{(core::Object) → core::bool} #0#0.{core::List::[]}(0){(core::int) → core::Object?}) + core::print("ok"); + } +} +static extension-type-member method JsonList3|constructor#(wildcard initializing-formal core::List _#wc5#formal) → self::JsonList3 /* erasure=core::List */ { + lowered final self::JsonList3 /* erasure=core::List */ #this = _#wc5#formal; + return #this; +} +static extension-type-member synthetic method JsonList3|constructor#_#new#tearOff(core::List _#wc5#formal) → self::JsonList3 /* erasure=core::List */ + return self::JsonList3|constructor#(_#wc5#formal); +static extension-type-member method JsonList3|sublist(lowered final self::JsonList3 /* erasure=core::List */ #this, core::int start, [core::int? end = #C4]) → core::List + return (#this as{Unchecked} core::List).{core::List::sublist}(start, end){(core::int, [core::int?]) → core::List}.{core::List::cast}(){() → core::List}; +static extension-type-member method JsonList3|get#sublist(lowered final self::JsonList3 /* erasure=core::List */ #this) → (core::int, [core::int?]) → core::List + return (core::int start, [core::int? end = #C4]) → core::List => self::JsonList3|sublist(#this, start, end); +static method parseJson6(self::JsonList3 /* erasure=core::List */ list) → void { + { + final synthesized self::JsonList3 /* erasure=core::List */ #0#0 = list; + final const synthesized core::int #0#2 = #C3; + final const synthesized core::String #0#5 = #C2; + if(#0#0.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C3 && #C2 =={core::String::==}{(core::Object) → core::bool} #0#0.{core::List::[]}(0){(core::int) → core::Object?}) + core::print("ok"); + } +} + +constants { + #C1 = "key" + #C2 = "value" + #C3 = 1 + #C4 = null +} + +Extra constant evaluation status: +Evaluated: IsExpression @ org-dartlang-testcase:///issue63315.dart:11:22 -> BoolConstant(true) +Evaluated: IsExpression @ org-dartlang-testcase:///issue63315.dart:20:22 -> BoolConstant(true) +Evaluated: IsExpression @ org-dartlang-testcase:///issue63315.dart:29:22 -> BoolConstant(true) +Extra constant evaluation: evaluated: 167, effectively constant: 3 diff --git a/pkg/front_end/testcases/patterns/issue63315.dart.textual_outline.expect b/pkg/front_end/testcases/patterns/issue63315.dart.textual_outline.expect new file mode 100644 index 00000000000..8374d3b0d9f --- /dev/null +++ b/pkg/front_end/testcases/patterns/issue63315.dart.textual_outline.expect @@ -0,0 +1,38 @@ +extension type JsonMap1(Map _) + implements Map { + T operator [](String key) => _[key] as T; +} + +void parseJson1(JsonMap1 map) {} + +extension type JsonMap2(Map _) + implements Map { + bool containsKey(String key) => _.containsKey(key); +} + +void parseJson2(JsonMap2 map) {} + +extension type JsonMap3(Map _) + implements Map { + int get length => _.length; +} + +void parseJson3(JsonMap3 map) {} + +extension type JsonList1(List _) implements List { + T operator [](int index) => _[index] as T; +} + +void parseJson4(JsonList1 list) {} + +extension type JsonList2(List _) implements List { + int get length => _.length; +} + +void parseJson5(JsonList2 list) {} + +extension type JsonList3(List _) implements List { + List sublist(int start, [int? end]) => _.sublist(start, end).cast(); +} + +void parseJson6(JsonList3 list) {} diff --git a/pkg/front_end/testcases/patterns/issue63315.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/patterns/issue63315.dart.textual_outline_modelled.expect new file mode 100644 index 00000000000..c829442998d --- /dev/null +++ b/pkg/front_end/testcases/patterns/issue63315.dart.textual_outline_modelled.expect @@ -0,0 +1,38 @@ +extension type JsonList1(List _) implements List { + T operator [](int index) => _[index] as T; +} + +extension type JsonList2(List _) implements List { + int get length => _.length; +} + +extension type JsonList3(List _) implements List { + List sublist(int start, [int? end]) => _.sublist(start, end).cast(); +} + +extension type JsonMap1(Map _) + implements Map { + T operator [](String key) => _[key] as T; +} + +extension type JsonMap2(Map _) + implements Map { + bool containsKey(String key) => _.containsKey(key); +} + +extension type JsonMap3(Map _) + implements Map { + int get length => _.length; +} + +void parseJson1(JsonMap1 map) {} + +void parseJson2(JsonMap2 map) {} + +void parseJson3(JsonMap3 map) {} + +void parseJson4(JsonList1 list) {} + +void parseJson5(JsonList2 list) {} + +void parseJson6(JsonList3 list) {} diff --git a/pkg/front_end/testcases/patterns/map_lookup.dart.strong.expect b/pkg/front_end/testcases/patterns/map_lookup.dart.strong.expect index 09dd4f600ac..7189d77393c 100644 --- a/pkg/front_end/testcases/patterns/map_lookup.dart.strong.expect +++ b/pkg/front_end/testcases/patterns/map_lookup.dart.strong.expect @@ -155,7 +155,7 @@ static method main() → dynamic { synthesized core::int? #0#6; synthesized core::bool #0#6#isSet = false; final const synthesized core::String #0#4 = #C7; - if(!((!((#0#3#isSet ?{core::int?} #0#3 : let final dynamic #t30 = #0#3#isSet = true in #0#3 = #0#0.{self::MyMap::[]}(#C5){(core::Object?) → core::int?}) == null) || null is core::int && #0#0.{self::MyMap::containsKey}(#C5){(core::Object?) → core::bool}) && (let final dynamic #t31 = x1 = (#0#3#isSet ?{core::int?} #0#3 : let final dynamic #t32 = #0#3#isSet = true in #0#3 = #0#0.{self::MyMap::[]}(#C5){(core::Object?) → core::int?}) as{Unchecked} core::int in true) && (!((#0#6#isSet ?{core::int?} #0#6 : let final dynamic #t33 = #0#6#isSet = true in #0#6 = #0#0.{self::MyMap::[]}(#C7){(core::Object?) → core::int?}) == null) || null is core::int && #0#0.{self::MyMap::containsKey}(#C7){(core::Object?) → core::bool}) && (let final dynamic #t34 = x2 = (#0#6#isSet ?{core::int?} #0#6 : let final dynamic #t35 = #0#6#isSet = true in #0#6 = #0#0.{self::MyMap::[]}(#C7){(core::Object?) → core::int?}) as{Unchecked} core::int in true))) + if(!((!((#0#3#isSet ?{core::int?} #0#3 : let final dynamic #t30 = #0#3#isSet = true in #0#3 = #0#0.{core::Map::[]}(#C5){(core::Object?) → core::int?}) == null) || null is core::int && #0#0.{core::Map::containsKey}(#C5){(core::Object?) → core::bool}) && (let final dynamic #t31 = x1 = (#0#3#isSet ?{core::int?} #0#3 : let final dynamic #t32 = #0#3#isSet = true in #0#3 = #0#0.{core::Map::[]}(#C5){(core::Object?) → core::int?}) as{Unchecked} core::int in true) && (!((#0#6#isSet ?{core::int?} #0#6 : let final dynamic #t33 = #0#6#isSet = true in #0#6 = #0#0.{core::Map::[]}(#C7){(core::Object?) → core::int?}) == null) || null is core::int && #0#0.{core::Map::containsKey}(#C7){(core::Object?) → core::bool}) && (let final dynamic #t34 = x2 = (#0#6#isSet ?{core::int?} #0#6 : let final dynamic #t35 = #0#6#isSet = true in #0#6 = #0#0.{core::Map::[]}(#C7){(core::Object?) → core::int?}) as{Unchecked} core::int in true))) throw{for-error-handling} new core::StateError::•("Pattern matching error"); } self::expect(self::hasUnsoundNullSafety ?{core::String} self::unsoundResult : self::soundResult, map.{self::MyMap::log}{core::String}); @@ -170,7 +170,7 @@ static method main() → dynamic { synthesized core::int? #1#6; synthesized core::bool #1#6#isSet = false; final const synthesized core::String #1#4 = #C7; - if(!((!((#1#3#isSet ?{core::int?} #1#3 : let final dynamic #t36 = #1#3#isSet = true in #1#3 = #1#0.{self::MyMap::[]}(#C5){(core::Object?) → core::int?}) == null) || null is core::int && #1#0.{self::MyMap::containsKey}(#C5){(core::Object?) → core::bool}) && (let final dynamic #t37 = y1 = (#1#3#isSet ?{core::int?} #1#3 : let final dynamic #t38 = #1#3#isSet = true in #1#3 = #1#0.{self::MyMap::[]}(#C5){(core::Object?) → core::int?}) as{Unchecked} core::int in true) && (!((#1#6#isSet ?{core::int?} #1#6 : let final dynamic #t39 = #1#6#isSet = true in #1#6 = #1#0.{self::MyMap::[]}(#C7){(core::Object?) → core::int?}) == null) || null is core::int && #1#0.{self::MyMap::containsKey}(#C7){(core::Object?) → core::bool}) && (let final dynamic #t40 = y2 = (#1#6#isSet ?{core::int?} #1#6 : let final dynamic #t41 = #1#6#isSet = true in #1#6 = #1#0.{self::MyMap::[]}(#C7){(core::Object?) → core::int?}) as{Unchecked} core::int in true))) + if(!((!((#1#3#isSet ?{core::int?} #1#3 : let final dynamic #t36 = #1#3#isSet = true in #1#3 = #1#0.{core::Map::[]}(#C5){(core::Object?) → core::int?}) == null) || null is core::int && #1#0.{core::Map::containsKey}(#C5){(core::Object?) → core::bool}) && (let final dynamic #t37 = y1 = (#1#3#isSet ?{core::int?} #1#3 : let final dynamic #t38 = #1#3#isSet = true in #1#3 = #1#0.{core::Map::[]}(#C5){(core::Object?) → core::int?}) as{Unchecked} core::int in true) && (!((#1#6#isSet ?{core::int?} #1#6 : let final dynamic #t39 = #1#6#isSet = true in #1#6 = #1#0.{core::Map::[]}(#C7){(core::Object?) → core::int?}) == null) || null is core::int && #1#0.{core::Map::containsKey}(#C7){(core::Object?) → core::bool}) && (let final dynamic #t40 = y2 = (#1#6#isSet ?{core::int?} #1#6 : let final dynamic #t41 = #1#6#isSet = true in #1#6 = #1#0.{core::Map::[]}(#C7){(core::Object?) → core::int?}) as{Unchecked} core::int in true))) throw{for-error-handling} new core::StateError::•("Pattern matching error"); } self::expect(self::hasUnsoundNullSafety ?{core::String} self::unsoundResult : self::soundResult, map.{self::MyMap::log}{core::String}); diff --git a/pkg/front_end/testcases/patterns/map_lookup.dart.strong.modular.expect b/pkg/front_end/testcases/patterns/map_lookup.dart.strong.modular.expect index 09dd4f600ac..7189d77393c 100644 --- a/pkg/front_end/testcases/patterns/map_lookup.dart.strong.modular.expect +++ b/pkg/front_end/testcases/patterns/map_lookup.dart.strong.modular.expect @@ -155,7 +155,7 @@ static method main() → dynamic { synthesized core::int? #0#6; synthesized core::bool #0#6#isSet = false; final const synthesized core::String #0#4 = #C7; - if(!((!((#0#3#isSet ?{core::int?} #0#3 : let final dynamic #t30 = #0#3#isSet = true in #0#3 = #0#0.{self::MyMap::[]}(#C5){(core::Object?) → core::int?}) == null) || null is core::int && #0#0.{self::MyMap::containsKey}(#C5){(core::Object?) → core::bool}) && (let final dynamic #t31 = x1 = (#0#3#isSet ?{core::int?} #0#3 : let final dynamic #t32 = #0#3#isSet = true in #0#3 = #0#0.{self::MyMap::[]}(#C5){(core::Object?) → core::int?}) as{Unchecked} core::int in true) && (!((#0#6#isSet ?{core::int?} #0#6 : let final dynamic #t33 = #0#6#isSet = true in #0#6 = #0#0.{self::MyMap::[]}(#C7){(core::Object?) → core::int?}) == null) || null is core::int && #0#0.{self::MyMap::containsKey}(#C7){(core::Object?) → core::bool}) && (let final dynamic #t34 = x2 = (#0#6#isSet ?{core::int?} #0#6 : let final dynamic #t35 = #0#6#isSet = true in #0#6 = #0#0.{self::MyMap::[]}(#C7){(core::Object?) → core::int?}) as{Unchecked} core::int in true))) + if(!((!((#0#3#isSet ?{core::int?} #0#3 : let final dynamic #t30 = #0#3#isSet = true in #0#3 = #0#0.{core::Map::[]}(#C5){(core::Object?) → core::int?}) == null) || null is core::int && #0#0.{core::Map::containsKey}(#C5){(core::Object?) → core::bool}) && (let final dynamic #t31 = x1 = (#0#3#isSet ?{core::int?} #0#3 : let final dynamic #t32 = #0#3#isSet = true in #0#3 = #0#0.{core::Map::[]}(#C5){(core::Object?) → core::int?}) as{Unchecked} core::int in true) && (!((#0#6#isSet ?{core::int?} #0#6 : let final dynamic #t33 = #0#6#isSet = true in #0#6 = #0#0.{core::Map::[]}(#C7){(core::Object?) → core::int?}) == null) || null is core::int && #0#0.{core::Map::containsKey}(#C7){(core::Object?) → core::bool}) && (let final dynamic #t34 = x2 = (#0#6#isSet ?{core::int?} #0#6 : let final dynamic #t35 = #0#6#isSet = true in #0#6 = #0#0.{core::Map::[]}(#C7){(core::Object?) → core::int?}) as{Unchecked} core::int in true))) throw{for-error-handling} new core::StateError::•("Pattern matching error"); } self::expect(self::hasUnsoundNullSafety ?{core::String} self::unsoundResult : self::soundResult, map.{self::MyMap::log}{core::String}); @@ -170,7 +170,7 @@ static method main() → dynamic { synthesized core::int? #1#6; synthesized core::bool #1#6#isSet = false; final const synthesized core::String #1#4 = #C7; - if(!((!((#1#3#isSet ?{core::int?} #1#3 : let final dynamic #t36 = #1#3#isSet = true in #1#3 = #1#0.{self::MyMap::[]}(#C5){(core::Object?) → core::int?}) == null) || null is core::int && #1#0.{self::MyMap::containsKey}(#C5){(core::Object?) → core::bool}) && (let final dynamic #t37 = y1 = (#1#3#isSet ?{core::int?} #1#3 : let final dynamic #t38 = #1#3#isSet = true in #1#3 = #1#0.{self::MyMap::[]}(#C5){(core::Object?) → core::int?}) as{Unchecked} core::int in true) && (!((#1#6#isSet ?{core::int?} #1#6 : let final dynamic #t39 = #1#6#isSet = true in #1#6 = #1#0.{self::MyMap::[]}(#C7){(core::Object?) → core::int?}) == null) || null is core::int && #1#0.{self::MyMap::containsKey}(#C7){(core::Object?) → core::bool}) && (let final dynamic #t40 = y2 = (#1#6#isSet ?{core::int?} #1#6 : let final dynamic #t41 = #1#6#isSet = true in #1#6 = #1#0.{self::MyMap::[]}(#C7){(core::Object?) → core::int?}) as{Unchecked} core::int in true))) + if(!((!((#1#3#isSet ?{core::int?} #1#3 : let final dynamic #t36 = #1#3#isSet = true in #1#3 = #1#0.{core::Map::[]}(#C5){(core::Object?) → core::int?}) == null) || null is core::int && #1#0.{core::Map::containsKey}(#C5){(core::Object?) → core::bool}) && (let final dynamic #t37 = y1 = (#1#3#isSet ?{core::int?} #1#3 : let final dynamic #t38 = #1#3#isSet = true in #1#3 = #1#0.{core::Map::[]}(#C5){(core::Object?) → core::int?}) as{Unchecked} core::int in true) && (!((#1#6#isSet ?{core::int?} #1#6 : let final dynamic #t39 = #1#6#isSet = true in #1#6 = #1#0.{core::Map::[]}(#C7){(core::Object?) → core::int?}) == null) || null is core::int && #1#0.{core::Map::containsKey}(#C7){(core::Object?) → core::bool}) && (let final dynamic #t40 = y2 = (#1#6#isSet ?{core::int?} #1#6 : let final dynamic #t41 = #1#6#isSet = true in #1#6 = #1#0.{core::Map::[]}(#C7){(core::Object?) → core::int?}) as{Unchecked} core::int in true))) throw{for-error-handling} new core::StateError::•("Pattern matching error"); } self::expect(self::hasUnsoundNullSafety ?{core::String} self::unsoundResult : self::soundResult, map.{self::MyMap::log}{core::String}); diff --git a/pkg/front_end/testcases/patterns/map_lookup.dart.strong.transformed.expect b/pkg/front_end/testcases/patterns/map_lookup.dart.strong.transformed.expect index a8b6f858589..978064d0f93 100644 --- a/pkg/front_end/testcases/patterns/map_lookup.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/patterns/map_lookup.dart.strong.transformed.expect @@ -155,7 +155,7 @@ static method main() → dynamic { synthesized core::int? #0#6; synthesized core::bool #0#6#isSet = false; final const synthesized core::String #0#4 = #C7; - if(!((!((#0#3#isSet ?{core::int?} #0#3 : let final dynamic #t38 = #0#3#isSet = true in #0#3 = #0#0.{self::MyMap::[]}(#C5){(core::Object?) → core::int?}) == null) || null is core::int && #0#0.{self::MyMap::containsKey}(#C5){(core::Object?) → core::bool}) && (let final dynamic #t39 = x1 = let core::int? #t40 = #0#3#isSet ?{core::int?} #0#3 : let final dynamic #t41 = #0#3#isSet = true in #0#3 = #0#0.{self::MyMap::[]}(#C5){(core::Object?) → core::int?} in #t40 == null ?{core::int} #t40 as{Unchecked} core::int : #t40{core::int} in true) && (!((#0#6#isSet ?{core::int?} #0#6 : let final dynamic #t42 = #0#6#isSet = true in #0#6 = #0#0.{self::MyMap::[]}(#C7){(core::Object?) → core::int?}) == null) || null is core::int && #0#0.{self::MyMap::containsKey}(#C7){(core::Object?) → core::bool}) && (let final dynamic #t43 = x2 = let core::int? #t44 = #0#6#isSet ?{core::int?} #0#6 : let final dynamic #t45 = #0#6#isSet = true in #0#6 = #0#0.{self::MyMap::[]}(#C7){(core::Object?) → core::int?} in #t44 == null ?{core::int} #t44 as{Unchecked} core::int : #t44{core::int} in true))) + if(!((!((#0#3#isSet ?{core::int?} #0#3 : let final dynamic #t38 = #0#3#isSet = true in #0#3 = #0#0.{core::Map::[]}(#C5){(core::Object?) → core::int?}) == null) || null is core::int && #0#0.{core::Map::containsKey}(#C5){(core::Object?) → core::bool}) && (let final dynamic #t39 = x1 = let core::int? #t40 = #0#3#isSet ?{core::int?} #0#3 : let final dynamic #t41 = #0#3#isSet = true in #0#3 = #0#0.{core::Map::[]}(#C5){(core::Object?) → core::int?} in #t40 == null ?{core::int} #t40 as{Unchecked} core::int : #t40{core::int} in true) && (!((#0#6#isSet ?{core::int?} #0#6 : let final dynamic #t42 = #0#6#isSet = true in #0#6 = #0#0.{core::Map::[]}(#C7){(core::Object?) → core::int?}) == null) || null is core::int && #0#0.{core::Map::containsKey}(#C7){(core::Object?) → core::bool}) && (let final dynamic #t43 = x2 = let core::int? #t44 = #0#6#isSet ?{core::int?} #0#6 : let final dynamic #t45 = #0#6#isSet = true in #0#6 = #0#0.{core::Map::[]}(#C7){(core::Object?) → core::int?} in #t44 == null ?{core::int} #t44 as{Unchecked} core::int : #t44{core::int} in true))) throw{for-error-handling} new core::StateError::•("Pattern matching error"); } self::expect(self::hasUnsoundNullSafety ?{core::String} self::unsoundResult : self::soundResult, map.{self::MyMap::log}{core::String}); @@ -170,7 +170,7 @@ static method main() → dynamic { synthesized core::int? #1#6; synthesized core::bool #1#6#isSet = false; final const synthesized core::String #1#4 = #C7; - if(!((!((#1#3#isSet ?{core::int?} #1#3 : let final dynamic #t46 = #1#3#isSet = true in #1#3 = #1#0.{self::MyMap::[]}(#C5){(core::Object?) → core::int?}) == null) || null is core::int && #1#0.{self::MyMap::containsKey}(#C5){(core::Object?) → core::bool}) && (let final dynamic #t47 = y1 = let core::int? #t48 = #1#3#isSet ?{core::int?} #1#3 : let final dynamic #t49 = #1#3#isSet = true in #1#3 = #1#0.{self::MyMap::[]}(#C5){(core::Object?) → core::int?} in #t48 == null ?{core::int} #t48 as{Unchecked} core::int : #t48{core::int} in true) && (!((#1#6#isSet ?{core::int?} #1#6 : let final dynamic #t50 = #1#6#isSet = true in #1#6 = #1#0.{self::MyMap::[]}(#C7){(core::Object?) → core::int?}) == null) || null is core::int && #1#0.{self::MyMap::containsKey}(#C7){(core::Object?) → core::bool}) && (let final dynamic #t51 = y2 = let core::int? #t52 = #1#6#isSet ?{core::int?} #1#6 : let final dynamic #t53 = #1#6#isSet = true in #1#6 = #1#0.{self::MyMap::[]}(#C7){(core::Object?) → core::int?} in #t52 == null ?{core::int} #t52 as{Unchecked} core::int : #t52{core::int} in true))) + if(!((!((#1#3#isSet ?{core::int?} #1#3 : let final dynamic #t46 = #1#3#isSet = true in #1#3 = #1#0.{core::Map::[]}(#C5){(core::Object?) → core::int?}) == null) || null is core::int && #1#0.{core::Map::containsKey}(#C5){(core::Object?) → core::bool}) && (let final dynamic #t47 = y1 = let core::int? #t48 = #1#3#isSet ?{core::int?} #1#3 : let final dynamic #t49 = #1#3#isSet = true in #1#3 = #1#0.{core::Map::[]}(#C5){(core::Object?) → core::int?} in #t48 == null ?{core::int} #t48 as{Unchecked} core::int : #t48{core::int} in true) && (!((#1#6#isSet ?{core::int?} #1#6 : let final dynamic #t50 = #1#6#isSet = true in #1#6 = #1#0.{core::Map::[]}(#C7){(core::Object?) → core::int?}) == null) || null is core::int && #1#0.{core::Map::containsKey}(#C7){(core::Object?) → core::bool}) && (let final dynamic #t51 = y2 = let core::int? #t52 = #1#6#isSet ?{core::int?} #1#6 : let final dynamic #t53 = #1#6#isSet = true in #1#6 = #1#0.{core::Map::[]}(#C7){(core::Object?) → core::int?} in #t52 == null ?{core::int} #t52 as{Unchecked} core::int : #t52{core::int} in true))) throw{for-error-handling} new core::StateError::•("Pattern matching error"); } self::expect(self::hasUnsoundNullSafety ?{core::String} self::unsoundResult : self::soundResult, map.{self::MyMap::log}{core::String}); diff --git a/pkg/front_end/testcases/patterns/matching_and_capturing_accesses_list_element_once.dart.strong.expect b/pkg/front_end/testcases/patterns/matching_and_capturing_accesses_list_element_once.dart.strong.expect index 1adcbb0a62f..2610799ab1f 100644 --- a/pkg/front_end/testcases/patterns/matching_and_capturing_accesses_list_element_once.dart.strong.expect +++ b/pkg/front_end/testcases/patterns/matching_and_capturing_accesses_list_element_once.dart.strong.expect @@ -157,8 +157,8 @@ static method main() → dynamic { { hoisted core::int x; hoisted core::int y; - if(#0#0.{self::A::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C5 && ((#0#4#isSet ?{core::int} #0#4 : let final dynamic #t1 = #0#4#isSet = true in #0#4 = #0#0.{self::A::[]}(0){(core::int) → core::int}) is core::int && (let final dynamic #t2 = x = #0#4#isSet ?{core::int} #0#4 : let final dynamic #t3 = #0#4#isSet = true in #0#4 = #0#0.{self::A::[]}(0){(core::int) → core::int} in true)) && (#0#5#isSet ?{core::int} #0#5 : let final dynamic #t4 = #0#5#isSet = true in #0#5 = #0#0.{self::A::[]}(1){(core::int) → core::int}) is core::int) { - y = #0#5#isSet ?{core::int} #0#5 : let final dynamic #t5 = #0#5#isSet = true in #0#5 = #0#0.{self::A::[]}(1){(core::int) → core::int}; + if(#0#0.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C5 && ((#0#4#isSet ?{core::int} #0#4 : let final dynamic #t1 = #0#4#isSet = true in #0#4 = #0#0.{core::List::[]}(0){(core::int) → core::int}) is core::int && (let final dynamic #t2 = x = #0#4#isSet ?{core::int} #0#4 : let final dynamic #t3 = #0#4#isSet = true in #0#4 = #0#0.{core::List::[]}(0){(core::int) → core::int} in true)) && (#0#5#isSet ?{core::int} #0#5 : let final dynamic #t4 = #0#5#isSet = true in #0#5 = #0#0.{core::List::[]}(1){(core::int) → core::int}) is core::int) { + y = #0#5#isSet ?{core::int} #0#5 : let final dynamic #t5 = #0#5#isSet = true in #0#5 = #0#0.{core::List::[]}(1){(core::int) → core::int}; { self::expectEquals(x, 0); self::expectEquals(y, 0); diff --git a/pkg/front_end/testcases/patterns/matching_and_capturing_accesses_list_element_once.dart.strong.modular.expect b/pkg/front_end/testcases/patterns/matching_and_capturing_accesses_list_element_once.dart.strong.modular.expect index 1adcbb0a62f..2610799ab1f 100644 --- a/pkg/front_end/testcases/patterns/matching_and_capturing_accesses_list_element_once.dart.strong.modular.expect +++ b/pkg/front_end/testcases/patterns/matching_and_capturing_accesses_list_element_once.dart.strong.modular.expect @@ -157,8 +157,8 @@ static method main() → dynamic { { hoisted core::int x; hoisted core::int y; - if(#0#0.{self::A::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C5 && ((#0#4#isSet ?{core::int} #0#4 : let final dynamic #t1 = #0#4#isSet = true in #0#4 = #0#0.{self::A::[]}(0){(core::int) → core::int}) is core::int && (let final dynamic #t2 = x = #0#4#isSet ?{core::int} #0#4 : let final dynamic #t3 = #0#4#isSet = true in #0#4 = #0#0.{self::A::[]}(0){(core::int) → core::int} in true)) && (#0#5#isSet ?{core::int} #0#5 : let final dynamic #t4 = #0#5#isSet = true in #0#5 = #0#0.{self::A::[]}(1){(core::int) → core::int}) is core::int) { - y = #0#5#isSet ?{core::int} #0#5 : let final dynamic #t5 = #0#5#isSet = true in #0#5 = #0#0.{self::A::[]}(1){(core::int) → core::int}; + if(#0#0.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C5 && ((#0#4#isSet ?{core::int} #0#4 : let final dynamic #t1 = #0#4#isSet = true in #0#4 = #0#0.{core::List::[]}(0){(core::int) → core::int}) is core::int && (let final dynamic #t2 = x = #0#4#isSet ?{core::int} #0#4 : let final dynamic #t3 = #0#4#isSet = true in #0#4 = #0#0.{core::List::[]}(0){(core::int) → core::int} in true)) && (#0#5#isSet ?{core::int} #0#5 : let final dynamic #t4 = #0#5#isSet = true in #0#5 = #0#0.{core::List::[]}(1){(core::int) → core::int}) is core::int) { + y = #0#5#isSet ?{core::int} #0#5 : let final dynamic #t5 = #0#5#isSet = true in #0#5 = #0#0.{core::List::[]}(1){(core::int) → core::int}; { self::expectEquals(x, 0); self::expectEquals(y, 0); diff --git a/pkg/front_end/testcases/patterns/matching_and_capturing_accesses_list_element_once.dart.strong.transformed.expect b/pkg/front_end/testcases/patterns/matching_and_capturing_accesses_list_element_once.dart.strong.transformed.expect index 4fc3aa2708c..ab9e2c9b799 100644 --- a/pkg/front_end/testcases/patterns/matching_and_capturing_accesses_list_element_once.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/patterns/matching_and_capturing_accesses_list_element_once.dart.strong.transformed.expect @@ -534,8 +534,8 @@ static method main() → dynamic { { hoisted core::int x; hoisted core::int y; - if(#0#0.{self::A::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C8 && ((#0#4#isSet ?{core::int} #0#4 : let final dynamic #t10 = #0#4#isSet = true in #0#4 = #0#0.{self::A::[]}(0){(core::int) → core::int}) is core::int && (let final dynamic #t11 = x = #0#4#isSet ?{core::int} #0#4 : let final dynamic #t12 = #0#4#isSet = true in #0#4 = #0#0.{self::A::[]}(0){(core::int) → core::int} in true)) && (#0#5#isSet ?{core::int} #0#5 : let final dynamic #t13 = #0#5#isSet = true in #0#5 = #0#0.{self::A::[]}(1){(core::int) → core::int}) is core::int) { - y = #0#5#isSet ?{core::int} #0#5 : let final dynamic #t14 = #0#5#isSet = true in #0#5 = #0#0.{self::A::[]}(1){(core::int) → core::int}; + if(#0#0.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C8 && ((#0#4#isSet ?{core::int} #0#4 : let final dynamic #t10 = #0#4#isSet = true in #0#4 = #0#0.{core::List::[]}(0){(core::int) → core::int}) is core::int && (let final dynamic #t11 = x = #0#4#isSet ?{core::int} #0#4 : let final dynamic #t12 = #0#4#isSet = true in #0#4 = #0#0.{core::List::[]}(0){(core::int) → core::int} in true)) && (#0#5#isSet ?{core::int} #0#5 : let final dynamic #t13 = #0#5#isSet = true in #0#5 = #0#0.{core::List::[]}(1){(core::int) → core::int}) is core::int) { + y = #0#5#isSet ?{core::int} #0#5 : let final dynamic #t14 = #0#5#isSet = true in #0#5 = #0#0.{core::List::[]}(1){(core::int) → core::int}; { self::expectEquals(x, 0); self::expectEquals(y, 0); diff --git a/pkg/front_end/testcases/patterns/never_list.dart.strong.expect b/pkg/front_end/testcases/patterns/never_list.dart.strong.expect index 0d9088951b9..819fc2d9c47 100644 --- a/pkg/front_end/testcases/patterns/never_list.dart.strong.expect +++ b/pkg/front_end/testcases/patterns/never_list.dart.strong.expect @@ -4,10 +4,11 @@ import "dart:core" as core; static method main() → void { try { - has-declared-initializer core::Object? y; + hoisted has-declared-initializer core::Object? y; { final synthesized Never #0#0 = throw 42; - if(!#0#0) + final const synthesized core::int #0#2 = #C1; + if(!(#0#0.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (let final dynamic #t1 = y = #0#0.{core::List::[]}(0){(core::int) → core::Object?} in true))) throw{for-error-handling} new core::StateError::•("Pattern matching error"); } } @@ -17,3 +18,7 @@ static method main() → void { } throw "Missing exception"; } + +constants { + #C1 = 1 +} diff --git a/pkg/front_end/testcases/patterns/never_list.dart.strong.modular.expect b/pkg/front_end/testcases/patterns/never_list.dart.strong.modular.expect index 0d9088951b9..819fc2d9c47 100644 --- a/pkg/front_end/testcases/patterns/never_list.dart.strong.modular.expect +++ b/pkg/front_end/testcases/patterns/never_list.dart.strong.modular.expect @@ -4,10 +4,11 @@ import "dart:core" as core; static method main() → void { try { - has-declared-initializer core::Object? y; + hoisted has-declared-initializer core::Object? y; { final synthesized Never #0#0 = throw 42; - if(!#0#0) + final const synthesized core::int #0#2 = #C1; + if(!(#0#0.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (let final dynamic #t1 = y = #0#0.{core::List::[]}(0){(core::int) → core::Object?} in true))) throw{for-error-handling} new core::StateError::•("Pattern matching error"); } } @@ -17,3 +18,7 @@ static method main() → void { } throw "Missing exception"; } + +constants { + #C1 = 1 +} diff --git a/pkg/front_end/testcases/patterns/never_list.dart.strong.transformed.expect b/pkg/front_end/testcases/patterns/never_list.dart.strong.transformed.expect index 0d9088951b9..819fc2d9c47 100644 --- a/pkg/front_end/testcases/patterns/never_list.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/patterns/never_list.dart.strong.transformed.expect @@ -4,10 +4,11 @@ import "dart:core" as core; static method main() → void { try { - has-declared-initializer core::Object? y; + hoisted has-declared-initializer core::Object? y; { final synthesized Never #0#0 = throw 42; - if(!#0#0) + final const synthesized core::int #0#2 = #C1; + if(!(#0#0.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (let final dynamic #t1 = y = #0#0.{core::List::[]}(0){(core::int) → core::Object?} in true))) throw{for-error-handling} new core::StateError::•("Pattern matching error"); } } @@ -17,3 +18,7 @@ static method main() → void { } throw "Missing exception"; } + +constants { + #C1 = 1 +} diff --git a/pkg/front_end/testcases/patterns/never_map.dart.strong.expect b/pkg/front_end/testcases/patterns/never_map.dart.strong.expect index 0ccd2063a24..88c75a0fcca 100644 --- a/pkg/front_end/testcases/patterns/never_map.dart.strong.expect +++ b/pkg/front_end/testcases/patterns/never_map.dart.strong.expect @@ -4,10 +4,13 @@ import "dart:core" as core; static method main() → void { try { - has-declared-initializer core::Object? b; + hoisted has-declared-initializer core::Object? b; { final synthesized Never #0#0 = throw {42: 42}; - if(!#0#0) + synthesized core::Object? #0#3; + synthesized core::bool #0#3#isSet = false; + final const synthesized core::int #0#1 = #C1; + if(!((!((#0#3#isSet ?{core::Object?} #0#3 : let final dynamic #t1 = #0#3#isSet = true in #0#3 = #0#0.{core::Map::[]}(#C1){(core::Object?) → core::Object?}) == null) || null is core::Object? && #0#0.{core::Map::containsKey}(#C1){(core::Object?) → core::bool}) && (let final dynamic #t2 = b = #0#3#isSet ?{core::Object?} #0#3 : let final dynamic #t3 = #0#3#isSet = true in #0#3 = #0#0.{core::Map::[]}(#C1){(core::Object?) → core::Object?} in true))) throw{for-error-handling} new core::StateError::•("Pattern matching error"); } } @@ -17,3 +20,7 @@ static method main() → void { } throw "Missing exception"; } + +constants { + #C1 = 42 +} diff --git a/pkg/front_end/testcases/patterns/never_map.dart.strong.modular.expect b/pkg/front_end/testcases/patterns/never_map.dart.strong.modular.expect index 0ccd2063a24..88c75a0fcca 100644 --- a/pkg/front_end/testcases/patterns/never_map.dart.strong.modular.expect +++ b/pkg/front_end/testcases/patterns/never_map.dart.strong.modular.expect @@ -4,10 +4,13 @@ import "dart:core" as core; static method main() → void { try { - has-declared-initializer core::Object? b; + hoisted has-declared-initializer core::Object? b; { final synthesized Never #0#0 = throw {42: 42}; - if(!#0#0) + synthesized core::Object? #0#3; + synthesized core::bool #0#3#isSet = false; + final const synthesized core::int #0#1 = #C1; + if(!((!((#0#3#isSet ?{core::Object?} #0#3 : let final dynamic #t1 = #0#3#isSet = true in #0#3 = #0#0.{core::Map::[]}(#C1){(core::Object?) → core::Object?}) == null) || null is core::Object? && #0#0.{core::Map::containsKey}(#C1){(core::Object?) → core::bool}) && (let final dynamic #t2 = b = #0#3#isSet ?{core::Object?} #0#3 : let final dynamic #t3 = #0#3#isSet = true in #0#3 = #0#0.{core::Map::[]}(#C1){(core::Object?) → core::Object?} in true))) throw{for-error-handling} new core::StateError::•("Pattern matching error"); } } @@ -17,3 +20,7 @@ static method main() → void { } throw "Missing exception"; } + +constants { + #C1 = 42 +} diff --git a/pkg/front_end/testcases/patterns/never_map.dart.strong.transformed.expect b/pkg/front_end/testcases/patterns/never_map.dart.strong.transformed.expect index 0ccd2063a24..7ef4d318c82 100644 --- a/pkg/front_end/testcases/patterns/never_map.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/patterns/never_map.dart.strong.transformed.expect @@ -4,10 +4,13 @@ import "dart:core" as core; static method main() → void { try { - has-declared-initializer core::Object? b; + hoisted has-declared-initializer core::Object? b; { final synthesized Never #0#0 = throw {42: 42}; - if(!#0#0) + synthesized core::Object? #0#3; + synthesized core::bool #0#3#isSet = false; + final const synthesized core::int #0#1 = #C1; + if(!((!((#0#3#isSet ?{core::Object?} #0#3 : let final dynamic #t1 = #0#3#isSet = true in #0#3 = #0#0.{core::Map::[]}(#C1){(core::Object?) → core::Object?}) == null) || null is core::Object? && #0#0.{core::Map::containsKey}(#C1){(core::Object?) → core::bool}) && (let final dynamic #t2 = b = #0#3#isSet ?{core::Object?} #0#3 : let final dynamic #t3 = #0#3#isSet = true in #0#3 = #0#0.{core::Map::[]}(#C1){(core::Object?) → core::Object?} in true))) throw{for-error-handling} new core::StateError::•("Pattern matching error"); } } @@ -17,3 +20,11 @@ static method main() → void { } throw "Missing exception"; } + +constants { + #C1 = 42 +} + +Extra constant evaluation status: +Evaluated: IsExpression @ org-dartlang-testcase:///never_map.dart:7:12 -> BoolConstant(true) +Extra constant evaluation: evaluated: 34, effectively constant: 1 diff --git a/pkg/kernel/lib/src/ast/patterns.dart b/pkg/kernel/lib/src/ast/patterns.dart index 00d070525b9..0a196d4087c 100644 --- a/pkg/kernel/lib/src/ast/patterns.dart +++ b/pkg/kernel/lib/src/ast/patterns.dart @@ -364,7 +364,6 @@ class NullCheckPattern extends Pattern { class ListPattern extends Pattern { static const int FlagNeedsCheck = 1 << 0; static const int FlagHasRestPattern = 1 << 1; - static const int FlagIsNeverPattern = 1 << 2; int flags = 0; @@ -403,17 +402,6 @@ class ListPattern extends Pattern { /// This is set during inference. DartType? lookupType; - /// If `true`, this list pattern is performed on an expression of type - /// `Never`. - /// - /// This is set during inference. - bool get isNeverPattern => flags & FlagIsNeverPattern != 0; - void set isNeverPattern(bool value) { - flags = value - ? (flags | FlagIsNeverPattern) - : (flags & ~FlagIsNeverPattern); - } - /// If `true`, this list pattern contains a rest pattern. /// /// This is set during inference. @@ -966,7 +954,6 @@ class AssignedVariablePattern extends Pattern { class MapPattern extends Pattern { static const int FlagNeedsCheck = 1 << 0; - static const int FlagIsNeverPattern = 1 << 1; int flags = 0; @@ -1008,16 +995,6 @@ class MapPattern extends Pattern { /// This is set during inference. DartType? lookupType; - /// If `true`, this map pattern is performed on an expression of type `Never`. - /// - /// This is set during inference. - bool get isNeverPattern => flags & FlagIsNeverPattern != 0; - void set isNeverPattern(bool value) { - flags = value - ? (flags | FlagIsNeverPattern) - : (flags & ~FlagIsNeverPattern); - } - /// Reference to the target of the `containsKey` method of the map. /// /// This is set during inference.