Version 2.13.0-42.0.dev
Merge commit '4d5f027ccb2d998771677067a621bdd582ddfaf6' into 'dev'
diff --git a/pkg/analysis_server/test/src/domains/completion/get_suggestion_details_test.dart b/pkg/analysis_server/test/src/domains/completion/get_suggestion_details_test.dart
index 7ed929c..7876489 100644
--- a/pkg/analysis_server/test/src/domains/completion/get_suggestion_details_test.dart
+++ b/pkg/analysis_server/test/src/domains/completion/get_suggestion_details_test.dart
@@ -115,6 +115,104 @@
''');
}
+ Future<void> test_newImport_afterLibraryBeforeFirstImportsAnnotation() async {
+ // Annotations are only treated as being for the file if they are on the first
+ // directive of the file.
+ addTestFile(r'''
+library foo;
+
+@myAnnotation
+import 'package:zzz';
+
+main() {} // ref
+''');
+
+ var mathSet = await waitForSetWithUri('dart:math');
+ var result = await _getSuggestionDetails(
+ _buildRequest(
+ id: mathSet.id,
+ label: 'sin',
+ offset: testCode.indexOf('} // ref'),
+ ),
+ );
+
+ expect(result.completion, 'sin');
+ _assertTestFileChange(result.change, r'''
+library foo;
+
+import 'dart:math';
+
+@myAnnotation
+import 'package:zzz';
+
+main() {} // ref
+''');
+ }
+
+ Future<void> test_newImport_betweenAnnotationAndFirstImport() async {
+ // Annotations attached to the first import in a file are considered
+ // to be for the file, so if an import is inserted in the top position, it
+ // should go after the annotation.
+ addTestFile(r'''
+@myAnnotation
+
+import 'package:zzz';
+
+main() {} // ref
+''');
+
+ var mathSet = await waitForSetWithUri('dart:math');
+ var result = await _getSuggestionDetails(
+ _buildRequest(
+ id: mathSet.id,
+ label: 'sin',
+ offset: testCode.indexOf('} // ref'),
+ ),
+ );
+
+ expect(result.completion, 'sin');
+ _assertTestFileChange(result.change, r'''
+@myAnnotation
+
+import 'dart:math';
+
+import 'package:zzz';
+
+main() {} // ref
+''');
+ }
+
+ Future<void> test_newImport_notBetweenAnnotationAndNonFirstImport() async {
+ // Annotations on non-first directives should not be kept above the newly
+ // imported imports (opposite of test_newImport_betweenAnnotationAndFirstImport).
+ addTestFile(r'''
+import 'dart:async';
+@myAnnotation
+import 'package:zzz';
+
+main() {} // ref
+''');
+
+ var mathSet = await waitForSetWithUri('dart:math');
+ var result = await _getSuggestionDetails(
+ _buildRequest(
+ id: mathSet.id,
+ label: 'sin',
+ offset: testCode.indexOf('} // ref'),
+ ),
+ );
+
+ expect(result.completion, 'sin');
+ _assertTestFileChange(result.change, r'''
+import 'dart:async';
+import 'dart:math';
+@myAnnotation
+import 'package:zzz';
+
+main() {} // ref
+''');
+ }
+
Future<void> test_newImport_part() async {
var partCode = r'''
part of 'test.dart';
diff --git a/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart b/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart
index 83c5b04..6f0ab75 100644
--- a/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart
+++ b/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart
@@ -1515,7 +1515,14 @@
writeImport(builder, import);
});
} else {
- var offset = next.offset;
+ // Annotations attached to the first directive should remain above
+ // the newly inserted import, as they are treated as being for the
+ // file.
+ var isFirst =
+ next == (next.parent as CompilationUnit).directives.first;
+ var offset = isFirst && next is AnnotatedNode
+ ? next.firstTokenAfterCommentAndMetadata.offset
+ : next.offset;
addInsertion(offset, (EditBuilder builder) {
writeImport(builder, import);
builder.writeln();
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 8aa06a4..ef11697 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -3172,7 +3172,6 @@
// modified by finalization, only shifted to higher indices in the vector.
// The super type may not even be resolved yet. This is not necessary, since
// we only check for matching type parameters, which are resolved by default.
- const auto& type_params = TypeArguments::Handle(zone, type_parameters());
// Determine the maximum overlap of a prefix of the vector consisting of the
// type parameters of this class with a suffix of the vector consisting of the
// type arguments of the super type of this class.
@@ -3181,7 +3180,6 @@
// Attempt to overlap the whole vector of type parameters; reduce the size
// of the vector (keeping the first type parameter) until it fits or until
// its size is zero.
- auto& type_param = TypeParameter::Handle(zone);
auto& sup_type_arg = AbstractType::Handle(zone);
for (intptr_t num_overlapping_type_args =
(num_type_params < sup_type_args_length) ? num_type_params
@@ -3189,12 +3187,19 @@
num_overlapping_type_args > 0; num_overlapping_type_args--) {
intptr_t i = 0;
for (; i < num_overlapping_type_args; i++) {
- type_param ^= type_params.TypeAt(i);
- ASSERT(!type_param.IsNull());
sup_type_arg = sup_type_args.TypeAt(sup_type_args_length -
num_overlapping_type_args + i);
ASSERT(!sup_type_arg.IsNull());
- if (!type_param.Equals(sup_type_arg)) break;
+ if (!sup_type_arg.IsTypeParameter()) break;
+ // The only type parameters appearing in the type arguments of the super
+ // type are those declared by this class. Their finalized indices depend
+ // on the number of type arguments being computed here. Therefore, they
+ // cannot possibly be finalized yet.
+ ASSERT(!TypeParameter::Cast(sup_type_arg).IsFinalized());
+ if (TypeParameter::Cast(sup_type_arg).index() != i ||
+ TypeParameter::Cast(sup_type_arg).IsNullable()) {
+ break;
+ }
}
if (i == num_overlapping_type_args) {
// Overlap found.
@@ -21033,12 +21038,12 @@
return false;
}
const TypeParameter& other_type_param = TypeParameter::Cast(other);
+ ASSERT(IsFinalized() && other_type_param.IsFinalized());
// Compare index, name, bound, default argument, and flags.
if (IsFunctionTypeParameter()) {
if (!other_type_param.IsFunctionTypeParameter()) {
return false;
}
- ASSERT(IsFinalized() && other_type_param.IsFinalized());
if (kind == TypeEquality::kInSubtypeTest) {
// To be equivalent, the function type parameters should be declared
// at the same position in the generic function. Their index therefore
@@ -21105,7 +21110,6 @@
return false;
}
} else {
- ASSERT(IsFinalized() && other_type_param.IsFinalized());
if (index() != other_type_param.index()) {
return false;
}
diff --git a/tests/language/regress/regress179942377_test.dart b/tests/language/regress/regress179942377_test.dart
new file mode 100644
index 0000000..f9decac
--- /dev/null
+++ b/tests/language/regress/regress179942377_test.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2021, 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.
+
+// Regression test for issue 179942377.
+
+import 'package:expect/expect.dart';
+
+class A<T> {
+ bool test() {
+ return null is T;
+ }
+}
+
+class B<T> extends A<T?> {}
+
+void main() {
+ Expect.isTrue(B<int>().test());
+}
diff --git a/tools/VERSION b/tools/VERSION
index 0933579..7b6bfe1 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 13
PATCH 0
-PRERELEASE 41
+PRERELEASE 42
PRERELEASE_PATCH 0
\ No newline at end of file