[analyzer] Fix #32913, no error for inferring a non-const type argument in a generic function used in a const location

Bug: 32913
Change-Id: I7e5ef10fdd9befdc7d8a19b2c5c5b91639c82666
Fixed: 33439
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/91105
Commit-Queue: Mike Fairhurst <mfairhurst@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Paul Berry <paulberry@google.com>
This commit is contained in:
Mike Fairhurst 2020-02-06 20:33:02 +00:00 committed by commit-bot@chromium.org
parent a62b9c8d23
commit a98f4acd1a
3 changed files with 141 additions and 0 deletions

View file

@ -24,6 +24,7 @@ import 'package:analyzer/src/dart/constant/utilities.dart';
import 'package:analyzer/src/dart/constant/value.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/member.dart';
import 'package:analyzer/src/dart/element/type_visitor.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/generated/constant.dart';
import 'package:analyzer/src/generated/engine.dart';
@ -1690,6 +1691,13 @@ class ConstantVisitor extends UnifyingAstVisitor<DartObjectImpl> {
element = element?.declaration;
Element variableElement =
element is PropertyAccessorElement ? element.variable : element;
if (node is SimpleIdentifier &&
(node.tearOffTypeArgumentTypes?.any(_hasAppliedTypeParameters) ??
false)) {
_error(node, null);
}
if (variableElement is VariableElementImpl) {
// We access values of constant variables here in two cases: when we
// compute values of other constant variables, or when we compute values
@ -1755,6 +1763,13 @@ class ConstantVisitor extends UnifyingAstVisitor<DartObjectImpl> {
return null;
}
/// Check if any type parameters are referenced by [type], which is an error.
bool _hasAppliedTypeParameters(DartType type) {
final visitor = _ReferencesTypeParameterVisitor();
DartTypeVisitor.visit(type, visitor);
return visitor.result;
}
/// Return `true` if the given [targetResult] represents a string and the
/// [identifier] is "length".
bool _isStringLength(
@ -1801,6 +1816,27 @@ class ConstantVisitor extends UnifyingAstVisitor<DartObjectImpl> {
}
}
/// A visitor to find if a type contains any [TypeParameterType]s.
///
/// To find the result, check [result] on this instance after visiting the tree.
/// The actual value returned by the visit methods is merely used so that
/// [RecursiveTypeVisitor] stops visiting the type once the first type parameter
/// type is found.
class _ReferencesTypeParameterVisitor extends RecursiveTypeVisitor {
/// The result of whether any type parameters were found.
bool result = false;
@override
bool visitTypeParameterType(_) {
result = true;
// Stop visiting at this point.
return false;
}
@override
bool defaultDartType(_) => true; // Continue visiting in this case.
}
/// A utility class that contains methods for manipulating instances of a Dart
/// class and for collecting errors during evaluation.
class DartObjectComputer {

View file

@ -0,0 +1,103 @@
// Copyright (c) 2020, 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.
import 'package:analyzer/src/error/codes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../../generated/test_support.dart';
import '../dart/resolution/driver_resolution.dart';
main() {
defineReflectiveSuite(() {
defineReflectiveTests(NonConstantDefaultValueTest);
});
}
@reflectiveTest
class NonConstantDefaultValueTest extends DriverResolutionTest {
test_appliedTypeParameter_defaultConstructorValue() async {
await assertErrorsInCode(r'''
void f<T>(T t) => t;
class C<T> {
final void Function(T) p;
const C({this.p = f});
}
''', [ExpectedError(CompileTimeErrorCode.NON_CONSTANT_DEFAULT_VALUE, 83, 1)]);
}
test_appliedTypeParameter_defaultFunctionValue() async {
await assertErrorsInCode(r'''
void f<T>(T t) => t;
void bar<T>([void Function(T) p = f]) {}
''', [ExpectedError(CompileTimeErrorCode.NON_CONSTANT_DEFAULT_VALUE, 56, 1)]);
}
test_appliedTypeParameter_defaultMethodValue() async {
await assertErrorsInCode(r'''
void f<T>(T t) => t;
class C<T> {
void foo([void Function(T) p = f]) {}
}
''', [ExpectedError(CompileTimeErrorCode.NON_CONSTANT_DEFAULT_VALUE, 68, 1)]);
}
test_appliedTypeParameter_nested() async {
await assertErrorsInCode(r'''
void f<T>(T t) => t;
void bar<T>([void Function(List<T>) p = f]) {}
''', [ExpectedError(CompileTimeErrorCode.NON_CONSTANT_DEFAULT_VALUE, 62, 1)]);
}
test_appliedTypeParameter_nestedFunction() async {
await assertErrorsInCode(r'''
void f<T>(T t) => t;
void bar<T>([void Function(T Function()) p = f]) {}
''', [ExpectedError(CompileTimeErrorCode.NON_CONSTANT_DEFAULT_VALUE, 67, 1)]);
}
test_noAppliedTypeParameters_defaultConstructorValue_dynamic() async {
await assertNoErrorsInCode(r'''
void f<T>(T t) => t;
class C<T> {
final dynamic p;
const C({this.p = f});
}
''');
}
test_noAppliedTypeParameters_defaultConstructorValue_genericFn() async {
await assertNoErrorsInCode(r'''
void f<T>(T t) => t;
class C<T> {
final void Function<T>(T) p;
const C({this.p = f});
}
''');
}
test_noAppliedTypeParameters_defaultFunctionValue_genericFn() async {
await assertNoErrorsInCode(r'''
void f<T>(T t) => t;
void bar<T>([void Function<T>(T) p = f]) {}
''');
}
test_noAppliedTypeParameters_defaultMethodValue_genericFn() async {
await assertNoErrorsInCode(r'''
void f<T>(T t) => t;
class C<T> {
void foo([void Function<T>(T) p = f]) {}
}
''');
}
}

View file

@ -288,6 +288,7 @@ import 'non_bool_operand_test.dart' as non_bool_operand;
import 'non_constant_case_expression_from_deferred_library_test.dart'
as non_constant_case_expression_from_deferred_library;
import 'non_constant_case_expression_test.dart' as non_constant_case_expression;
import 'non_constant_default_value_test.dart' as non_constant_default_value;
import 'non_constant_list_element_from_deferred_library_test.dart'
as non_constant_list_element_from_deferred_library;
import 'non_constant_list_element_test.dart' as non_constant_list_element;
@ -808,6 +809,7 @@ main() {
undefined_prefixed_name.main();
undefined_setter.main();
undefined_shown_name.main();
non_constant_default_value.main();
unnecessary_cast.main();
unnecessary_no_such_method.main();
unnecessary_non_null_assertion.main();