Skip to content

Commit d43f687

Browse files
author
John Messerly
committed
fix #25794, infer parameter type from default value
[email protected] Review URL: https://codereview.chromium.org/2092873002 .
1 parent 21fb121 commit d43f687

File tree

5 files changed

+75
-28
lines changed

5 files changed

+75
-28
lines changed

pkg/analyzer/lib/src/generated/resolver.dart

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4840,7 +4840,7 @@ class InferenceContext {
48404840
* Place an info node into the error stream indicating that a
48414841
* [type] has been inferred as the type of [node].
48424842
*/
4843-
void recordInference(Expression node, DartType type) {
4843+
void recordInference(AstNode node, DartType type) {
48444844
if (!_inferenceHints) {
48454845
return;
48464846
}
@@ -5635,6 +5635,11 @@ class ResolverVisitor extends ScopedVisitor {
56355635
*/
56365636
bool resolveOnlyCommentInFunctionBody = false;
56375637

5638+
/**
5639+
* True if we're analyzing in strong mode.
5640+
*/
5641+
bool _strongMode;
5642+
56385643
/**
56395644
* Body of the function currently being analyzed, if any.
56405645
*/
@@ -5666,6 +5671,7 @@ class ResolverVisitor extends ScopedVisitor {
56665671
this.typeSystem = definingLibrary.context.typeSystem;
56675672
bool strongModeHints = false;
56685673
AnalysisOptions options = definingLibrary.context.analysisOptions;
5674+
_strongMode = options.strongMode;
56695675
if (options is AnalysisOptionsImpl) {
56705676
strongModeHints = options.strongModeHints;
56715677
}
@@ -6356,13 +6362,24 @@ class ResolverVisitor extends ScopedVisitor {
63566362

63576363
@override
63586364
Object visitDefaultFormalParameter(DefaultFormalParameter node) {
6359-
InferenceContext.setType(node.defaultValue, node.parameter.element?.type);
6360-
super.visitDefaultFormalParameter(node);
63616365
ParameterElement element = node.element;
6366+
InferenceContext.setType(node.defaultValue, element.type);
6367+
super.visitDefaultFormalParameter(node);
63626368
if (element.initializer != null && node.defaultValue != null) {
63636369
(element.initializer as FunctionElementImpl).returnType =
63646370
node.defaultValue.staticType;
63656371
}
6372+
if (_strongMode &&
6373+
node.defaultValue != null &&
6374+
element.hasImplicitType &&
6375+
element is! FieldFormalParameterElement) {
6376+
6377+
DartType type = node.defaultValue.staticType;
6378+
if (!type.isBottom && !type.isDynamic) {
6379+
(element as ParameterElementImpl).type = type;
6380+
inferenceContext.recordInference(node, type);
6381+
}
6382+
}
63666383
// Clone the ASTs for default formal parameters, so that we can use them
63676384
// during constant evaluation.
63686385
if (!LibraryElementImpl.hasResolutionCapability(

pkg/analyzer/lib/src/summary/summarize_elements.dart

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -902,10 +902,14 @@ class _CompilationUnitSerializer {
902902
DartType type = parameter.type;
903903
if (parameter.hasImplicitType) {
904904
Element contextParent = context.enclosingElement;
905+
// Strong mode infers parameters in two cases:
906+
// - instance members (i.e. not constructors or static members),
907+
// - parameters with default values, except initializing formals
908+
// (the type comes from the field).
905909
if (!parameter.isInitializingFormal &&
906910
contextParent is ExecutableElement &&
907-
!contextParent.isStatic &&
908-
contextParent is! ConstructorElement) {
911+
(!contextParent.isStatic && contextParent is! ConstructorElement ||
912+
parameter.parameterKind != ParameterKind.REQUIRED)) {
909913
b.inferredTypeSlot = storeInferredType(type, context);
910914
}
911915
} else {

pkg/analyzer/test/src/summary/resynthesize_ast_test.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,12 @@ var b = a.m();
508508
super.test_inferCorrectlyOnMultipleVariablesDeclaredTogether();
509509
}
510510

511+
@override
512+
@failingTest
513+
void test_inferDefaultFormalParameter() {
514+
super.test_inferDefaultFormalParameter();
515+
}
516+
511517
@override
512518
@failingTest
513519
void test_inferenceInCyclesIsDeterministic() {

pkg/analyzer/test/src/summary/resynthesize_test.dart

Lines changed: 15 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4107,9 +4107,7 @@ void f<T, U>() {
41074107
checkLibrary('class C { bool operator<=(C other) => false; }');
41084108
}
41094109

4110-
test_parameterTypeNotInferred_constructor() {
4111-
// Strong mode doesn't do type inference on constructor parameters, so it's
4112-
// ok that we don't store inferred type info for them in summaries.
4110+
test_parameterType_inferred_constructor() {
41134111
checkLibrary('''
41144112
class C {
41154113
C.positional([x = 1]);
@@ -4118,21 +4116,7 @@ class C {
41184116
''');
41194117
}
41204118

4121-
test_parameterTypeNotInferred_initializingFormal() {
4122-
// Strong mode doesn't do type inference on initializing formals, so it's
4123-
// ok that we don't store inferred type info for them in summaries.
4124-
checkLibrary('''
4125-
class C {
4126-
var x;
4127-
C.positional([this.x = 1]);
4128-
C.named({this.x: 1});
4129-
}
4130-
''');
4131-
}
4132-
4133-
test_parameterTypeNotInferred_staticMethod() {
4134-
// Strong mode doesn't do type inference on parameters of static methods,
4135-
// so it's ok that we don't store inferred type info for them in summaries.
4119+
test_parameterType_inferred_staticMethod() {
41364120
checkLibrary('''
41374121
class C {
41384122
static void positional([x = 1]) {}
@@ -4141,16 +4125,25 @@ class C {
41414125
''');
41424126
}
41434127

4144-
test_parameterTypeNotInferred_topLevelFunction() {
4145-
// Strong mode doesn't do type inference on parameters of top level
4146-
// functions, so it's ok that we don't store inferred type info for them in
4147-
// summaries.
4128+
test_parameterType_inferred_topLevelFunction() {
41484129
checkLibrary('''
41494130
void positional([x = 1]) {}
41504131
void named({x: 1}) {}
41514132
''');
41524133
}
41534134

4135+
test_parameterTypeNotInferred_initializingFormal() {
4136+
// Strong mode doesn't do type inference on initializing formals, so it's
4137+
// ok that we don't store inferred type info for them in summaries.
4138+
checkLibrary('''
4139+
class C {
4140+
var x;
4141+
C.positional([this.x = 1]);
4142+
C.named({this.x: 1});
4143+
}
4144+
''');
4145+
}
4146+
41544147
test_parts() {
41554148
addSource('/a.dart', 'part of my.lib;');
41564149
addSource('/b.dart', 'part of my.lib;');

pkg/analyzer/test/src/task/strong/inferred_type_test.dart

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -723,7 +723,7 @@ class Foo {
723723
}
724724
void f([List<int> l = /*info:INFERRED_TYPE_LITERAL*/const [1]]) {}
725725
// We do this inference in an early task but don't preserve the infos.
726-
Function2<List<int>, String> g = /*pass should be info:INFERRED_TYPE_CLOSURE*/([llll = /*info:INFERRED_TYPE_LITERAL*/const [1]]) => "hello";
726+
Function2<List<int>, String> g = /*pass should be info:INFERRED_TYPE_CLOSURE*/([/*info:INFERRED_TYPE*/llll = /*info:INFERRED_TYPE_LITERAL*/const [1]]) => "hello";
727727
''');
728728
}
729729

@@ -1913,6 +1913,33 @@ foo() {
19131913
''');
19141914
}
19151915

1916+
void test_inferDefaultFormalParameter() {
1917+
var unit = checkFile('''
1918+
f([/*info:INFERRED_TYPE*/x = 42]) {}
1919+
g({/*info:INFERRED_TYPE*/x: 'hi'}) {}
1920+
''');
1921+
expect(unit.functions[0].parameters[0].type.toString(), 'int');
1922+
expect(unit.functions[1].parameters[0].type.toString(), 'String');
1923+
}
1924+
1925+
void test_inferDefaultFormalParameter_fieldFormal() {
1926+
checkFile('''
1927+
class C {
1928+
int x;
1929+
var y;
1930+
C({this.x: /*error:INVALID_ASSIGNMENT*/0.0, this.y: 'hi'}) {
1931+
String z = /*info:DYNAMIC_CAST*/y;
1932+
}
1933+
C.c([this.x =/*error:INVALID_ASSIGNMENT*/0.0, this.y = 'hi']) {
1934+
String z = /*info:DYNAMIC_CAST*/y;
1935+
}
1936+
m() {
1937+
String z = /*info:DYNAMIC_CAST*/y;
1938+
}
1939+
}
1940+
''');
1941+
}
1942+
19161943
void test_inferedType_usesSyntheticFunctionType() {
19171944
var mainUnit = checkFile('''
19181945
int f() => null;

0 commit comments

Comments
 (0)