diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart index d675223ad99f..b1bbed7805ed 100644 --- a/pkg/analyzer/lib/error/error.dart +++ b/pkg/analyzer/lib/error/error.dart @@ -180,6 +180,7 @@ const List errorCodeValues = [ CompileTimeErrorCode.INCONSISTENT_CASE_EXPRESSION_TYPES, CompileTimeErrorCode.INCONSISTENT_INHERITANCE, CompileTimeErrorCode.INCONSISTENT_INHERITANCE_GETTER_AND_METHOD, + CompileTimeErrorCode.INCONSISTENT_LANGUAGE_VERSION_OVERRIDE, CompileTimeErrorCode.INITIALIZER_FOR_NON_EXISTENT_FIELD, CompileTimeErrorCode.INITIALIZER_FOR_STATIC_FIELD, CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_NON_EXISTENT_FIELD, diff --git a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart index c6480843fd8d..11a988e1d675 100644 --- a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart +++ b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart @@ -185,6 +185,8 @@ class LibraryAnalyzer { assert(units.values.every(LegacyTypeAsserter.assertLegacyTypes)); + _checkForInconsistentLanguageVersionOverride(units); + timerLibraryAnalyzerVerify.stop(); // Return full results. @@ -198,6 +200,44 @@ class LibraryAnalyzer { return results; } + void _checkForInconsistentLanguageVersionOverride( + Map units, + ) { + var libraryUnit = units.values.first; + var libraryOverrideToken = libraryUnit.languageVersionToken; + + for (var partEntry in units.entries.skip(1)) { + var partUnit = partEntry.value; + var partOverrideToken = partUnit.languageVersionToken; + if (libraryOverrideToken != null) { + if (partOverrideToken != null) { + if (partOverrideToken.major != libraryOverrideToken.major || + partOverrideToken.minor != libraryOverrideToken.minor) { + _getErrorReporter(partEntry.key).reportErrorForToken( + CompileTimeErrorCode.INCONSISTENT_LANGUAGE_VERSION_OVERRIDE, + partOverrideToken, + ); + } + } else { + var partDirectives = partUnit.directives; + for (var partOf in partDirectives.whereType()) { + var partOffset = partOf.partKeyword.offset; + _getErrorReporter(partEntry.key).reportErrorForOffset( + CompileTimeErrorCode.INCONSISTENT_LANGUAGE_VERSION_OVERRIDE, + partOffset, + partOf.ofKeyword.end - partOffset, + ); + } + } + } else if (partOverrideToken != null) { + _getErrorReporter(partEntry.key).reportErrorForToken( + CompileTimeErrorCode.INCONSISTENT_LANGUAGE_VERSION_OVERRIDE, + partOverrideToken, + ); + } + } + } + void _computeConstantErrors( ErrorReporter errorReporter, CompilationUnit unit) { ConstantVerifier constantVerifier = ConstantVerifier( diff --git a/pkg/analyzer/lib/src/error/codes.dart b/pkg/analyzer/lib/src/error/codes.dart index 6071d5669350..d8328640edd1 100644 --- a/pkg/analyzer/lib/src/error/codes.dart +++ b/pkg/analyzer/lib/src/error/codes.dart @@ -3032,6 +3032,20 @@ class CompileTimeErrorCode extends AnalyzerErrorCode { "Try adjusting the supertypes of this class to remove the " "inconsistency."); + /** + * It is a compile-time error if a part file has a different language version + * override than its library. + * + * https://github.com/dart-lang/language/blob/master/accepted/ + * future-releases/language-versioning/feature-specification.md + * #individual-library-language-version-override + */ + static const CompileTimeErrorCode INCONSISTENT_LANGUAGE_VERSION_OVERRIDE = + CompileTimeErrorCode( + 'INCONSISTENT_LANGUAGE_VERSION_OVERRIDE', + "Parts must have exactly the same language version override as " + "the library."); + /** * Parameters: * 0: the name of the initializing formal that is not an instance variable in diff --git a/pkg/analyzer/test/src/dart/resolution/resolution.dart b/pkg/analyzer/test/src/dart/resolution/resolution.dart index 63c6e6d458d5..21f9f82d158f 100644 --- a/pkg/analyzer/test/src/dart/resolution/resolution.dart +++ b/pkg/analyzer/test/src/dart/resolution/resolution.dart @@ -257,6 +257,16 @@ mixin ResolutionTest implements ResourceProviderMixin { return result; } + Future assertErrorsInFile2( + String path, + List expectedErrors, + ) async { + path = convertPath(path); + + var result = await resolveFile(path); + assertErrorsInResolvedUnit(result, expectedErrors); + } + void assertErrorsInList( List errors, List expectedErrors, diff --git a/pkg/analyzer/test/src/diagnostics/inconsistent_language_version_override_test.dart b/pkg/analyzer/test/src/diagnostics/inconsistent_language_version_override_test.dart new file mode 100644 index 000000000000..9e8bee811303 --- /dev/null +++ b/pkg/analyzer/test/src/diagnostics/inconsistent_language_version_override_test.dart @@ -0,0 +1,111 @@ +// 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:meta/meta.dart'; +import 'package:test_reflective_loader/test_reflective_loader.dart'; + +import '../../generated/test_support.dart'; +import '../dart/resolution/driver_resolution.dart'; + +main() { + defineReflectiveSuite(() { + defineReflectiveTests(InconsistentLanguageVersionOverrideTest); + }); +} + +@reflectiveTest +class InconsistentLanguageVersionOverrideTest extends DriverResolutionTest { + CompileTimeErrorCode get _errorCode => + CompileTimeErrorCode.INCONSISTENT_LANGUAGE_VERSION_OVERRIDE; + + test_both_different() async { + await _checkLibraryAndPart( + libraryContent: r''' +// @dart = 2.5 +part 'b.dart'; +''', + partContent: r''' +// @dart = 2.6 +part of 'a.dart'; +''', + partErrors: [ + error(_errorCode, 0, 14), + ], + ); + } + + test_both_same() async { + await _checkLibraryAndPart( + libraryContent: r''' +// @dart = 2.5 +part 'b.dart'; +''', + partContent: r''' +// @dart = 2.5 +part of 'a.dart'; +''', + partErrors: [], + ); + } + + test_none() async { + await _checkLibraryAndPart( + libraryContent: r''' +part 'b.dart'; +''', + partContent: r''' +part of 'a.dart'; +''', + partErrors: [], + ); + } + + test_onlyLibrary() async { + await _checkLibraryAndPart( + libraryContent: r''' +// @dart = 2.5 +part 'b.dart'; +''', + partContent: r''' +part of 'a.dart'; +''', + partErrors: [ + error(_errorCode, 0, 7), + ], + ); + } + + test_onlyPart() async { + await _checkLibraryAndPart( + libraryContent: r''' +part 'b.dart'; +''', + partContent: r''' +// @dart = 2.5 +part of 'a.dart'; +''', + partErrors: [ + error(_errorCode, 0, 14), + ], + ); + } + + Future _checkLibraryAndPart({ + @required String libraryContent, + @required String partContent, + @required List partErrors, + }) async { + var libraryPath = convertPath('/test/lib/a.dart'); + var partPath = convertPath('/test/lib/b.dart'); + + newFile(libraryPath, content: libraryContent); + + newFile(partPath, content: partContent); + + await resolveFile(libraryPath); + + await assertErrorsInFile2(partPath, partErrors); + } +} diff --git a/pkg/analyzer/test/src/diagnostics/test_all.dart b/pkg/analyzer/test/src/diagnostics/test_all.dart index 496937e34e3d..18550034651e 100644 --- a/pkg/analyzer/test/src/diagnostics/test_all.dart +++ b/pkg/analyzer/test/src/diagnostics/test_all.dart @@ -191,6 +191,8 @@ import 'inconsistent_case_expression_types_test.dart' import 'inconsistent_inheritance_getter_and_method_test.dart' as inconsistent_inheritance_getter_and_method; import 'inconsistent_inheritance_test.dart' as inconsistent_inheritance; +import 'inconsistent_language_version_override_test.dart' + as inconsistent_language_version_override; import 'inference_failure_on_collection_literal_test.dart' as inference_failure_on_collection_literal; import 'inference_failure_on_function_return_type_test.dart' @@ -663,6 +665,7 @@ main() { inconsistent_case_expression_types.main(); inconsistent_inheritance_getter_and_method.main(); inconsistent_inheritance.main(); + inconsistent_language_version_override.main(); inference_failure_on_collection_literal.main(); inference_failure_on_function_return_type.main(); inference_failure_on_uninitialized_variable.main();