Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(346)

Side by Side Diff: pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart

Issue 2950923002: Add type inference for null-aware method invocations. (Closed)
Patch Set: Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 /// This file declares a "shadow hierarchy" of concrete classes which extend 5 /// This file declares a "shadow hierarchy" of concrete classes which extend
6 /// the kernel class hierarchy, adding methods and fields needed by the 6 /// the kernel class hierarchy, adding methods and fields needed by the
7 /// BodyBuilder. 7 /// BodyBuilder.
8 /// 8 ///
9 /// Instances of these classes may be created using the factory methods in 9 /// Instances of these classes may be created using the factory methods in
10 /// `ast_factory.dart`. 10 /// `ast_factory.dart`.
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
46 if (arguments is KernelArguments) { 46 if (arguments is KernelArguments) {
47 return arguments._hasExplicitTypeArguments ? arguments.types : null; 47 return arguments._hasExplicitTypeArguments ? arguments.types : null;
48 } else { 48 } else {
49 // This code path should only be taken in situations where there are no 49 // This code path should only be taken in situations where there are no
50 // type arguments at all, e.g. calling a user-definable operator. 50 // type arguments at all, e.g. calling a user-definable operator.
51 assert(arguments.types.isEmpty); 51 assert(arguments.types.isEmpty);
52 return null; 52 return null;
53 } 53 }
54 } 54 }
55 55
56 bool _isOverloadableArithmeticOperator(String name) {
57 return identical(name, '+') ||
58 identical(name, '-') ||
59 identical(name, '*') ||
60 identical(name, '%');
61 }
62
63 bool _isUserDefinableOperator(String name) {
64 return identical(name, '<') ||
65 identical(name, '>') ||
66 identical(name, '<=') ||
67 identical(name, '>=') ||
68 identical(name, '==') ||
69 identical(name, '-') ||
70 identical(name, '+') ||
71 identical(name, '/') ||
72 identical(name, '~/') ||
73 identical(name, '*') ||
74 identical(name, '%') ||
75 identical(name, '|') ||
76 identical(name, '^') ||
77 identical(name, '&') ||
78 identical(name, '<<') ||
79 identical(name, '>>') ||
80 identical(name, '[]=') ||
81 identical(name, '~');
82 }
83
84 /// Concrete shadow object representing a set of invocation arguments. 56 /// Concrete shadow object representing a set of invocation arguments.
85 class KernelArguments extends Arguments { 57 class KernelArguments extends Arguments {
86 bool _hasExplicitTypeArguments; 58 bool _hasExplicitTypeArguments;
87 59
88 KernelArguments(List<Expression> positional, 60 KernelArguments(List<Expression> positional,
89 {List<DartType> types, List<NamedExpression> named}) 61 {List<DartType> types, List<NamedExpression> named})
90 : _hasExplicitTypeArguments = types != null && types.isNotEmpty, 62 : _hasExplicitTypeArguments = types != null && types.isNotEmpty,
91 super(positional, types: types, named: named); 63 super(positional, types: types, named: named);
92 64
93 static void setExplicitArgumentTypes( 65 static void setExplicitArgumentTypes(
(...skipping 1258 matching lines...) Expand 10 before | Expand all | Expand 10 after
1352 KernelMethodInvocation(Expression receiver, Name name, Arguments arguments, 1324 KernelMethodInvocation(Expression receiver, Name name, Arguments arguments,
1353 {bool isImplicitCall: false, Member interfaceTarget}) 1325 {bool isImplicitCall: false, Member interfaceTarget})
1354 : _isImplicitCall = isImplicitCall, 1326 : _isImplicitCall = isImplicitCall,
1355 super(receiver, name, arguments, interfaceTarget); 1327 super(receiver, name, arguments, interfaceTarget);
1356 1328
1357 @override 1329 @override
1358 void _collectDependencies(KernelDependencyCollector collector) { 1330 void _collectDependencies(KernelDependencyCollector collector) {
1359 // The inference dependencies are the inference dependencies of the 1331 // The inference dependencies are the inference dependencies of the
1360 // receiver. 1332 // receiver.
1361 collector.collectDependencies(receiver); 1333 collector.collectDependencies(receiver);
1362 if (_isOverloadableArithmeticOperator(name.name)) { 1334 if (isOverloadableArithmeticOperator(name.name)) {
1363 collector.collectDependencies(arguments.positional[0]); 1335 collector.collectDependencies(arguments.positional[0]);
1364 } 1336 }
1365 } 1337 }
1366 1338
1367 @override 1339 @override
1368 DartType _inferExpression( 1340 DartType _inferExpression(
1369 KernelTypeInferrer inferrer, DartType typeContext, bool typeNeeded) { 1341 KernelTypeInferrer inferrer, DartType typeContext, bool typeNeeded) {
1370 typeNeeded = inferrer.listener.methodInvocationEnter(this, typeContext) || 1342 return inferrer.inferMethodInvocation(this, receiver, fileOffset, this,
1371 typeNeeded; 1343 _isImplicitCall, typeContext, typeNeeded);
1372 // First infer the receiver so we can look up the method that was invoked.
1373 var receiverType = inferrer.inferExpression(receiver, null, true);
1374 bool isOverloadedArithmeticOperator = false;
1375 Member interfaceMember =
1376 inferrer.findMethodInvocationMember(receiverType, this);
1377 if (interfaceMember is Procedure) {
1378 isOverloadedArithmeticOperator = inferrer.typeSchemaEnvironment
1379 .isOverloadedArithmeticOperatorAndType(interfaceMember, receiverType);
1380 }
1381 var calleeType = inferrer.getCalleeFunctionType(
1382 interfaceMember, receiverType, name, !_isImplicitCall);
1383 bool forceArgumentInference = false;
1384 if (inferrer.isDryRun) {
1385 if (_isUserDefinableOperator(name.name)) {
1386 // If this is an overloadable arithmetic operator, then type inference
1387 // might depend on the RHS, so conservatively assume it does.
1388 forceArgumentInference = _isOverloadableArithmeticOperator(name.name);
1389 } else {
1390 // If no type arguments were given, then type inference might depend on
1391 // the arguments (because the called method might be generic), so
1392 // conservatively assume it does.
1393 forceArgumentInference = getExplicitTypeArguments(arguments) == null;
1394 }
1395 }
1396 var inferredType = inferrer.inferInvocation(typeContext, typeNeeded,
1397 fileOffset, calleeType, calleeType.returnType, arguments,
1398 isOverloadedArithmeticOperator: isOverloadedArithmeticOperator,
1399 receiverType: receiverType,
1400 forceArgumentInference: forceArgumentInference);
1401 inferrer.listener.methodInvocationExit(this, inferredType);
1402 return inferredType;
1403 } 1344 }
1404 } 1345 }
1405 1346
1406 /// Shadow object for [Not]. 1347 /// Shadow object for [Not].
1407 class KernelNot extends Not implements KernelExpression { 1348 class KernelNot extends Not implements KernelExpression {
1408 KernelNot(Expression operand) : super(operand); 1349 KernelNot(Expression operand) : super(operand);
1409 1350
1410 @override 1351 @override
1411 void _collectDependencies(KernelDependencyCollector collector) { 1352 void _collectDependencies(KernelDependencyCollector collector) {
1412 collector.collectDependencies(operand); 1353 collector.collectDependencies(operand);
1413 } 1354 }
1414 1355
1415 @override 1356 @override
1416 DartType _inferExpression( 1357 DartType _inferExpression(
1417 KernelTypeInferrer inferrer, DartType typeContext, bool typeNeeded) { 1358 KernelTypeInferrer inferrer, DartType typeContext, bool typeNeeded) {
1418 typeNeeded = inferrer.listener.notEnter(this, typeContext) || typeNeeded; 1359 typeNeeded = inferrer.listener.notEnter(this, typeContext) || typeNeeded;
1419 // First infer the receiver so we can look up the method that was invoked. 1360 // First infer the receiver so we can look up the method that was invoked.
1420 var boolType = inferrer.coreTypes.boolClass.rawType; 1361 var boolType = inferrer.coreTypes.boolClass.rawType;
1421 inferrer.inferExpression(operand, boolType, false); 1362 inferrer.inferExpression(operand, boolType, false);
1422 DartType inferredType = typeNeeded ? boolType : null; 1363 DartType inferredType = typeNeeded ? boolType : null;
1423 inferrer.listener.notExit(this, inferredType); 1364 inferrer.listener.notExit(this, inferredType);
1424 return inferredType; 1365 return inferredType;
1425 } 1366 }
1426 } 1367 }
1427 1368
1369 /// Concrete shadow object representing a null-aware method invocation.
1370 ///
1371 /// A null-aware method invocation of the form `a?.b(...)` is represented as the
1372 /// expression:
1373 ///
1374 /// let v = a in v == null ? null : v.b(...)
1375 class KernelNullAwareMethodInvocation extends Let implements KernelExpression {
1376 KernelNullAwareMethodInvocation(VariableDeclaration variable, Expression body)
1377 : super(variable, body);
1378
1379 @override
1380 ConditionalExpression get body => super.body;
1381
1382 MethodInvocation get _desugaredInvocation => body.otherwise;
1383
1384 @override
1385 void _collectDependencies(KernelDependencyCollector collector) {
1386 // Null aware expressions are not immediately evident.
1387 collector.recordNotImmediatelyEvident(fileOffset);
1388 }
1389
1390 @override
1391 DartType _inferExpression(
1392 KernelTypeInferrer inferrer, DartType typeContext, bool typeNeeded) {
1393 var inferredType = inferrer.inferMethodInvocation(
1394 this,
1395 variable.initializer,
1396 fileOffset,
1397 _desugaredInvocation,
1398 false,
1399 typeContext,
1400 true,
1401 receiverVariable: variable);
1402 body.staticType = inferredType;
1403 return inferredType;
1404 }
1405 }
1406
1428 /// Concrete shadow object representing a null-aware read from a property. 1407 /// Concrete shadow object representing a null-aware read from a property.
1429 /// 1408 ///
1430 /// A null-aware property get of the form `a?.b` is represented as the kernel 1409 /// A null-aware property get of the form `a?.b` is represented as the kernel
1431 /// expression: 1410 /// expression:
1432 /// 1411 ///
1433 /// let v = a in v == null ? null : v.b 1412 /// let v = a in v == null ? null : v.b
1434 class KernelNullAwarePropertyGet extends Let implements KernelExpression { 1413 class KernelNullAwarePropertyGet extends Let implements KernelExpression {
1435 KernelNullAwarePropertyGet( 1414 KernelNullAwarePropertyGet(
1436 VariableDeclaration variable, ConditionalExpression body) 1415 VariableDeclaration variable, ConditionalExpression body)
1437 : super(variable, body); 1416 : super(variable, body);
(...skipping 848 matching lines...) Expand 10 before | Expand all | Expand 10 after
2286 } 2265 }
2287 2266
2288 transformChildren(v) { 2267 transformChildren(v) {
2289 return internalError("Internal error: Unsupported operation."); 2268 return internalError("Internal error: Unsupported operation.");
2290 } 2269 }
2291 2270
2292 visitChildren(v) { 2271 visitChildren(v) {
2293 return internalError("Internal error: Unsupported operation."); 2272 return internalError("Internal error: Unsupported operation.");
2294 } 2273 }
2295 } 2274 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698