Version 2.18.0-227.0.dev
Merge commit '0c72795f692faa01e148126761d9524d19da9bb3' into 'dev'
diff --git a/pkg/analysis_server/lib/src/cider/completion.dart b/pkg/analysis_server/lib/src/cider/completion.dart
index 86e6d59..e9a515d 100644
--- a/pkg/analysis_server/lib/src/cider/completion.dart
+++ b/pkg/analysis_server/lib/src/cider/completion.dart
@@ -7,9 +7,9 @@
import 'package:analysis_server/src/services/completion/dart/fuzzy_filter_sort.dart';
import 'package:analysis_server/src/services/completion/dart/local_library_contributor.dart';
import 'package:analysis_server/src/services/completion/dart/suggestion_builder.dart';
-import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/element/element.dart' show LibraryElement;
import 'package:analyzer/src/dart/analysis/performance_logger.dart';
+import 'package:analyzer/src/dart/analysis/results.dart';
import 'package:analyzer/src/dart/micro/resolve_file.dart';
import 'package:analyzer/src/util/performance/operation_performance.dart';
import 'package:meta/meta.dart';
@@ -51,13 +51,14 @@
required String path,
required int line,
required int column,
- @visibleForTesting void Function(ResolvedUnitResult)? testResolvedUnit,
+ @visibleForTesting
+ void Function(ResolvedForCompletionResultImpl)? testResolvedUnit,
}) async {
return _performanceRoot.runAsync('completion', (performance) async {
- var resolvedUnit = await performance.runAsync(
+ final resolvedUnit = await performance.runAsync(
'resolution',
(performance) async {
- return _fileResolver.resolve2(
+ return _fileResolver.resolveForCompletion(
completionLine: line,
completionColumn: column,
path: path,
@@ -70,12 +71,21 @@
testResolvedUnit(resolvedUnit);
}
+ final analysisSession = resolvedUnit.analysisSession;
+ final enclosingNode = resolvedUnit.parsedUnit;
+
var lineInfo = resolvedUnit.lineInfo;
var offset = lineInfo.getOffsetOfLine(line) + column;
- _dartCompletionRequest = DartCompletionRequest.forResolvedUnit(
- resolvedUnit: resolvedUnit,
+ _dartCompletionRequest = DartCompletionRequest(
+ analysisSession: analysisSession,
+ filePath: resolvedUnit.path,
+ fileContent: resolvedUnit.content,
+ unitElement: resolvedUnit.unitElement,
+ enclosingNode: enclosingNode,
offset: offset,
+ dartdocDirectiveInfo: null,
+ documentationCache: null,
);
var suggestions = await performance.runAsync(
diff --git a/pkg/analysis_server/test/src/cider/completion_test.dart b/pkg/analysis_server/test/src/cider/completion_test.dart
index 2fd1095..c43ddad 100644
--- a/pkg/analysis_server/test/src/cider/completion_test.dart
+++ b/pkg/analysis_server/test/src/cider/completion_test.dart
@@ -3,8 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analysis_server/src/cider/completion.dart';
-import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/source/line_info.dart';
+import 'package:analyzer/src/dart/analysis/results.dart';
import 'package:analyzer/src/test_utilities/function_ast_visitor.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart'
show CompletionSuggestion, CompletionSuggestionKind, ElementKind;
@@ -24,7 +24,7 @@
final CiderCompletionCache _completionCache = CiderCompletionCache();
late CiderCompletionComputer _computer;
- void Function(ResolvedUnitResult)? _testResolvedUnit;
+ void Function(ResolvedForCompletionResultImpl)? _testResolvedUnit;
late CiderCompletionResult _completionResult;
late List<CompletionSuggestion> _suggestions;
@@ -806,7 +806,7 @@
/// for completion we don't resolve unnecessary node.
void _configureToCheckNotResolved({required Set<String> identifiers}) {
_testResolvedUnit = (resolvedUnitResult) {
- var unit = resolvedUnitResult.unit;
+ var unit = resolvedUnitResult.parsedUnit;
unit.accept(
FunctionAstVisitor(
simpleIdentifier: (node) {
diff --git a/pkg/analyzer/lib/src/dart/analysis/context_locator.dart b/pkg/analyzer/lib/src/dart/analysis/context_locator.dart
index ade3b53..af049b8 100644
--- a/pkg/analyzer/lib/src/dart/analysis/context_locator.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/context_locator.dart
@@ -378,10 +378,12 @@
Workspace? workspace;
workspace = BazelWorkspace.find(resourceProvider, rootPath,
lookForBuildFileSubstitutes: false);
- workspace ??= GnWorkspace.find(resourceProvider, rootPath);
- workspace ??=
- PackageBuildWorkspace.find(resourceProvider, packages, rootPath);
- workspace ??= PubWorkspace.find(resourceProvider, packages, rootPath);
+ workspace = _mostSpecificWorkspace(
+ workspace, GnWorkspace.find(resourceProvider, rootPath));
+ workspace = _mostSpecificWorkspace(workspace,
+ PackageBuildWorkspace.find(resourceProvider, packages, rootPath));
+ workspace = _mostSpecificWorkspace(
+ workspace, PubWorkspace.find(resourceProvider, packages, rootPath));
workspace ??= BasicWorkspace.find(resourceProvider, packages, rootPath);
return workspace;
}
@@ -555,6 +557,20 @@
return true;
}
+
+ /// Pick a workspace with the most specific root. If the root of [first] is
+ /// non-null and is within the root of [second], return [second]. If any of
+ /// [first] and [second] is null, return the other one. If the roots aren't
+ /// within each other, return [first].
+ static Workspace? _mostSpecificWorkspace(
+ Workspace? first, Workspace? second) {
+ if (first == null) return second;
+ if (second == null) return first;
+ if (isWithin(first.root, second.root)) {
+ return second;
+ }
+ return first;
+ }
}
/// The packages [file] found for the [parent].
diff --git a/pkg/analyzer/lib/src/dart/analysis/results.dart b/pkg/analyzer/lib/src/dart/analysis/results.dart
index 81dcce5..223e40d 100644
--- a/pkg/analyzer/lib/src/dart/analysis/results.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/results.dart
@@ -177,6 +177,8 @@
required this.unitElement,
required this.resolvedNodes,
});
+
+ LibraryElement get libraryElement => unitElement.enclosingElement;
}
class ResolvedLibraryResultImpl extends AnalysisResultImpl
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index a2bca9a..2303065 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -5730,6 +5730,22 @@
return super.name!;
}
+ /// Instantiates this type alias with its type parameters as arguments.
+ DartType get rawType {
+ final List<DartType> typeArguments;
+ if (typeParameters.isNotEmpty) {
+ typeArguments = typeParameters.map<DartType>((t) {
+ return t.instantiate(nullabilitySuffix: _noneOrStarSuffix);
+ }).toList();
+ } else {
+ typeArguments = const <DartType>[];
+ }
+ return instantiate(
+ typeArguments: typeArguments,
+ nullabilitySuffix: _noneOrStarSuffix,
+ );
+ }
+
@override
List<TypeParameterElement> get typeParameters {
linkedData?.read(this);
diff --git a/pkg/analyzer/lib/src/dart/element/type_system.dart b/pkg/analyzer/lib/src/dart/element/type_system.dart
index 5208c75..9fc03c6 100644
--- a/pkg/analyzer/lib/src/dart/element/type_system.dart
+++ b/pkg/analyzer/lib/src/dart/element/type_system.dart
@@ -321,7 +321,11 @@
if (mixinElement.isMixin) {
candidates = mixinElement.superclassConstraints;
} else {
- candidates = [mixinElement.supertype!];
+ final supertype = mixinElement.supertype;
+ if (supertype == null) {
+ return const [];
+ }
+ candidates = [supertype];
candidates.addAll(mixinElement.mixins);
if (mixinElement.isMixinApplication) {
candidates.removeLast();
@@ -1220,16 +1224,15 @@
return (type as TypeImpl).withNullability(NullabilitySuffix.question);
}
- /// Attempts to find the appropriate substitution for the [mixinElement]
- /// type parameters that can be applied to [srcTypes] to make it equal to
- /// [destTypes]. If no such substitution can be found, `null` is returned.
+ /// Attempts to find the appropriate substitution for the [typeParameters]
+ /// that can be applied to [srcTypes] to make it equal to [destTypes].
+ /// If no such substitution can be found, `null` is returned.
List<DartType>? matchSupertypeConstraints(
- ClassElement mixinElement,
+ List<TypeParameterElement> typeParameters,
List<DartType> srcTypes,
List<DartType> destTypes, {
required bool genericMetadataIsEnabled,
}) {
- var typeParameters = mixinElement.typeParameters;
var inferrer = GenericInferrer(this, typeParameters,
genericMetadataIsEnabled: genericMetadataIsEnabled);
for (int i = 0; i < srcTypes.length; i++) {
diff --git a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
index cb41ad2..8283d1d 100644
--- a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
+++ b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
@@ -19,12 +19,12 @@
import 'package:analyzer/src/dart/analysis/experiments.dart';
import 'package:analyzer/src/dart/analysis/feature_set_provider.dart';
import 'package:analyzer/src/dart/analysis/file_state.dart';
+import 'package:analyzer/src/dart/analysis/library_analyzer.dart';
import 'package:analyzer/src/dart/analysis/library_context.dart';
import 'package:analyzer/src/dart/analysis/performance_logger.dart';
import 'package:analyzer/src/dart/analysis/results.dart';
import 'package:analyzer/src/dart/analysis/search.dart';
import 'package:analyzer/src/dart/micro/analysis_context.dart';
-import 'package:analyzer/src/dart/micro/library_analyzer.dart';
import 'package:analyzer/src/dart/micro/utils.dart';
import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl;
import 'package:analyzer/src/generated/source.dart';
@@ -511,10 +511,7 @@
releaseAndClearRemovedIds();
}
- /// The [completionLine] and [completionColumn] are zero based.
Future<ResolvedUnitResult> resolve2({
- int? completionLine,
- int? completionColumn,
required String path,
OperationPerformanceImpl? performance,
}) async {
@@ -529,23 +526,11 @@
);
var file = fileContext.file;
- // // If we have a `part of` directive, we want to analyze this library.
- // // But the library must include the file, so have its element.
- // var libraryFile = file;
- // var partOfLibrary = file.partOfLibrary;
- // if (partOfLibrary != null) {
- // if (partOfLibrary.files().ofLibrary.contains(file)) {
- // libraryFile = partOfLibrary;
- // }
- // }
final libraryKind = file.kind.library ?? file.kind.asLibrary;
final libraryFile = libraryKind.file;
var libraryResult = await resolveLibrary2(
- completionLine: completionLine,
- completionColumn: completionColumn,
path: libraryFile.path,
- completionPath: completionLine != null ? path : null,
performance: performance,
);
return libraryResult.units.firstWhere(
@@ -555,10 +540,74 @@
}
/// The [completionLine] and [completionColumn] are zero based.
+ Future<ResolvedForCompletionResultImpl> resolveForCompletion({
+ required int completionLine,
+ required int completionColumn,
+ required String path,
+ OperationPerformanceImpl? performance,
+ }) async {
+ _throwIfNotAbsoluteNormalizedPath(path);
+
+ performance ??= OperationPerformanceImpl('<default>');
+
+ return logger.runAsync('Resolve $path', () async {
+ final fileContext = getFileContext(
+ path: path,
+ performance: performance!,
+ );
+ final file = fileContext.file;
+ final libraryKind = file.kind.library ?? file.kind.asLibrary;
+
+ final lineOffset = file.lineInfo.getOffsetOfLine(completionLine);
+ final completionOffset = lineOffset + completionColumn;
+
+ await performance.runAsync('libraryContext', (performance) async {
+ await libraryContext!.load(
+ targetLibrary: libraryKind,
+ performance: performance,
+ );
+ });
+
+ final unitElement = libraryContext!.computeUnitElement(libraryKind, file);
+
+ return logger.run('Compute analysis results', () {
+ final elementFactory = libraryContext!.elementFactory;
+ final analysisSession = elementFactory.analysisSession;
+
+ var libraryAnalyzer = LibraryAnalyzer(
+ fileContext.analysisOptions,
+ contextObjects!.declaredVariables,
+ sourceFactory,
+ elementFactory.libraryOfUri2(libraryKind.file.uri),
+ analysisSession.inheritanceManager,
+ libraryKind,
+ );
+
+ final analysisResult = performance!.run('analyze', (performance) {
+ return libraryAnalyzer.analyzeForCompletion(
+ file: file,
+ offset: completionOffset,
+ unitElement: unitElement,
+ performance: performance,
+ );
+ });
+
+ return ResolvedForCompletionResultImpl(
+ analysisSession: analysisSession,
+ path: path,
+ uri: file.uri,
+ exists: file.exists,
+ content: file.content,
+ lineInfo: file.lineInfo,
+ parsedUnit: analysisResult.parsedUnit,
+ unitElement: unitElement,
+ resolvedNodes: analysisResult.resolvedNodes,
+ );
+ });
+ });
+ }
+
Future<ResolvedLibraryResult> resolveLibrary2({
- int? completionLine,
- int? completionColumn,
- String? completionPath,
required String path,
OperationPerformanceImpl? performance,
}) async {
@@ -577,24 +626,7 @@
performance: performance!,
);
var file = fileContext.file;
-
- // // If we have a `part of` directive, we want to analyze this library.
- // // But the library must include the file, so have its element.
- // var libraryFile = file;
- // var partOfLibrary = file.partOfLibrary;
- // if (partOfLibrary != null) {
- // if (partOfLibrary.files().ofLibrary.contains(file)) {
- // libraryFile = partOfLibrary;
- // }
- // }
final libraryKind = file.kind.library ?? file.kind.asLibrary;
- final libraryFile = libraryKind.file;
-
- int? completionOffset;
- if (completionLine != null && completionColumn != null) {
- var lineOffset = file.lineInfo.getOffsetOfLine(completionLine);
- completionOffset = lineOffset + completionColumn;
- }
await performance.runAsync('libraryContext', (performance) async {
await libraryContext!.load(
@@ -605,31 +637,24 @@
testData?.addResolvedLibrary(path);
- late Map<FileState, UnitAnalysisResult> results;
+ late List<UnitAnalysisResult> results;
logger.run('Compute analysis results', () {
var libraryAnalyzer = LibraryAnalyzer(
fileContext.analysisOptions,
contextObjects!.declaredVariables,
sourceFactory,
- (_) => true, // _isLibraryUri
- libraryContext!.analysisContext,
- libraryContext!.elementFactory,
- contextObjects!.inheritanceManager,
- libraryFile,
- (file) => file.getContent(),
+ libraryContext!.elementFactory.libraryOfUri2(libraryKind.file.uri),
+ libraryContext!.elementFactory.analysisSession.inheritanceManager,
+ libraryKind,
);
results = performance!.run('analyze', (performance) {
- return libraryAnalyzer.analyze(
- completionPath: completionOffset != null ? completionPath : null,
- completionOffset: completionOffset,
- performance: performance,
- );
+ return libraryAnalyzer.analyze();
});
});
- var resolvedUnits = results.values.map((fileResult) {
+ var resolvedUnits = results.map((fileResult) {
var file = fileResult.file;
return ResolvedUnitResultImpl(
contextObjects!.analysisSession,
@@ -648,9 +673,7 @@
var result = ResolvedLibraryResultImpl(contextObjects!.analysisSession,
libraryUnit.libraryElement, resolvedUnits);
- if (completionPath == null) {
- cachedResults[path] = result;
- }
+ cachedResults[path] = result;
return result;
});
diff --git a/pkg/analyzer/lib/src/summary2/types_builder.dart b/pkg/analyzer/lib/src/summary2/types_builder.dart
index 1fd8625..64d6087 100644
--- a/pkg/analyzer/lib/src/summary2/types_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/types_builder.dart
@@ -383,14 +383,6 @@
interfacesMerger.addWithSupertypes(element.supertype);
}
- NullabilitySuffix get _noneOrStarSuffix {
- return _nonNullableEnabled
- ? NullabilitySuffix.none
- : NullabilitySuffix.star;
- }
-
- bool get _nonNullableEnabled => featureSet.isEnabled(Feature.non_nullable);
-
void perform(WithClause? withClause) {
if (withClause == null) return;
@@ -438,19 +430,46 @@
return mixinType;
}
- var mixinElement = mixinType.element;
- if (mixinElement.typeParameters.isEmpty) {
- return mixinType;
+ List<TypeParameterElement>? typeParameters;
+ List<InterfaceType>? supertypeConstraints;
+ InterfaceType Function(List<DartType> typeArguments)? instantiate;
+ final mixinElement = mixinNode.name.staticElement;
+ if (mixinElement is ClassElement) {
+ typeParameters = mixinElement.typeParameters;
+ if (typeParameters.isNotEmpty) {
+ supertypeConstraints = typeSystem
+ .gatherMixinSupertypeConstraintsForInference(mixinElement);
+ instantiate = (typeArguments) {
+ return mixinElement.instantiate(
+ typeArguments: typeArguments,
+ nullabilitySuffix: mixinType.nullabilitySuffix,
+ );
+ };
+ }
+ } else if (mixinElement is TypeAliasElementImpl) {
+ typeParameters = mixinElement.typeParameters;
+ if (typeParameters.isNotEmpty) {
+ final rawType = mixinElement.rawType;
+ if (rawType is InterfaceType) {
+ supertypeConstraints = rawType.superclassConstraints;
+ instantiate = (typeArguments) {
+ return mixinElement.instantiate(
+ typeArguments: typeArguments,
+ nullabilitySuffix: mixinType.nullabilitySuffix,
+ ) as InterfaceType;
+ };
+ }
+ }
}
- var mixinSupertypeConstraints =
- typeSystem.gatherMixinSupertypeConstraintsForInference(mixinElement);
- if (mixinSupertypeConstraints.isEmpty) {
+ if (typeParameters == null ||
+ supertypeConstraints == null ||
+ instantiate == null) {
return mixinType;
}
var matchingInterfaceTypes = _findInterfaceTypesForConstraints(
- mixinSupertypeConstraints,
+ supertypeConstraints,
interfacesMerger.typeList,
);
@@ -468,22 +487,18 @@
// mixinSupertypeConstraints to find the correct set of type
// parameters to apply to the mixin.
var inferredTypeArguments = typeSystem.matchSupertypeConstraints(
- mixinElement,
- mixinSupertypeConstraints,
+ typeParameters,
+ supertypeConstraints,
matchingInterfaceTypes,
- genericMetadataIsEnabled:
- mixinElement.library.featureSet.isEnabled(Feature.generic_metadata),
+ genericMetadataIsEnabled: featureSet.isEnabled(Feature.generic_metadata),
);
- if (inferredTypeArguments != null) {
- var inferredMixin = mixinElement.instantiate(
- typeArguments: inferredTypeArguments,
- nullabilitySuffix: _noneOrStarSuffix,
- );
- mixinType = inferredMixin;
- mixinNode.type = inferredMixin;
+ if (inferredTypeArguments == null) {
+ return mixinType;
}
- return mixinType;
+ final inferredType = instantiate(inferredTypeArguments);
+ mixinNode.type = inferredType;
+ return inferredType;
}
InterfaceType _interfaceType(DartType type) {
diff --git a/pkg/analyzer/test/src/dart/analysis/context_locator_test.dart b/pkg/analyzer/test/src/dart/analysis/context_locator_test.dart
index 9f757d0..70b8c34 100644
--- a/pkg/analyzer/test/src/dart/analysis/context_locator_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/context_locator_test.dart
@@ -290,6 +290,35 @@
expect(outerRoot.packagesFile, outerPackagesFile);
}
+ void
+ test_locateRoots_multiple_dirAndNestedDir_outerIsBazel_innerConfigurationFiles() {
+ var outerRootFolder = newFolder('/outer');
+ newFile('$outerRootFolder/WORKSPACE', '');
+ newBazelBuildFile('$outerRootFolder', '');
+ var innerRootFolder = newFolder('/outer/examples/inner');
+ var innerOptionsFile = newAnalysisOptionsYamlFile('$innerRootFolder', '');
+ var innerPackagesFile = newPackageConfigJsonFile('$innerRootFolder', '');
+ newPubspecYamlFile('$innerRootFolder', '');
+
+ var roots = contextLocator.locateRoots(
+ includedPaths: [outerRootFolder.path, innerRootFolder.path],
+ );
+ expect(roots, hasLength(2));
+
+ var outerRoot = findRoot(roots, outerRootFolder);
+ expect(outerRoot.includedPaths, unorderedEquals([outerRootFolder.path]));
+ expect(outerRoot.excludedPaths, unorderedEquals([innerRootFolder.path]));
+ expect(outerRoot.optionsFile, isNull);
+ expect(outerRoot.packagesFile, isNull);
+
+ var innerRoot = findRoot(roots, innerRootFolder);
+ expect(innerRoot.workspace.root, equals(innerRootFolder.path));
+ expect(innerRoot.includedPaths, unorderedEquals([innerRootFolder.path]));
+ expect(innerRoot.excludedPaths, isEmpty);
+ expect(innerRoot.optionsFile, innerOptionsFile);
+ expect(innerRoot.packagesFile, innerPackagesFile);
+ }
+
void test_locateRoots_multiple_dirAndNestedFile_excludedByOptions() {
var rootPath = convertPath('/home/test');
var rootFolder = newFolder(rootPath);
diff --git a/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart b/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
index b284a45..8b247dd 100644
--- a/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
+++ b/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
@@ -3322,32 +3322,6 @@
expect(result, isNot(same(result1)));
}
- test_resolveFile_dontCache_whenForCompletion() async {
- final a = newFile('/workspace/dart/test/lib/a.dart', r'''
-part 'b.dart';
-''');
-
- final b = newFile('/workspace/dart/test/lib/b.dart', r'''
-part of 'a.dart';
-''');
-
- // No resolved files yet.
- _assertResolvedFiles([]);
-
- await fileResolver.resolve2(
- path: b.path,
- completionLine: 0,
- completionColumn: 0,
- );
-
- // The library was resolved.
- _assertResolvedFiles([a]);
-
- // The completion location was set, so not units are resolved.
- // So, the result should not be cached.
- expect(fileResolver.cachedResults, isEmpty);
- }
-
test_resolveLibrary() async {
var aPath = convertPath('/workspace/dart/test/lib/a.dart');
newFile(aPath, r'''
diff --git a/pkg/analyzer/test/src/summary/elements_test.dart b/pkg/analyzer/test/src/summary/elements_test.dart
index 7101cab..dc9ab8f 100644
--- a/pkg/analyzer/test/src/summary/elements_test.dart
+++ b/pkg/analyzer/test/src/summary/elements_test.dart
@@ -31080,6 +31080,116 @@
''');
}
+ test_mixin_inference_viaTypeAlias() async {
+ var library = await buildLibrary(r'''
+mixin M<T, U> on S<T> {}
+
+typedef M2<T2> = M<T2, int>;
+
+class S<T3> {}
+
+class X extends S<String> with M2 {}
+''');
+ checkElementText(library, r'''
+library
+ definingUnit
+ classes
+ class S @62
+ typeParameters
+ covariant T3 @64
+ defaultType: dynamic
+ constructors
+ synthetic @-1
+ class X @78
+ supertype: S<String>
+ mixins
+ M<String, int>
+ alias: self::@typeAlias::M2
+ typeArguments
+ String
+ constructors
+ synthetic @-1
+ superConstructor: ConstructorMember
+ base: self::@class::S::@constructor::•
+ substitution: {T3: String}
+ mixins
+ mixin M @6
+ typeParameters
+ covariant T @8
+ defaultType: dynamic
+ covariant U @11
+ defaultType: dynamic
+ superclassConstraints
+ S<T>
+ typeAliases
+ M2 @34
+ typeParameters
+ covariant T2 @37
+ defaultType: dynamic
+ aliasedType: M<T2, int>
+''');
+ }
+
+ test_mixin_inference_viaTypeAlias2() async {
+ var library = await buildLibrary(r'''
+mixin M<T, U> on S<T> {}
+
+typedef M2<T2> = M<T2, int>;
+
+typedef M3<T3> = M2<T3>;
+
+class S<T4> {}
+
+class X extends S<String> with M3 {}
+''');
+ checkElementText(library, r'''
+library
+ definingUnit
+ classes
+ class S @88
+ typeParameters
+ covariant T4 @90
+ defaultType: dynamic
+ constructors
+ synthetic @-1
+ class X @104
+ supertype: S<String>
+ mixins
+ M<String, int>
+ alias: self::@typeAlias::M3
+ typeArguments
+ String
+ constructors
+ synthetic @-1
+ superConstructor: ConstructorMember
+ base: self::@class::S::@constructor::•
+ substitution: {T4: String}
+ mixins
+ mixin M @6
+ typeParameters
+ covariant T @8
+ defaultType: dynamic
+ covariant U @11
+ defaultType: dynamic
+ superclassConstraints
+ S<T>
+ typeAliases
+ M2 @34
+ typeParameters
+ covariant T2 @37
+ defaultType: dynamic
+ aliasedType: M<T2, int>
+ M3 @64
+ typeParameters
+ covariant T3 @67
+ defaultType: dynamic
+ aliasedType: M<T3, int>
+ alias: self::@typeAlias::M2
+ typeArguments
+ T3
+''');
+ }
+
test_mixin_method_invokesSuperSelf() async {
var library = await buildLibrary(r'''
mixin M on A {
diff --git a/pkg/test_runner/lib/bot_results.dart b/pkg/test_runner/lib/bot_results.dart
index 1bad14e..6b0a850 100644
--- a/pkg/test_runner/lib/bot_results.dart
+++ b/pkg/test_runner/lib/bot_results.dart
@@ -24,35 +24,37 @@
final bool matches;
final String name;
final String outcome;
- final bool changed;
- final String commitHash;
+ final bool? changed;
+ final String? commitHash;
final bool flaked; // From optional flakiness_data argument to constructor.
- final bool isFlaky; // From results.json after it is extended.
- final String previousOutcome;
+ final bool? isFlaky; // From results.json after it is extended.
+ final String? previousOutcome;
Result(
- this.configuration,
- this.name,
- this.outcome,
- this.expectation,
- this.matches,
- this.changed,
- this.commitHash,
- this.isFlaky,
- this.previousOutcome,
- [this.flaked = false]);
+ this.configuration,
+ this.name,
+ this.outcome,
+ this.expectation,
+ this.matches,
+ this.changed,
+ this.commitHash,
+ this.isFlaky,
+ this.previousOutcome, {
+ this.flaked = false,
+ });
- Result.fromMap(Map<String, dynamic> map,
- [Map<String, dynamic>? flakinessData])
- : configuration = map["configuration"] as String,
+ Result.fromMap(
+ Map<String, dynamic> map, [
+ Map<String, dynamic>? flakinessData,
+ ]) : configuration = map["configuration"] as String,
name = map["name"] as String,
outcome = map["result"] as String,
expectation = map["expected"] as String,
matches = map["matches"] as bool,
- changed = map["changed"] as bool,
- commitHash = map["commit_hash"] as String,
- isFlaky = map["flaky"] as bool,
- previousOutcome = map["previous_result"] as String,
+ changed = map["changed"] as bool?,
+ commitHash = map["commit_hash"] as String?,
+ isFlaky = map["flaky"] as bool?,
+ previousOutcome = map["previous_result"] as String?,
flaked = flakinessData != null &&
(flakinessData["active"] ?? true) == true &&
(flakinessData["outcomes"] as List).contains(map["result"]);
diff --git a/pkg/test_runner/test/compare_results/compare_results_test.dart b/pkg/test_runner/test/compare_results/compare_results_test.dart
index 2a8b174..c655ddf 100644
--- a/pkg/test_runner/test/compare_results/compare_results_test.dart
+++ b/pkg/test_runner/test/compare_results/compare_results_test.dart
@@ -198,6 +198,16 @@
bool flaked = false,
bool isFlaky = false,
String previousOutcome = 'Pass'}) {
- return Result(configuration, name, outcome, expectation, matches, changed,
- commitHash, isFlaky, previousOutcome, flaked);
+ return Result(
+ configuration,
+ name,
+ outcome,
+ expectation,
+ matches,
+ changed,
+ commitHash,
+ isFlaky,
+ previousOutcome,
+ flaked: flaked,
+ );
}
diff --git a/tools/VERSION b/tools/VERSION
index 67be777..234f0fe 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 18
PATCH 0
-PRERELEASE 226
+PRERELEASE 227
PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/bots/compare_results.dart b/tools/bots/compare_results.dart
index 1e2bad3..5ca9f1f 100755
--- a/tools/bots/compare_results.dart
+++ b/tools/bots/compare_results.dart
@@ -7,8 +7,6 @@
// The output contains additional details in the verbose mode. There is a human
// readable mode that explains the results and how they changed.
-// @dart = 2.9
-
import '../../pkg/test_runner/bin/compare_results.dart' as compare_results;
main(List<String> args) {
diff --git a/tools/bots/extend_results.dart b/tools/bots/extend_results.dart
index 6b03623..98fcec8 100644
--- a/tools/bots/extend_results.dart
+++ b/tools/bots/extend_results.dart
@@ -5,8 +5,6 @@
// Add fields with data about the test run and the commit tested, and
// with the result on the last build tested, to the test results file.
-// @dart = 2.9
-
import 'dart:convert';
import 'dart:io';
@@ -38,10 +36,10 @@
}
});
for (final String key in results.keys) {
- final Map<String, dynamic> result = results[key];
- final Map<String, dynamic> priorResult = priorResults[key];
- final Map<String, dynamic> flaky = flakes[key];
- final Map<String, dynamic> priorFlaky = priorFlakes[key];
+ final Map<String, dynamic> result = results[key]!;
+ final Map<String, dynamic>? priorResult = priorResults[key];
+ final Map<String, dynamic>? flaky = flakes[key];
+ final Map<String, dynamic>? priorFlaky = priorFlakes[key];
result['commit_hash'] = commitHash;
result['commit_time'] = commitTime;
result['build_number'] = buildNumber;
diff --git a/tools/bots/update_blamelists.dart b/tools/bots/update_blamelists.dart
index 0776afc..7956090 100644
--- a/tools/bots/update_blamelists.dart
+++ b/tools/bots/update_blamelists.dart
@@ -6,8 +6,6 @@
// of active, non-approved failures which include the commit of the current
// bisection build.
-// @dart = 2.9
-
import 'dart:io';
import 'package:args/args.dart';
@@ -20,7 +18,7 @@
const maxAttempts = 20;
-FirestoreDatabase database;
+late FirestoreDatabase database;
class ResultRecord {
final Map data;
@@ -77,7 +75,7 @@
/// Compute if the record should be updated based on the outcomes in the
/// result record and the new test result.
-bool shouldUpdateRecord(ResultRecord resultRecord, Result testResult) {
+bool shouldUpdateRecord(ResultRecord resultRecord, Result? testResult) {
if (testResult == null || !testResult.matches) {
return false;
}
@@ -97,8 +95,8 @@
return true;
}
-void updateBlameLists(
- String configuration, String commit, Map<String, Map> testResults) async {
+void updateBlameLists(String configuration, String commit,
+ Map<String, Map<String, dynamic>> testResults) async {
int commitIndex = await getCommitIndex(commit);
var query = unapprovedActiveFailuresQuery(configuration);
bool needsRetry;
@@ -127,7 +125,7 @@
print('Found result record: $configuration:${result.name}: '
'${result.previousResult} -> ${result.result} '
'in ${result.blamelistStartIndex}..${result.blamelistEndIndex} '
- 'to update with ${testResult.outcome} at $commitIndex.');
+ 'to update with ${testResult?.outcome} at $commitIndex.');
// We found a result representation for this test and configuration whose
// blamelist includes this results' commit but whose outcome is different
// then the outcome in the provided test results.
@@ -176,7 +174,7 @@
}
// Pick an arbitrary result entry to find configuration and commit hash.
var firstResult = Result.fromMap(results.values.first);
- var commit = firstResult.commitHash;
+ var commit = firstResult.commitHash!;
var configuration = firstResult.configuration;
var project = options['staging'] ? 'dart-ci-staging' : 'dart-ci';
database = FirestoreDatabase(
diff --git a/tools/bots/update_flakiness.dart b/tools/bots/update_flakiness.dart
index 92667a5..a112fed 100755
--- a/tools/bots/update_flakiness.dart
+++ b/tools/bots/update_flakiness.dart
@@ -5,8 +5,6 @@
// Update the flakiness data with a set of fresh results.
-// @dart = 2.9
-
import 'dart:convert';
import 'dart:io';
@@ -43,7 +41,7 @@
final resultsForInactiveFlakiness = {
for (final flakyTest in data.keys)
- if (data[flakyTest]['active'] == false) flakyTest: <String>{}
+ if (data[flakyTest]!['active'] == false) flakyTest: <String>{}
};
// Incrementally update the flakiness data with each observed result.
for (final path in parameters) {
@@ -99,11 +97,11 @@
options['output'] != null ? File(options['output']).openWrite() : stdout;
final keys = data.keys.toList()..sort();
for (final key in keys) {
- final testData = data[key];
+ final testData = data[key]!;
if (testData['outcomes'].length < 2) continue;
// Reactivate inactive flaky results that are flaky again.
if (testData['active'] == false) {
- if (resultsForInactiveFlakiness[key].length > 1) {
+ if (resultsForInactiveFlakiness[key]!.length > 1) {
testData['active'] = true;
testData['reactivation_count'] =
(testData['reactivation_count'] ?? 0) + 1;
diff --git a/tools/generate_experimental_flags.dart b/tools/generate_experimental_flags.dart
index 3ae2858..f096ae9 100644
--- a/tools/generate_experimental_flags.dart
+++ b/tools/generate_experimental_flags.dart
@@ -2,14 +2,13 @@
// 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.
-// @dart = 2.9
-
import 'dart:io' show File, Platform;
+
import 'package:yaml/yaml.dart' show YamlMap, loadYaml;
void main() {
YamlMap yaml = loadYaml(File.fromUri(computeYamlFile()).readAsStringSync());
- final currentVersion = getAsVersionNumber(yaml['current-version']);
+ final currentVersion = getAsVersionNumber(yaml['current-version'])!;
final enumNames = StringBuffer();
final featureValues = StringBuffer();
final featureNames = StringBuffer();
@@ -108,7 +107,7 @@
return Platform.script.resolve("../runtime/vm/experimental_features.h");
}
-List<num> getAsVersionNumber(dynamic value) {
+List<num>? getAsVersionNumber(dynamic value) {
if (value == null) return null;
final version = List.of("$value".split(".").map(int.parse));
while (version.length < 3) {
diff --git a/tools/test.dart b/tools/test.dart
index fece115..e85bebd 100755
--- a/tools/test.dart
+++ b/tools/test.dart
@@ -3,8 +3,6 @@
// 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.
-// @dart = 2.9
-
import 'package:test_runner/test_runner.dart';
void main(List<String> args) {