mirror of
https://github.com/dart-lang/sdk
synced 2024-07-20 04:25:52 +00:00
Use pattern type schema for expression inference.
0277f03586
Change-Id: Ie305303ad85c0c7c920f9a28f4357abd9a02de3f
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/281580
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Paul Berry <paulberry@google.com>
This commit is contained in:
parent
e8842d862c
commit
55e0784a62
|
@ -1180,7 +1180,9 @@ mixin TypeAnalyzer<
|
|||
required void Function() dispatchBody,
|
||||
}) {
|
||||
// Stack: ()
|
||||
Type expressionType = analyzeExpression(expression, unknownType);
|
||||
Type patternTypeSchema = dispatchPatternSchema(pattern);
|
||||
Type expressionTypeSchema = iterableType(patternTypeSchema);
|
||||
Type expressionType = analyzeExpression(expression, expressionTypeSchema);
|
||||
// Stack: (Expression)
|
||||
|
||||
Type? elementType = operations.matchIterableType(expressionType);
|
||||
|
@ -1950,6 +1952,9 @@ mixin TypeAnalyzer<
|
|||
/// Queries whether [pattern] is a variable pattern.
|
||||
bool isVariablePattern(Node pattern);
|
||||
|
||||
/// Returns the type `Iterable`, with type argument [elementType].
|
||||
Type iterableType(Type elementType);
|
||||
|
||||
/// Returns the type `List`, with type argument [elementType].
|
||||
Type listType(Type elementType);
|
||||
|
||||
|
|
|
@ -1067,10 +1067,10 @@ class MiniAstOperations
|
|||
|
||||
@override
|
||||
Type? matchIterableType(Type type) {
|
||||
if (type is PrimaryType &&
|
||||
type.name == 'Iterable' &&
|
||||
type.args.length == 1) {
|
||||
return type.args[0];
|
||||
if (type is PrimaryType && type.args.length == 1) {
|
||||
if (type.name == 'Iterable' || type.name == 'List') {
|
||||
return type.args[0];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -3832,6 +3832,11 @@ class _MiniAstTypeAnalyzer
|
|||
@override
|
||||
bool isVariablePattern(Node pattern) => pattern is _VariablePattern;
|
||||
|
||||
@override
|
||||
Type iterableType(Type elementType) {
|
||||
return PrimaryType('Iterable', args: [elementType]);
|
||||
}
|
||||
|
||||
Type leastUpperBound(Type t1, Type t2) => _harness._operations._lub(t1, t2);
|
||||
|
||||
@override
|
||||
|
|
|
@ -1634,6 +1634,26 @@ main() {
|
|||
});
|
||||
|
||||
group('Pattern-for-in:', () {
|
||||
group('Expression context type schema:', () {
|
||||
test('Pattern has type', () {
|
||||
var x = Var('x');
|
||||
h.run([
|
||||
patternForIn(x.pattern(type: 'num'),
|
||||
expr('List<int>').checkContext('Iterable<num>'), [])
|
||||
.checkIr('forEach(expr(List<int>), varPattern(x, '
|
||||
'matchedType: int, staticType: num), block())'),
|
||||
]);
|
||||
});
|
||||
test('Pattern does not have type', () {
|
||||
var x = Var('x');
|
||||
h.run([
|
||||
patternForIn(x.pattern(),
|
||||
expr('List<int>').checkContext('Iterable<?>'), [])
|
||||
.checkIr('forEach(expr(List<int>), varPattern(x, '
|
||||
'matchedType: int, staticType: int), block())'),
|
||||
]);
|
||||
});
|
||||
});
|
||||
group('Expression type:', () {
|
||||
test('Iterable', () {
|
||||
var x = Var('x');
|
||||
|
|
|
@ -1211,6 +1211,11 @@ class ResolverVisitor extends ThrowingAstVisitor<void>
|
|||
@override
|
||||
bool isVariablePattern(AstNode pattern) => pattern is DeclaredVariablePattern;
|
||||
|
||||
@override
|
||||
DartType iterableType(DartType elementType) {
|
||||
return typeProvider.iterableType(elementType);
|
||||
}
|
||||
|
||||
@override
|
||||
DartType listType(DartType elementType) {
|
||||
return typeProvider.listType(elementType);
|
||||
|
|
|
@ -176,6 +176,98 @@ ForElement
|
|||
''');
|
||||
}
|
||||
|
||||
test_iterableContextType_patternVariable_typed() async {
|
||||
await assertNoErrorsInCode(r'''
|
||||
void f() {
|
||||
[for (var (int a) in g()) a];
|
||||
}
|
||||
|
||||
T g<T>() => throw 0;
|
||||
''');
|
||||
var node = findNode.singleForElement;
|
||||
assertResolvedNodeText(node, r'''
|
||||
ForElement
|
||||
forKeyword: for
|
||||
leftParenthesis: (
|
||||
forLoopParts: ForEachPartsWithPattern
|
||||
keyword: var
|
||||
pattern: ParenthesizedPattern
|
||||
leftParenthesis: (
|
||||
pattern: DeclaredVariablePattern
|
||||
type: NamedType
|
||||
name: SimpleIdentifier
|
||||
token: int
|
||||
staticElement: dart:core::@class::int
|
||||
staticType: null
|
||||
type: int
|
||||
name: a
|
||||
declaredElement: a@28
|
||||
type: int
|
||||
rightParenthesis: )
|
||||
inKeyword: in
|
||||
iterable: MethodInvocation
|
||||
methodName: SimpleIdentifier
|
||||
token: g
|
||||
staticElement: self::@function::g
|
||||
staticType: T Function<T>()
|
||||
argumentList: ArgumentList
|
||||
leftParenthesis: (
|
||||
rightParenthesis: )
|
||||
staticInvokeType: Iterable<int> Function()
|
||||
staticType: Iterable<int>
|
||||
typeArgumentTypes
|
||||
Iterable<int>
|
||||
rightParenthesis: )
|
||||
body: SimpleIdentifier
|
||||
token: a
|
||||
staticElement: a@28
|
||||
staticType: int
|
||||
''');
|
||||
}
|
||||
|
||||
test_iterableContextType_patternVariable_untyped() async {
|
||||
await assertNoErrorsInCode(r'''
|
||||
void f() {
|
||||
[for (var (a) in g()) a];
|
||||
}
|
||||
|
||||
T g<T>() => throw 0;
|
||||
''');
|
||||
var node = findNode.singleForElement;
|
||||
assertResolvedNodeText(node, r'''
|
||||
ForElement
|
||||
forKeyword: for
|
||||
leftParenthesis: (
|
||||
forLoopParts: ForEachPartsWithPattern
|
||||
keyword: var
|
||||
pattern: ParenthesizedPattern
|
||||
leftParenthesis: (
|
||||
pattern: DeclaredVariablePattern
|
||||
name: a
|
||||
declaredElement: hasImplicitType a@24
|
||||
type: Object?
|
||||
rightParenthesis: )
|
||||
inKeyword: in
|
||||
iterable: MethodInvocation
|
||||
methodName: SimpleIdentifier
|
||||
token: g
|
||||
staticElement: self::@function::g
|
||||
staticType: T Function<T>()
|
||||
argumentList: ArgumentList
|
||||
leftParenthesis: (
|
||||
rightParenthesis: )
|
||||
staticInvokeType: Iterable<Object?> Function()
|
||||
staticType: Iterable<Object?>
|
||||
typeArgumentTypes
|
||||
Iterable<Object?>
|
||||
rightParenthesis: )
|
||||
body: SimpleIdentifier
|
||||
token: a
|
||||
staticElement: a@24
|
||||
staticType: Object?
|
||||
''');
|
||||
}
|
||||
|
||||
test_keyword_final_patternVariable() async {
|
||||
await assertNoErrorsInCode(r'''
|
||||
void f(List<int> x) {
|
||||
|
|
|
@ -532,6 +532,100 @@ ForStatement
|
|||
''');
|
||||
}
|
||||
|
||||
test_iterableContextType_patternVariable_typed() async {
|
||||
await assertErrorsInCode(r'''
|
||||
void f() {
|
||||
for (var (int a) in g()) {}
|
||||
}
|
||||
|
||||
T g<T>() => throw 0;
|
||||
''', [
|
||||
error(HintCode.UNUSED_LOCAL_VARIABLE, 27, 1),
|
||||
]);
|
||||
var node = findNode.forStatement('for');
|
||||
assertResolvedNodeText(node, r'''
|
||||
ForStatement
|
||||
forKeyword: for
|
||||
leftParenthesis: (
|
||||
forLoopParts: ForEachPartsWithPattern
|
||||
keyword: var
|
||||
pattern: ParenthesizedPattern
|
||||
leftParenthesis: (
|
||||
pattern: DeclaredVariablePattern
|
||||
type: NamedType
|
||||
name: SimpleIdentifier
|
||||
token: int
|
||||
staticElement: dart:core::@class::int
|
||||
staticType: null
|
||||
type: int
|
||||
name: a
|
||||
declaredElement: a@27
|
||||
type: int
|
||||
rightParenthesis: )
|
||||
inKeyword: in
|
||||
iterable: MethodInvocation
|
||||
methodName: SimpleIdentifier
|
||||
token: g
|
||||
staticElement: self::@function::g
|
||||
staticType: T Function<T>()
|
||||
argumentList: ArgumentList
|
||||
leftParenthesis: (
|
||||
rightParenthesis: )
|
||||
staticInvokeType: Iterable<int> Function()
|
||||
staticType: Iterable<int>
|
||||
typeArgumentTypes
|
||||
Iterable<int>
|
||||
rightParenthesis: )
|
||||
body: Block
|
||||
leftBracket: {
|
||||
rightBracket: }
|
||||
''');
|
||||
}
|
||||
|
||||
test_iterableContextType_patternVariable_untyped() async {
|
||||
await assertErrorsInCode(r'''
|
||||
void f() {
|
||||
for (var (a) in g()) {}
|
||||
}
|
||||
|
||||
T g<T>() => throw 0;
|
||||
''', [
|
||||
error(HintCode.UNUSED_LOCAL_VARIABLE, 23, 1),
|
||||
]);
|
||||
var node = findNode.forStatement('for');
|
||||
assertResolvedNodeText(node, r'''
|
||||
ForStatement
|
||||
forKeyword: for
|
||||
leftParenthesis: (
|
||||
forLoopParts: ForEachPartsWithPattern
|
||||
keyword: var
|
||||
pattern: ParenthesizedPattern
|
||||
leftParenthesis: (
|
||||
pattern: DeclaredVariablePattern
|
||||
name: a
|
||||
declaredElement: hasImplicitType a@23
|
||||
type: Object?
|
||||
rightParenthesis: )
|
||||
inKeyword: in
|
||||
iterable: MethodInvocation
|
||||
methodName: SimpleIdentifier
|
||||
token: g
|
||||
staticElement: self::@function::g
|
||||
staticType: T Function<T>()
|
||||
argumentList: ArgumentList
|
||||
leftParenthesis: (
|
||||
rightParenthesis: )
|
||||
staticInvokeType: Iterable<Object?> Function()
|
||||
staticType: Iterable<Object?>
|
||||
typeArgumentTypes
|
||||
Iterable<Object?>
|
||||
rightParenthesis: )
|
||||
body: Block
|
||||
leftBracket: {
|
||||
rightBracket: }
|
||||
''');
|
||||
}
|
||||
|
||||
test_keyword_final_patternVariable() async {
|
||||
await assertNoErrorsInCode(r'''
|
||||
void f(List<int> x) {
|
||||
|
|
|
@ -9425,6 +9425,12 @@ class InferenceVisitorImpl extends InferenceVisitorBase
|
|||
throw new UnimplementedError('TODO(paulberry)');
|
||||
}
|
||||
|
||||
@override
|
||||
DartType iterableType(DartType elementType) {
|
||||
return new InterfaceType(coreTypes.iterableClass, Nullability.nonNullable,
|
||||
<DartType>[elementType]);
|
||||
}
|
||||
|
||||
@override
|
||||
DartType listType(DartType elementType) {
|
||||
return new InterfaceType(
|
||||
|
|
Loading…
Reference in a new issue