Version 2.16.0-94.0.dev
Merge commit '5064c19938c5307128aefb17c83955dff56ebc40' into 'dev'
diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json
index d50d6f5..0d8297b 100644
--- a/.dart_tool/package_config.json
+++ b/.dart_tool/package_config.json
@@ -11,7 +11,7 @@
"constraint, update this by running tools/generate_package_config.dart."
],
"configVersion": 2,
- "generated": "2021-11-15T17:34:02.415038",
+ "generated": "2021-12-09T13:52:42.287379",
"generator": "tools/generate_package_config.dart",
"packages": [
{
@@ -760,7 +760,7 @@
"name": "vm",
"rootUri": "../pkg/vm",
"packageUri": "lib/",
- "languageVersion": "2.12"
+ "languageVersion": "2.15"
},
{
"name": "vm_service",
diff --git a/pkg/analysis_server/doc/api.html b/pkg/analysis_server/doc/api.html
index b84e3fd..1bb0ba8 100644
--- a/pkg/analysis_server/doc/api.html
+++ b/pkg/analysis_server/doc/api.html
@@ -109,7 +109,7 @@
<body>
<h1>Analysis Server API Specification</h1>
<h1 style="color:#999999">Version
- 1.32.7
+ 1.32.8
</h1>
<p>
This document contains a specification of the API provided by the
@@ -236,6 +236,11 @@
ignoring the item or treating it with some default/fallback handling.
</p>
<h3>Changelog</h3>
+<h4>1.32.8</h4>
+<ul>
+ <li>Added <tt>server.cancelRequest</tt> to allow clients to request cancellation
+ of outstanding requests.</li>
+</ul>
<h4>1.32.7</h4>
<ul>
<li><tt>HoverInformation.elementDescription</tt> may now include linebreaks to
@@ -286,6 +291,7 @@
<p><a href="#domain_server">Server</a></p><ul><li><a href="#request_server.getVersion">server.getVersion</a></li>
<li><a href="#request_server.shutdown">server.shutdown</a></li>
<li><a href="#request_server.setSubscriptions">server.setSubscriptions</a></li>
+<li><a href="#request_server.cancelRequest">server.cancelRequest</a></li>
</ul>
<p><a href="#domain_analysis">Analysis</a></p><ul><li><a href="#request_analysis.getErrors">analysis.getErrors</a></li>
@@ -421,6 +427,7 @@
+
<h3>Requests</h3><dl><dt class="request"><a name="request_server.getVersion">server.getVersion</a></dt><dd><div class="box"><pre>request: {
"id": String
"method": "server.getVersion"
@@ -474,6 +481,32 @@
<h4>parameters:</h4><dl><dt class="field"><b>subscriptions: List<<a href="#type_ServerService">ServerService</a>></b></dt><dd>
<p>A list of the services being subscribed to.</p>
+ </dd></dl></dd><dt class="request"><a name="request_server.cancelRequest">server.cancelRequest</a></dt><dd><div class="box"><pre>request: {
+ "<b>id</b>": String
+ "method": "server.cancelRequest"
+ "params": {
+ "<b>id</b>": String
+ }
+}</pre><br><pre>response: {
+ "id": String
+ "error": <span style="color:#999999">optional</span> <a href="#type_RequestError">RequestError</a>
+}</pre></div>
+ <p>Requests cancellation of a request sent by the client by id.
+ This is provided on a best-effort basis and there is no
+ guarantee the server will be able to cancel any specific
+ request.
+
+ The server will still always produce a response to the request
+ even in the case of cancellation, but clients should discard
+ any results of any cancelled request because they may be
+ incomplete or inaccurate.
+
+ This request always completes without error regardless of
+ whether the request is successfully cancelled.</p>
+
+ <h4>parameters:</h4><dl><dt class="field"><b>id: String</b></dt><dd>
+
+ <p>The id of the request that should be cancelled.</p>
</dd></dl></dd></dl><h3>Notifications</h3><dl><dt class="notification"><a name="notification_server.connected">server.connected</a></dt><dd><div class="box"><pre>notification: {
"event": "server.connected"
"params": {
@@ -6065,7 +6098,7 @@
TODO: TBD
</p>
<h2 class="domain"><a name="index">Index</a></h2>
-<h3>Domains</h3><h4>server (<a href="#domain_server">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_server.getVersion">getVersion</a></li><li><a href="#request_server.shutdown">shutdown</a></li><li><a href="#request_server.setSubscriptions">setSubscriptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_server.connected">connected</a></li><li><a href="#notification_server.error">error</a></li><li><a href="#notification_server.log">log</a></li><li><a href="#notification_server.status">status</a></li></ul></div></div><h4>analysis (<a href="#domain_analysis">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_analysis.getErrors">getErrors</a></li><li><a href="#request_analysis.getHover">getHover</a></li><li><a href="#request_analysis.getLibraryDependencies">getLibraryDependencies</a></li><li><a href="#request_analysis.getNavigation">getNavigation</a></li><li><a href="#request_analysis.getReachableSources">getReachableSources</a></li><li><a href="#request_analysis.reanalyze">reanalyze</a></li><li><a href="#request_analysis.setAnalysisRoots">setAnalysisRoots</a></li><li><a href="#request_analysis.setGeneralSubscriptions">setGeneralSubscriptions</a></li><li><a href="#request_analysis.setPriorityFiles">setPriorityFiles</a></li><li><a href="#request_analysis.setSubscriptions">setSubscriptions</a></li><li><a href="#request_analysis.updateContent">updateContent</a></li><li><a href="#request_analysis.updateOptions">updateOptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_analysis.analyzedFiles">analyzedFiles</a></li><li><a href="#notification_analysis.closingLabels">closingLabels</a></li><li><a href="#notification_analysis.errors">errors</a></li><li><a href="#notification_analysis.flushResults">flushResults</a></li><li><a href="#notification_analysis.folding">folding</a></li><li><a href="#notification_analysis.highlights">highlights</a></li><li><a href="#notification_analysis.implemented">implemented</a></li><li><a href="#notification_analysis.invalidate">invalidate</a></li><li><a href="#notification_analysis.navigation">navigation</a></li><li><a href="#notification_analysis.occurrences">occurrences</a></li><li><a href="#notification_analysis.outline">outline</a></li><li><a href="#notification_analysis.overrides">overrides</a></li></ul></div></div><h4>completion (<a href="#domain_completion">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_completion.getSuggestions">getSuggestions</a></li><li><a href="#request_completion.setSubscriptions">setSubscriptions</a></li><li><a href="#request_completion.registerLibraryPaths">registerLibraryPaths</a></li><li><a href="#request_completion.getSuggestionDetails">getSuggestionDetails</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_completion.results">results</a></li><li><a href="#notification_completion.availableSuggestions">availableSuggestions</a></li><li><a href="#notification_completion.existingImports">existingImports</a></li></ul></div></div><h4>search (<a href="#domain_search">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_search.findElementReferences">findElementReferences</a></li><li><a href="#request_search.findMemberDeclarations">findMemberDeclarations</a></li><li><a href="#request_search.findMemberReferences">findMemberReferences</a></li><li><a href="#request_search.findTopLevelDeclarations">findTopLevelDeclarations</a></li><li><a href="#request_search.getTypeHierarchy">getTypeHierarchy</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_search.results">results</a></li></ul></div></div><h4>edit (<a href="#domain_edit">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_edit.format">format</a></li><li><a href="#request_edit.getAssists">getAssists</a></li><li><a href="#request_edit.getAvailableRefactorings">getAvailableRefactorings</a></li><li><a href="#request_edit.getFixes">getFixes</a></li><li><a href="#request_edit.getPostfixCompletion">getPostfixCompletion</a></li><li><a href="#request_edit.getRefactoring">getRefactoring</a></li><li><a href="#request_edit.sortMembers">sortMembers</a></li><li><a href="#request_edit.organizeDirectives">organizeDirectives</a></li></ul></div><h4>execution (<a href="#domain_execution">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_execution.createContext">createContext</a></li><li><a href="#request_execution.deleteContext">deleteContext</a></li><li><a href="#request_execution.getSuggestions">getSuggestions</a></li><li><a href="#request_execution.mapUri">mapUri</a></li><li><a href="#request_execution.setSubscriptions">setSubscriptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_execution.launchData">launchData</a></li></ul></div></div><h4>diagnostic (<a href="#domain_diagnostic">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_diagnostic.getDiagnostics">getDiagnostics</a></li><li><a href="#request_diagnostic.getServerPort">getServerPort</a></li></ul></div><h4>flutter (<a href="#domain_flutter">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_flutter.setSubscriptions">setSubscriptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_flutter.outline">outline</a></li></ul></div></div><h3>Types (<a href="#types">↑</a>)</h3><div class="subindex"><ul><li><a href="#type_AddContentOverlay">AddContentOverlay</a></li><li><a href="#type_AnalysisError">AnalysisError</a></li><li><a href="#type_AnalysisErrorFixes">AnalysisErrorFixes</a></li><li><a href="#type_AnalysisErrorSeverity">AnalysisErrorSeverity</a></li><li><a href="#type_AnalysisErrorType">AnalysisErrorType</a></li><li><a href="#type_AnalysisOptions">AnalysisOptions</a></li><li><a href="#type_AnalysisService">AnalysisService</a></li><li><a href="#type_AnalysisStatus">AnalysisStatus</a></li><li><a href="#type_AvailableSuggestion">AvailableSuggestion</a></li><li><a href="#type_AvailableSuggestionRelevanceTag">AvailableSuggestionRelevanceTag</a></li><li><a href="#type_AvailableSuggestionSet">AvailableSuggestionSet</a></li><li><a href="#type_BulkFix">BulkFix</a></li><li><a href="#type_BulkFixDetail">BulkFixDetail</a></li><li><a href="#type_ChangeContentOverlay">ChangeContentOverlay</a></li><li><a href="#type_ClosingLabel">ClosingLabel</a></li><li><a href="#type_CompletionId">CompletionId</a></li><li><a href="#type_CompletionService">CompletionService</a></li><li><a href="#type_CompletionSuggestion">CompletionSuggestion</a></li><li><a href="#type_CompletionSuggestionKind">CompletionSuggestionKind</a></li><li><a href="#type_ContextData">ContextData</a></li><li><a href="#type_DiagnosticMessage">DiagnosticMessage</a></li><li><a href="#type_Element">Element</a></li><li><a href="#type_ElementDeclaration">ElementDeclaration</a></li><li><a href="#type_ElementKind">ElementKind</a></li><li><a href="#type_ExecutableFile">ExecutableFile</a></li><li><a href="#type_ExecutableKind">ExecutableKind</a></li><li><a href="#type_ExecutionContextId">ExecutionContextId</a></li><li><a href="#type_ExecutionService">ExecutionService</a></li><li><a href="#type_ExistingImport">ExistingImport</a></li><li><a href="#type_ExistingImports">ExistingImports</a></li><li><a href="#type_FileKind">FileKind</a></li><li><a href="#type_FilePath">FilePath</a></li><li><a href="#type_FlutterOutline">FlutterOutline</a></li><li><a href="#type_FlutterOutlineAttribute">FlutterOutlineAttribute</a></li><li><a href="#type_FlutterOutlineKind">FlutterOutlineKind</a></li><li><a href="#type_FlutterService">FlutterService</a></li><li><a href="#type_FlutterWidgetProperty">FlutterWidgetProperty</a></li><li><a href="#type_FlutterWidgetPropertyEditor">FlutterWidgetPropertyEditor</a></li><li><a href="#type_FlutterWidgetPropertyEditorKind">FlutterWidgetPropertyEditorKind</a></li><li><a href="#type_FlutterWidgetPropertyValue">FlutterWidgetPropertyValue</a></li><li><a href="#type_FlutterWidgetPropertyValueEnumItem">FlutterWidgetPropertyValueEnumItem</a></li><li><a href="#type_FoldingKind">FoldingKind</a></li><li><a href="#type_FoldingRegion">FoldingRegion</a></li><li><a href="#type_GeneralAnalysisService">GeneralAnalysisService</a></li><li><a href="#type_HighlightRegion">HighlightRegion</a></li><li><a href="#type_HighlightRegionType">HighlightRegionType</a></li><li><a href="#type_HoverInformation">HoverInformation</a></li><li><a href="#type_ImplementedClass">ImplementedClass</a></li><li><a href="#type_ImplementedMember">ImplementedMember</a></li><li><a href="#type_ImportedElementSet">ImportedElementSet</a></li><li><a href="#type_ImportedElements">ImportedElements</a></li><li><a href="#type_IncludedSuggestionRelevanceTag">IncludedSuggestionRelevanceTag</a></li><li><a href="#type_IncludedSuggestionSet">IncludedSuggestionSet</a></li><li><a href="#type_KytheEntry">KytheEntry</a></li><li><a href="#type_KytheVName">KytheVName</a></li><li><a href="#type_LibraryPathSet">LibraryPathSet</a></li><li><a href="#type_LinkedEditGroup">LinkedEditGroup</a></li><li><a href="#type_LinkedEditSuggestion">LinkedEditSuggestion</a></li><li><a href="#type_LinkedEditSuggestionKind">LinkedEditSuggestionKind</a></li><li><a href="#type_Location">Location</a></li><li><a href="#type_NavigationRegion">NavigationRegion</a></li><li><a href="#type_NavigationTarget">NavigationTarget</a></li><li><a href="#type_Occurrences">Occurrences</a></li><li><a href="#type_Outline">Outline</a></li><li><a href="#type_OverriddenMember">OverriddenMember</a></li><li><a href="#type_Override">Override</a></li><li><a href="#type_Position">Position</a></li><li><a href="#type_PostfixTemplateDescriptor">PostfixTemplateDescriptor</a></li><li><a href="#type_PubStatus">PubStatus</a></li><li><a href="#type_RefactoringFeedback">RefactoringFeedback</a></li><li><a href="#type_RefactoringKind">RefactoringKind</a></li><li><a href="#type_RefactoringMethodParameter">RefactoringMethodParameter</a></li><li><a href="#type_RefactoringMethodParameterKind">RefactoringMethodParameterKind</a></li><li><a href="#type_RefactoringOptions">RefactoringOptions</a></li><li><a href="#type_RefactoringProblem">RefactoringProblem</a></li><li><a href="#type_RefactoringProblemSeverity">RefactoringProblemSeverity</a></li><li><a href="#type_RemoveContentOverlay">RemoveContentOverlay</a></li><li><a href="#type_RequestError">RequestError</a></li><li><a href="#type_RequestErrorCode">RequestErrorCode</a></li><li><a href="#type_RuntimeCompletionExpression">RuntimeCompletionExpression</a></li><li><a href="#type_RuntimeCompletionExpressionType">RuntimeCompletionExpressionType</a></li><li><a href="#type_RuntimeCompletionExpressionTypeKind">RuntimeCompletionExpressionTypeKind</a></li><li><a href="#type_RuntimeCompletionVariable">RuntimeCompletionVariable</a></li><li><a href="#type_SearchId">SearchId</a></li><li><a href="#type_SearchResult">SearchResult</a></li><li><a href="#type_SearchResultKind">SearchResultKind</a></li><li><a href="#type_ServerService">ServerService</a></li><li><a href="#type_SourceChange">SourceChange</a></li><li><a href="#type_SourceEdit">SourceEdit</a></li><li><a href="#type_SourceFileEdit">SourceFileEdit</a></li><li><a href="#type_TypeHierarchyItem">TypeHierarchyItem</a></li></ul></div><h3>Refactorings (<a href="#refactorings">↑</a>)</h3><div class="subindex"><ul><li><a href="#refactoring_CONVERT_GETTER_TO_METHOD">CONVERT_GETTER_TO_METHOD</a></li><li><a href="#refactoring_CONVERT_METHOD_TO_GETTER">CONVERT_METHOD_TO_GETTER</a></li><li><a href="#refactoring_EXTRACT_LOCAL_VARIABLE">EXTRACT_LOCAL_VARIABLE</a></li><li><a href="#refactoring_EXTRACT_METHOD">EXTRACT_METHOD</a></li><li><a href="#refactoring_EXTRACT_WIDGET">EXTRACT_WIDGET</a></li><li><a href="#refactoring_INLINE_LOCAL_VARIABLE">INLINE_LOCAL_VARIABLE</a></li><li><a href="#refactoring_INLINE_METHOD">INLINE_METHOD</a></li><li><a href="#refactoring_MOVE_FILE">MOVE_FILE</a></li><li><a href="#refactoring_RENAME">RENAME</a></li></ul></div>
+<h3>Domains</h3><h4>server (<a href="#domain_server">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_server.getVersion">getVersion</a></li><li><a href="#request_server.shutdown">shutdown</a></li><li><a href="#request_server.setSubscriptions">setSubscriptions</a></li><li><a href="#request_server.cancelRequest">cancelRequest</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_server.connected">connected</a></li><li><a href="#notification_server.error">error</a></li><li><a href="#notification_server.log">log</a></li><li><a href="#notification_server.status">status</a></li></ul></div></div><h4>analysis (<a href="#domain_analysis">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_analysis.getErrors">getErrors</a></li><li><a href="#request_analysis.getHover">getHover</a></li><li><a href="#request_analysis.getLibraryDependencies">getLibraryDependencies</a></li><li><a href="#request_analysis.getNavigation">getNavigation</a></li><li><a href="#request_analysis.getReachableSources">getReachableSources</a></li><li><a href="#request_analysis.reanalyze">reanalyze</a></li><li><a href="#request_analysis.setAnalysisRoots">setAnalysisRoots</a></li><li><a href="#request_analysis.setGeneralSubscriptions">setGeneralSubscriptions</a></li><li><a href="#request_analysis.setPriorityFiles">setPriorityFiles</a></li><li><a href="#request_analysis.setSubscriptions">setSubscriptions</a></li><li><a href="#request_analysis.updateContent">updateContent</a></li><li><a href="#request_analysis.updateOptions">updateOptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_analysis.analyzedFiles">analyzedFiles</a></li><li><a href="#notification_analysis.closingLabels">closingLabels</a></li><li><a href="#notification_analysis.errors">errors</a></li><li><a href="#notification_analysis.flushResults">flushResults</a></li><li><a href="#notification_analysis.folding">folding</a></li><li><a href="#notification_analysis.highlights">highlights</a></li><li><a href="#notification_analysis.implemented">implemented</a></li><li><a href="#notification_analysis.invalidate">invalidate</a></li><li><a href="#notification_analysis.navigation">navigation</a></li><li><a href="#notification_analysis.occurrences">occurrences</a></li><li><a href="#notification_analysis.outline">outline</a></li><li><a href="#notification_analysis.overrides">overrides</a></li></ul></div></div><h4>completion (<a href="#domain_completion">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_completion.getSuggestions">getSuggestions</a></li><li><a href="#request_completion.setSubscriptions">setSubscriptions</a></li><li><a href="#request_completion.registerLibraryPaths">registerLibraryPaths</a></li><li><a href="#request_completion.getSuggestionDetails">getSuggestionDetails</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_completion.results">results</a></li><li><a href="#notification_completion.availableSuggestions">availableSuggestions</a></li><li><a href="#notification_completion.existingImports">existingImports</a></li></ul></div></div><h4>search (<a href="#domain_search">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_search.findElementReferences">findElementReferences</a></li><li><a href="#request_search.findMemberDeclarations">findMemberDeclarations</a></li><li><a href="#request_search.findMemberReferences">findMemberReferences</a></li><li><a href="#request_search.findTopLevelDeclarations">findTopLevelDeclarations</a></li><li><a href="#request_search.getTypeHierarchy">getTypeHierarchy</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_search.results">results</a></li></ul></div></div><h4>edit (<a href="#domain_edit">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_edit.format">format</a></li><li><a href="#request_edit.getAssists">getAssists</a></li><li><a href="#request_edit.getAvailableRefactorings">getAvailableRefactorings</a></li><li><a href="#request_edit.getFixes">getFixes</a></li><li><a href="#request_edit.getPostfixCompletion">getPostfixCompletion</a></li><li><a href="#request_edit.getRefactoring">getRefactoring</a></li><li><a href="#request_edit.sortMembers">sortMembers</a></li><li><a href="#request_edit.organizeDirectives">organizeDirectives</a></li></ul></div><h4>execution (<a href="#domain_execution">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_execution.createContext">createContext</a></li><li><a href="#request_execution.deleteContext">deleteContext</a></li><li><a href="#request_execution.getSuggestions">getSuggestions</a></li><li><a href="#request_execution.mapUri">mapUri</a></li><li><a href="#request_execution.setSubscriptions">setSubscriptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_execution.launchData">launchData</a></li></ul></div></div><h4>diagnostic (<a href="#domain_diagnostic">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_diagnostic.getDiagnostics">getDiagnostics</a></li><li><a href="#request_diagnostic.getServerPort">getServerPort</a></li></ul></div><h4>flutter (<a href="#domain_flutter">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_flutter.setSubscriptions">setSubscriptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_flutter.outline">outline</a></li></ul></div></div><h3>Types (<a href="#types">↑</a>)</h3><div class="subindex"><ul><li><a href="#type_AddContentOverlay">AddContentOverlay</a></li><li><a href="#type_AnalysisError">AnalysisError</a></li><li><a href="#type_AnalysisErrorFixes">AnalysisErrorFixes</a></li><li><a href="#type_AnalysisErrorSeverity">AnalysisErrorSeverity</a></li><li><a href="#type_AnalysisErrorType">AnalysisErrorType</a></li><li><a href="#type_AnalysisOptions">AnalysisOptions</a></li><li><a href="#type_AnalysisService">AnalysisService</a></li><li><a href="#type_AnalysisStatus">AnalysisStatus</a></li><li><a href="#type_AvailableSuggestion">AvailableSuggestion</a></li><li><a href="#type_AvailableSuggestionRelevanceTag">AvailableSuggestionRelevanceTag</a></li><li><a href="#type_AvailableSuggestionSet">AvailableSuggestionSet</a></li><li><a href="#type_BulkFix">BulkFix</a></li><li><a href="#type_BulkFixDetail">BulkFixDetail</a></li><li><a href="#type_ChangeContentOverlay">ChangeContentOverlay</a></li><li><a href="#type_ClosingLabel">ClosingLabel</a></li><li><a href="#type_CompletionId">CompletionId</a></li><li><a href="#type_CompletionService">CompletionService</a></li><li><a href="#type_CompletionSuggestion">CompletionSuggestion</a></li><li><a href="#type_CompletionSuggestionKind">CompletionSuggestionKind</a></li><li><a href="#type_ContextData">ContextData</a></li><li><a href="#type_DiagnosticMessage">DiagnosticMessage</a></li><li><a href="#type_Element">Element</a></li><li><a href="#type_ElementDeclaration">ElementDeclaration</a></li><li><a href="#type_ElementKind">ElementKind</a></li><li><a href="#type_ExecutableFile">ExecutableFile</a></li><li><a href="#type_ExecutableKind">ExecutableKind</a></li><li><a href="#type_ExecutionContextId">ExecutionContextId</a></li><li><a href="#type_ExecutionService">ExecutionService</a></li><li><a href="#type_ExistingImport">ExistingImport</a></li><li><a href="#type_ExistingImports">ExistingImports</a></li><li><a href="#type_FileKind">FileKind</a></li><li><a href="#type_FilePath">FilePath</a></li><li><a href="#type_FlutterOutline">FlutterOutline</a></li><li><a href="#type_FlutterOutlineAttribute">FlutterOutlineAttribute</a></li><li><a href="#type_FlutterOutlineKind">FlutterOutlineKind</a></li><li><a href="#type_FlutterService">FlutterService</a></li><li><a href="#type_FlutterWidgetProperty">FlutterWidgetProperty</a></li><li><a href="#type_FlutterWidgetPropertyEditor">FlutterWidgetPropertyEditor</a></li><li><a href="#type_FlutterWidgetPropertyEditorKind">FlutterWidgetPropertyEditorKind</a></li><li><a href="#type_FlutterWidgetPropertyValue">FlutterWidgetPropertyValue</a></li><li><a href="#type_FlutterWidgetPropertyValueEnumItem">FlutterWidgetPropertyValueEnumItem</a></li><li><a href="#type_FoldingKind">FoldingKind</a></li><li><a href="#type_FoldingRegion">FoldingRegion</a></li><li><a href="#type_GeneralAnalysisService">GeneralAnalysisService</a></li><li><a href="#type_HighlightRegion">HighlightRegion</a></li><li><a href="#type_HighlightRegionType">HighlightRegionType</a></li><li><a href="#type_HoverInformation">HoverInformation</a></li><li><a href="#type_ImplementedClass">ImplementedClass</a></li><li><a href="#type_ImplementedMember">ImplementedMember</a></li><li><a href="#type_ImportedElementSet">ImportedElementSet</a></li><li><a href="#type_ImportedElements">ImportedElements</a></li><li><a href="#type_IncludedSuggestionRelevanceTag">IncludedSuggestionRelevanceTag</a></li><li><a href="#type_IncludedSuggestionSet">IncludedSuggestionSet</a></li><li><a href="#type_KytheEntry">KytheEntry</a></li><li><a href="#type_KytheVName">KytheVName</a></li><li><a href="#type_LibraryPathSet">LibraryPathSet</a></li><li><a href="#type_LinkedEditGroup">LinkedEditGroup</a></li><li><a href="#type_LinkedEditSuggestion">LinkedEditSuggestion</a></li><li><a href="#type_LinkedEditSuggestionKind">LinkedEditSuggestionKind</a></li><li><a href="#type_Location">Location</a></li><li><a href="#type_NavigationRegion">NavigationRegion</a></li><li><a href="#type_NavigationTarget">NavigationTarget</a></li><li><a href="#type_Occurrences">Occurrences</a></li><li><a href="#type_Outline">Outline</a></li><li><a href="#type_OverriddenMember">OverriddenMember</a></li><li><a href="#type_Override">Override</a></li><li><a href="#type_Position">Position</a></li><li><a href="#type_PostfixTemplateDescriptor">PostfixTemplateDescriptor</a></li><li><a href="#type_PubStatus">PubStatus</a></li><li><a href="#type_RefactoringFeedback">RefactoringFeedback</a></li><li><a href="#type_RefactoringKind">RefactoringKind</a></li><li><a href="#type_RefactoringMethodParameter">RefactoringMethodParameter</a></li><li><a href="#type_RefactoringMethodParameterKind">RefactoringMethodParameterKind</a></li><li><a href="#type_RefactoringOptions">RefactoringOptions</a></li><li><a href="#type_RefactoringProblem">RefactoringProblem</a></li><li><a href="#type_RefactoringProblemSeverity">RefactoringProblemSeverity</a></li><li><a href="#type_RemoveContentOverlay">RemoveContentOverlay</a></li><li><a href="#type_RequestError">RequestError</a></li><li><a href="#type_RequestErrorCode">RequestErrorCode</a></li><li><a href="#type_RuntimeCompletionExpression">RuntimeCompletionExpression</a></li><li><a href="#type_RuntimeCompletionExpressionType">RuntimeCompletionExpressionType</a></li><li><a href="#type_RuntimeCompletionExpressionTypeKind">RuntimeCompletionExpressionTypeKind</a></li><li><a href="#type_RuntimeCompletionVariable">RuntimeCompletionVariable</a></li><li><a href="#type_SearchId">SearchId</a></li><li><a href="#type_SearchResult">SearchResult</a></li><li><a href="#type_SearchResultKind">SearchResultKind</a></li><li><a href="#type_ServerService">ServerService</a></li><li><a href="#type_SourceChange">SourceChange</a></li><li><a href="#type_SourceEdit">SourceEdit</a></li><li><a href="#type_SourceFileEdit">SourceFileEdit</a></li><li><a href="#type_TypeHierarchyItem">TypeHierarchyItem</a></li></ul></div><h3>Refactorings (<a href="#refactorings">↑</a>)</h3><div class="subindex"><ul><li><a href="#refactoring_CONVERT_GETTER_TO_METHOD">CONVERT_GETTER_TO_METHOD</a></li><li><a href="#refactoring_CONVERT_METHOD_TO_GETTER">CONVERT_METHOD_TO_GETTER</a></li><li><a href="#refactoring_EXTRACT_LOCAL_VARIABLE">EXTRACT_LOCAL_VARIABLE</a></li><li><a href="#refactoring_EXTRACT_METHOD">EXTRACT_METHOD</a></li><li><a href="#refactoring_EXTRACT_WIDGET">EXTRACT_WIDGET</a></li><li><a href="#refactoring_INLINE_LOCAL_VARIABLE">INLINE_LOCAL_VARIABLE</a></li><li><a href="#refactoring_INLINE_METHOD">INLINE_METHOD</a></li><li><a href="#refactoring_MOVE_FILE">MOVE_FILE</a></li><li><a href="#refactoring_RENAME">RENAME</a></li></ul></div>
</body></html>
\ No newline at end of file
diff --git a/pkg/analysis_server/lib/protocol/protocol.dart b/pkg/analysis_server/lib/protocol/protocol.dart
index 263083a..4899638 100644
--- a/pkg/analysis_server/lib/protocol/protocol.dart
+++ b/pkg/analysis_server/lib/protocol/protocol.dart
@@ -8,6 +8,7 @@
import 'package:analysis_server/protocol/protocol_generated.dart';
import 'package:analysis_server/src/protocol/protocol_internal.dart';
+import 'package:analysis_server/src/utilities/progress.dart';
export 'package:analyzer_plugin/protocol/protocol.dart' show Enum;
@@ -270,7 +271,7 @@
/// this handler, return `null` so that other handlers will be given a chance
/// to handle it. Otherwise, return the response that should be passed back to
/// the client.
- Response? handleRequest(Request request);
+ Response? handleRequest(Request request, CancellationToken cancellationToken);
}
/// A response to a request.
diff --git a/pkg/analysis_server/lib/protocol/protocol_constants.dart b/pkg/analysis_server/lib/protocol/protocol_constants.dart
index 85a4474..00b690a 100644
--- a/pkg/analysis_server/lib/protocol/protocol_constants.dart
+++ b/pkg/analysis_server/lib/protocol/protocol_constants.dart
@@ -6,7 +6,7 @@
// To regenerate the file, use the script
// "pkg/analysis_server/tool/spec/generate_files".
-const String PROTOCOL_VERSION = '1.32.7';
+const String PROTOCOL_VERSION = '1.32.8';
const String ANALYSIS_NOTIFICATION_ANALYZED_FILES = 'analysis.analyzedFiles';
const String ANALYSIS_NOTIFICATION_ANALYZED_FILES_DIRECTORIES = 'directories';
@@ -356,6 +356,8 @@
const String SERVER_NOTIFICATION_STATUS = 'server.status';
const String SERVER_NOTIFICATION_STATUS_ANALYSIS = 'analysis';
const String SERVER_NOTIFICATION_STATUS_PUB = 'pub';
+const String SERVER_REQUEST_CANCEL_REQUEST = 'server.cancelRequest';
+const String SERVER_REQUEST_CANCEL_REQUEST_ID = 'id';
const String SERVER_REQUEST_GET_VERSION = 'server.getVersion';
const String SERVER_REQUEST_SET_SUBSCRIPTIONS = 'server.setSubscriptions';
const String SERVER_REQUEST_SET_SUBSCRIPTIONS_SUBSCRIPTIONS = 'subscriptions';
diff --git a/pkg/analysis_server/lib/protocol/protocol_generated.dart b/pkg/analysis_server/lib/protocol/protocol_generated.dart
index bfdf408..8d9f921 100644
--- a/pkg/analysis_server/lib/protocol/protocol_generated.dart
+++ b/pkg/analysis_server/lib/protocol/protocol_generated.dart
@@ -15633,6 +15633,91 @@
);
}
+/// server.cancelRequest params
+///
+/// {
+/// "id": String
+/// }
+///
+/// Clients may not extend, implement or mix-in this class.
+class ServerCancelRequestParams implements RequestParams {
+ /// The id of the request that should be cancelled.
+ String id;
+
+ ServerCancelRequestParams(this.id);
+
+ factory ServerCancelRequestParams.fromJson(
+ JsonDecoder jsonDecoder, String jsonPath, Object? json) {
+ json ??= {};
+ if (json is Map) {
+ String id;
+ if (json.containsKey('id')) {
+ id = jsonDecoder.decodeString(jsonPath + '.id', json['id']);
+ } else {
+ throw jsonDecoder.mismatch(jsonPath, 'id');
+ }
+ return ServerCancelRequestParams(id);
+ } else {
+ throw jsonDecoder.mismatch(jsonPath, 'server.cancelRequest params', json);
+ }
+ }
+
+ factory ServerCancelRequestParams.fromRequest(Request request) {
+ return ServerCancelRequestParams.fromJson(
+ RequestDecoder(request), 'params', request.params);
+ }
+
+ @override
+ Map<String, Object> toJson() {
+ var result = <String, Object>{};
+ result['id'] = id;
+ return result;
+ }
+
+ @override
+ Request toRequest(String id) {
+ return Request(id, 'server.cancelRequest', toJson());
+ }
+
+ @override
+ String toString() => json.encode(toJson());
+
+ @override
+ bool operator ==(other) {
+ if (other is ServerCancelRequestParams) {
+ return id == other.id;
+ }
+ return false;
+ }
+
+ @override
+ int get hashCode => id.hashCode;
+}
+
+/// server.cancelRequest result
+///
+/// Clients may not extend, implement or mix-in this class.
+class ServerCancelRequestResult implements ResponseResult {
+ @override
+ Map<String, Object> toJson() => <String, Object>{};
+
+ @override
+ Response toResponse(String id) {
+ return Response(id, result: null);
+ }
+
+ @override
+ bool operator ==(other) {
+ if (other is ServerCancelRequestResult) {
+ return true;
+ }
+ return false;
+ }
+
+ @override
+ int get hashCode => 183255719;
+}
+
/// server.connected params
///
/// {
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index bbe634a..dc3332a 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -41,6 +41,7 @@
import 'package:analysis_server/src/server/sdk_configuration.dart';
import 'package:analysis_server/src/services/flutter/widget_descriptions.dart';
import 'package:analysis_server/src/utilities/process.dart';
+import 'package:analysis_server/src/utilities/progress.dart';
import 'package:analysis_server/src/utilities/request_statistics.dart';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/ast/ast.dart';
@@ -81,6 +82,13 @@
/// A set of the [ServerService]s to send notifications for.
Set<ServerService> serverServices = HashSet<ServerService>();
+ /// A table mapping request ids to cancellation tokens that allow cancelling
+ /// the request.
+ ///
+ /// Tokens are removed once a request completes and should not be assumed to
+ /// exist in this table just because cancellation was requested.
+ Map<String, CancelableToken> cancellationTokens = {};
+
/// A set of the [GeneralAnalysisService]s to send notifications for.
Set<GeneralAnalysisService> generalAnalysisServices =
HashSet<GeneralAnalysisService>();
@@ -219,6 +227,10 @@
return sdkManager.defaultSdkDirectory;
}
+ void cancelRequest(String id) {
+ cancellationTokens[id]?.cancel();
+ }
+
/// The socket from which requests are being read has been closed.
void done() {}
@@ -241,30 +253,32 @@
void handleRequest(Request request) {
performance.logRequestTiming(request.clientRequestTime);
runZonedGuarded(() {
+ var cancellationToken = CancelableToken();
+ cancellationTokens[request.id] = cancellationToken;
var count = handlers.length;
for (var i = 0; i < count; i++) {
try {
- var response = handlers[i].handleRequest(request);
+ var response = handlers[i].handleRequest(request, cancellationToken);
if (response == Response.DELAYED_RESPONSE) {
return;
}
if (response != null) {
- channel.sendResponse(response);
+ sendResponse(response);
return;
}
} on RequestFailure catch (exception) {
- channel.sendResponse(exception.response);
+ sendResponse(exception.response);
return;
} catch (exception, stackTrace) {
var error =
RequestError(RequestErrorCode.SERVER_ERROR, exception.toString());
error.stackTrace = stackTrace.toString();
var response = Response(request.id, error: error);
- channel.sendResponse(response);
+ sendResponse(response);
return;
}
}
- channel.sendResponse(Response.unknownRequest(request));
+ sendResponse(Response.unknownRequest(request));
}, (exception, stackTrace) {
instrumentationService.logException(
FatalException(
@@ -310,6 +324,7 @@
/// Send the given [response] to the client.
void sendResponse(Response response) {
channel.sendResponse(response);
+ cancellationTokens.remove(response.id);
}
/// If the [path] is not a valid file path, that is absolute and normalized,
diff --git a/pkg/analysis_server/lib/src/domain_analysis.dart b/pkg/analysis_server/lib/src/domain_analysis.dart
index 1595e38..d079a6b 100644
--- a/pkg/analysis_server/lib/src/domain_analysis.dart
+++ b/pkg/analysis_server/lib/src/domain_analysis.dart
@@ -13,6 +13,7 @@
import 'package:analysis_server/src/plugin/result_merger.dart';
import 'package:analysis_server/src/protocol/protocol_internal.dart';
import 'package:analysis_server/src/protocol_server.dart';
+import 'package:analysis_server/src/utilities/progress.dart';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/src/generated/engine.dart' as engine;
import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin;
@@ -254,7 +255,8 @@
}
@override
- Response? handleRequest(Request request) {
+ Response? handleRequest(
+ Request request, CancellationToken cancellationToken) {
try {
var requestName = request.method;
if (requestName == ANALYSIS_REQUEST_GET_ERRORS) {
diff --git a/pkg/analysis_server/lib/src/domain_analytics.dart b/pkg/analysis_server/lib/src/domain_analytics.dart
index 66df103..cec9fa8 100644
--- a/pkg/analysis_server/lib/src/domain_analytics.dart
+++ b/pkg/analysis_server/lib/src/domain_analytics.dart
@@ -6,6 +6,7 @@
import 'package:analysis_server/protocol/protocol_constants.dart';
import 'package:analysis_server/protocol/protocol_generated.dart';
import 'package:analysis_server/src/analysis_server.dart';
+import 'package:analysis_server/src/utilities/progress.dart';
import 'package:telemetry/telemetry.dart';
/// Instances of the class [AnalyticsDomainHandler] implement a [RequestHandler]
@@ -34,7 +35,8 @@
}
@override
- Response? handleRequest(Request request) {
+ Response? handleRequest(
+ Request request, CancellationToken cancellationToken) {
var requestName = request.method;
if (requestName == ANALYTICS_REQUEST_IS_ENABLED) {
diff --git a/pkg/analysis_server/lib/src/domain_completion.dart b/pkg/analysis_server/lib/src/domain_completion.dart
index 60c81b6..692b65f 100644
--- a/pkg/analysis_server/lib/src/domain_completion.dart
+++ b/pkg/analysis_server/lib/src/domain_completion.dart
@@ -22,6 +22,7 @@
import 'package:analysis_server/src/services/completion/yaml/fix_data_generator.dart';
import 'package:analysis_server/src/services/completion/yaml/pubspec_generator.dart';
import 'package:analysis_server/src/services/completion/yaml/yaml_completion_generator.dart';
+import 'package:analysis_server/src/utilities/progress.dart';
import 'package:analyzer/dart/analysis/session.dart';
import 'package:analyzer/exception/exception.dart';
import 'package:analyzer/src/generated/engine.dart';
@@ -425,7 +426,8 @@
}
@override
- Response? handleRequest(Request request) {
+ Response? handleRequest(
+ Request request, CancellationToken cancellationToken) {
if (!server.options.featureSet.completion) {
return Response.invalidParameter(
request,
diff --git a/pkg/analysis_server/lib/src/domain_diagnostic.dart b/pkg/analysis_server/lib/src/domain_diagnostic.dart
index 59056f2..117bec4 100644
--- a/pkg/analysis_server/lib/src/domain_diagnostic.dart
+++ b/pkg/analysis_server/lib/src/domain_diagnostic.dart
@@ -6,6 +6,7 @@
import 'package:analysis_server/protocol/protocol_constants.dart';
import 'package:analysis_server/protocol/protocol_generated.dart';
import 'package:analysis_server/src/analysis_server.dart';
+import 'package:analysis_server/src/utilities/progress.dart';
import 'package:analyzer/src/dart/analysis/driver.dart';
/// Instances of the class [DiagnosticDomainHandler] implement a
@@ -45,7 +46,8 @@
}
@override
- Response? handleRequest(Request request) {
+ Response? handleRequest(
+ Request request, CancellationToken cancellationToken) {
try {
var requestName = request.method;
if (requestName == DIAGNOSTIC_REQUEST_GET_DIAGNOSTICS) {
diff --git a/pkg/analysis_server/lib/src/domain_execution.dart b/pkg/analysis_server/lib/src/domain_execution.dart
index 5550f0b..c1e1b35 100644
--- a/pkg/analysis_server/lib/src/domain_execution.dart
+++ b/pkg/analysis_server/lib/src/domain_execution.dart
@@ -7,6 +7,7 @@
import 'package:analysis_server/protocol/protocol_constants.dart';
import 'package:analysis_server/src/analysis_server.dart';
import 'package:analysis_server/src/protocol_server.dart';
+import 'package:analysis_server/src/utilities/progress.dart';
import 'package:analyzer/file_system/file_system.dart';
/// Instances of the class [ExecutionDomainHandler] implement a [RequestHandler]
@@ -68,7 +69,8 @@
}
@override
- Response? handleRequest(Request request) {
+ Response? handleRequest(
+ Request request, CancellationToken cancellationToken) {
try {
var requestName = request.method;
if (requestName == EXECUTION_REQUEST_CREATE_CONTEXT) {
diff --git a/pkg/analysis_server/lib/src/domain_kythe.dart b/pkg/analysis_server/lib/src/domain_kythe.dart
index 0316e8f..0be62d1 100644
--- a/pkg/analysis_server/lib/src/domain_kythe.dart
+++ b/pkg/analysis_server/lib/src/domain_kythe.dart
@@ -9,6 +9,7 @@
import 'package:analysis_server/src/domain_abstract.dart';
import 'package:analysis_server/src/plugin/result_merger.dart';
import 'package:analysis_server/src/services/kythe/kythe_visitors.dart';
+import 'package:analysis_server/src/utilities/progress.dart';
import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin;
@@ -70,7 +71,8 @@
}
@override
- Response? handleRequest(Request request) {
+ Response? handleRequest(
+ Request request, CancellationToken cancellationToken) {
try {
var requestName = request.method;
if (requestName == KYTHE_REQUEST_GET_KYTHE_ENTRIES) {
diff --git a/pkg/analysis_server/lib/src/domain_server.dart b/pkg/analysis_server/lib/src/domain_server.dart
index 559f3b8..54efa9a 100644
--- a/pkg/analysis_server/lib/src/domain_server.dart
+++ b/pkg/analysis_server/lib/src/domain_server.dart
@@ -6,6 +6,7 @@
import 'package:analysis_server/protocol/protocol_constants.dart';
import 'package:analysis_server/protocol/protocol_generated.dart';
import 'package:analysis_server/src/analysis_server.dart';
+import 'package:analysis_server/src/utilities/progress.dart';
/// Instances of the class [ServerDomainHandler] implement a [RequestHandler]
/// that handles requests in the server domain.
@@ -17,6 +18,13 @@
/// [server].
ServerDomainHandler(this.server);
+ Response cancelRequest(Request request) {
+ final id = ServerCancelRequestParams.fromRequest(request).id;
+ server.cancelRequest(id);
+
+ return ServerCancelRequestResult().toResponse(request.id);
+ }
+
/// Return the version number of the analysis server.
Response getVersion(Request request) {
return ServerGetVersionResult(
@@ -25,7 +33,8 @@
}
@override
- Response? handleRequest(Request request) {
+ Response? handleRequest(
+ Request request, CancellationToken cancellationToken) {
try {
var requestName = request.method;
if (requestName == SERVER_REQUEST_GET_VERSION) {
@@ -35,6 +44,8 @@
} else if (requestName == SERVER_REQUEST_SHUTDOWN) {
shutdown(request);
return Response.DELAYED_RESPONSE;
+ } else if (requestName == SERVER_REQUEST_CANCEL_REQUEST) {
+ return cancelRequest(request);
}
} on RequestFailure catch (exception) {
return exception.response;
diff --git a/pkg/analysis_server/lib/src/edit/edit_domain.dart b/pkg/analysis_server/lib/src/edit/edit_domain.dart
index b73448c..ab7cbeb 100644
--- a/pkg/analysis_server/lib/src/edit/edit_domain.dart
+++ b/pkg/analysis_server/lib/src/edit/edit_domain.dart
@@ -32,6 +32,7 @@
import 'package:analysis_server/src/services/correction/status.dart';
import 'package:analysis_server/src/services/refactoring/refactoring.dart';
import 'package:analysis_server/src/services/search/search_engine.dart';
+import 'package:analysis_server/src/utilities/progress.dart';
import 'package:analyzer/dart/analysis/session.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/error/error.dart' as engine;
@@ -337,7 +338,8 @@
}
@override
- Response? handleRequest(Request request) {
+ Response? handleRequest(
+ Request request, CancellationToken cancellationToken) {
try {
var requestName = request.method;
if (requestName == EDIT_REQUEST_FORMAT) {
diff --git a/pkg/analysis_server/lib/src/flutter/flutter_domain.dart b/pkg/analysis_server/lib/src/flutter/flutter_domain.dart
index 6ec33cc..66bce33 100644
--- a/pkg/analysis_server/lib/src/flutter/flutter_domain.dart
+++ b/pkg/analysis_server/lib/src/flutter/flutter_domain.dart
@@ -7,6 +7,7 @@
import 'package:analysis_server/src/domain_abstract.dart';
import 'package:analysis_server/src/protocol/protocol_internal.dart';
import 'package:analysis_server/src/protocol_server.dart';
+import 'package:analysis_server/src/utilities/progress.dart';
import 'package:analyzer/dart/analysis/session.dart';
/// A [RequestHandler] that handles requests in the `flutter` domain.
@@ -71,7 +72,8 @@
}
@override
- Response? handleRequest(Request request) {
+ Response? handleRequest(
+ Request request, CancellationToken cancellationToken) {
try {
var requestName = request.method;
if (requestName == FLUTTER_REQUEST_GET_WIDGET_DESCRIPTION) {
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handlers.dart b/pkg/analysis_server/lib/src/lsp/handlers/handlers.dart
index 6b2ed52..e0f497c 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handlers.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handlers.dart
@@ -14,11 +14,14 @@
import 'package:analysis_server/src/lsp/json_parsing.dart';
import 'package:analysis_server/src/lsp/lsp_analysis_server.dart';
import 'package:analysis_server/src/lsp/progress.dart';
+import 'package:analysis_server/src/utilities/progress.dart';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/source/line_info.dart';
import 'package:analyzer_plugin/protocol/protocol.dart';
import 'package:analyzer_plugin/src/protocol/protocol_internal.dart';
+export 'package:analysis_server/src/utilities/progress.dart';
+
/// Converts an iterable using the provided function and skipping over any
/// null values.
Iterable<T> convert<T, E>(Iterable<E> items, T Function(E) converter) {
@@ -27,22 +30,6 @@
return items.map(converter).where((item) => item != null);
}
-class CancelableToken extends CancellationToken {
- bool _isCancelled = false;
-
- @override
- bool get isCancellationRequested => _isCancelled;
-
- void cancel() => _isCancelled = true;
-}
-
-/// A token used to signal cancellation of an operation. This allows computation
-/// to be skipped when a caller is no longer interested in the result, for example
-/// when a $/cancel request is recieved for an in-progress request.
-abstract class CancellationToken {
- bool get isCancellationRequested;
-}
-
abstract class CommandHandler<P, R> with Handler<P, R> {
@override
final LspAnalysisServer server;
@@ -151,11 +138,6 @@
}
}
-class NotCancelableToken extends CancellationToken {
- @override
- bool get isCancellationRequested => false;
-}
-
/// A message handler that handles all messages for a given server state.
abstract class ServerStateMessageHandler {
final LspAnalysisServer server;
diff --git a/pkg/analysis_server/lib/src/search/search_domain.dart b/pkg/analysis_server/lib/src/search/search_domain.dart
index 04542a8..f854cc4 100644
--- a/pkg/analysis_server/lib/src/search/search_domain.dart
+++ b/pkg/analysis_server/lib/src/search/search_domain.dart
@@ -11,6 +11,7 @@
import 'package:analysis_server/src/search/element_references.dart';
import 'package:analysis_server/src/search/type_hierarchy.dart';
import 'package:analysis_server/src/services/search/search_engine.dart';
+import 'package:analysis_server/src/utilities/progress.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/src/dart/analysis/search.dart' as search;
@@ -228,7 +229,8 @@
}
@override
- protocol.Response? handleRequest(protocol.Request request) {
+ protocol.Response? handleRequest(
+ protocol.Request request, CancellationToken cancellationToken) {
try {
var requestName = request.method;
if (requestName == SEARCH_REQUEST_FIND_ELEMENT_REFERENCES) {
diff --git a/pkg/analysis_server/lib/src/utilities/progress.dart b/pkg/analysis_server/lib/src/utilities/progress.dart
new file mode 100644
index 0000000..822b750
--- /dev/null
+++ b/pkg/analysis_server/lib/src/utilities/progress.dart
@@ -0,0 +1,25 @@
+// 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.
+
+class CancelableToken extends CancellationToken {
+ bool _isCancelled = false;
+
+ @override
+ bool get isCancellationRequested => _isCancelled;
+
+ void cancel() => _isCancelled = true;
+}
+
+/// A token used to signal cancellation of an operation. This allows computation
+/// to be skipped when a caller is no longer interested in the result, for example
+/// when a $/cancel request is recieved for an in-progress request.
+abstract class CancellationToken {
+ bool get isCancellationRequested;
+}
+
+/// A [CancellationToken] that cannot be cancelled.
+class NotCancelableToken extends CancellationToken {
+ @override
+ bool get isCancellationRequested => false;
+}
diff --git a/pkg/analysis_server/test/analysis_abstract.dart b/pkg/analysis_server/test/analysis_abstract.dart
index 809d27a..558a318 100644
--- a/pkg/analysis_server/test/analysis_abstract.dart
+++ b/pkg/analysis_server/test/analysis_abstract.dart
@@ -10,6 +10,7 @@
import 'package:analysis_server/src/domain_analysis.dart';
import 'package:analysis_server/src/server/crash_reporting_attachments.dart';
import 'package:analysis_server/src/utilities/mocks.dart';
+import 'package:analysis_server/src/utilities/progress.dart';
import 'package:analyzer/instrumentation/instrumentation.dart';
import 'package:analyzer/src/dart/analysis/driver.dart';
import 'package:analyzer/src/generated/engine.dart';
@@ -145,7 +146,7 @@
/// Validates that the given [request] is handled successfully.
Response handleSuccessfulRequest(Request request, {RequestHandler? handler}) {
handler ??= this.handler;
- var response = handler.handleRequest(request)!;
+ var response = handler.handleRequest(request, NotCancelableToken())!;
expect(response, isResponseSuccess(request.id));
return response;
}
diff --git a/pkg/analysis_server/test/analysis_server_test.dart b/pkg/analysis_server/test/analysis_server_test.dart
index 4b41a22..907c39a 100644
--- a/pkg/analysis_server/test/analysis_server_test.dart
+++ b/pkg/analysis_server/test/analysis_server_test.dart
@@ -9,6 +9,7 @@
import 'package:analysis_server/src/domain_server.dart';
import 'package:analysis_server/src/server/crash_reporting_attachments.dart';
import 'package:analysis_server/src/utilities/mocks.dart';
+import 'package:analysis_server/src/utilities/progress.dart';
import 'package:analyzer/instrumentation/instrumentation.dart';
import 'package:analyzer/src/generated/sdk.dart';
import 'package:analyzer/src/test_utilities/mock_sdk.dart';
@@ -94,7 +95,7 @@
}
Future test_echo() {
- server.handlers = [EchoHandler()];
+ server.handlers = [EchoHandler(server)];
var request = Request('my22', 'echo');
return channel.sendRequest(request).then((Response response) {
expect(response.id, equals('my22'));
@@ -215,8 +216,39 @@
});
}
+ Future test_slowEcho_cancelled() async {
+ server.handlers = [
+ ServerDomainHandler(server),
+ EchoHandler(server),
+ ];
+ // Send the normal request.
+ var responseFuture = channel.sendRequest(Request('my22', 'slowEcho'));
+ // Send a cancellation for it for waiting for it to complete.
+ channel.sendRequest(
+ Request(
+ 'my23',
+ 'server.cancelRequest',
+ {'id': 'my22'},
+ ),
+ );
+ var response = await responseFuture;
+ expect(response.id, equals('my22'));
+ expect(response.error, isNull);
+ expect(response.result!['cancelled'], isTrue);
+ }
+
+ Future test_slowEcho_notCancelled() {
+ server.handlers = [EchoHandler(server)];
+ var request = Request('my22', 'slowEcho');
+ return channel.sendRequest(request).then((Response response) {
+ expect(response.id, equals('my22'));
+ expect(response.error, isNull);
+ expect(response.result!['cancelled'], isFalse);
+ });
+ }
+
Future test_unknownRequest() {
- server.handlers = [EchoHandler()];
+ server.handlers = [EchoHandler(server)];
var request = Request('my22', 'randomRequest');
return channel.sendRequest(request).then((Response response) {
expect(response.id, equals('my22'));
@@ -226,11 +258,29 @@
}
class EchoHandler implements RequestHandler {
+ final AnalysisServer server;
+
+ EchoHandler(this.server);
+
@override
- Response? handleRequest(Request request) {
+ Response? handleRequest(
+ Request request, CancellationToken cancellationToken) {
if (request.method == 'echo') {
return Response(request.id, result: {'echo': true});
+ } else if (request.method == 'slowEcho') {
+ _slowEcho(request, cancellationToken);
+ return Response.DELAYED_RESPONSE;
}
return null;
}
+
+ void _slowEcho(Request request, CancellationToken cancellationToken) async {
+ for (var i = 0; i < 100; i++) {
+ if (cancellationToken.isCancellationRequested) {
+ server.sendResponse(Response(request.id, result: {'cancelled': true}));
+ }
+ await Future.delayed(const Duration(milliseconds: 10));
+ }
+ server.sendResponse(Response(request.id, result: {'cancelled': false}));
+ }
}
diff --git a/pkg/analysis_server/test/client/impl/abstract_client.dart b/pkg/analysis_server/test/client/impl/abstract_client.dart
index 51bd14d..999451f 100644
--- a/pkg/analysis_server/test/client/impl/abstract_client.dart
+++ b/pkg/analysis_server/test/client/impl/abstract_client.dart
@@ -10,6 +10,7 @@
import 'package:analysis_server/src/domain_completion.dart';
import 'package:analysis_server/src/server/crash_reporting_attachments.dart';
import 'package:analysis_server/src/utilities/mocks.dart';
+import 'package:analysis_server/src/utilities/progress.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/file_system/memory_file_system.dart';
import 'package:analyzer/instrumentation/instrumentation.dart';
@@ -132,7 +133,7 @@
/// Validate that the given [request] is handled successfully.
Response handleSuccessfulRequest(Request request, {RequestHandler? handler}) {
handler ??= analysisHandler;
- var response = handler.handleRequest(request)!;
+ var response = handler.handleRequest(request, NotCancelableToken())!;
expect(response, isResponseSuccess(request.id));
return response;
}
diff --git a/pkg/analysis_server/test/domain_analysis_test.dart b/pkg/analysis_server/test/domain_analysis_test.dart
index 317cc59..fa3b3e4 100644
--- a/pkg/analysis_server/test/domain_analysis_test.dart
+++ b/pkg/analysis_server/test/domain_analysis_test.dart
@@ -11,6 +11,7 @@
import 'package:analysis_server/src/domain_analysis.dart';
import 'package:analysis_server/src/server/crash_reporting_attachments.dart';
import 'package:analysis_server/src/utilities/mocks.dart';
+import 'package:analysis_server/src/utilities/progress.dart';
import 'package:analyzer/instrumentation/instrumentation.dart';
import 'package:analyzer/src/generated/sdk.dart';
import 'package:analyzer/src/test_utilities/mock_sdk.dart';
@@ -89,7 +90,7 @@
var contentChange = ChangeContentOverlay([edit]);
var request = AnalysisUpdateContentParams({helper.testFile: contentChange})
.toRequest('0');
- var response = helper.handler.handleRequest(request);
+ var response = helper.handler.handleRequest(request, NotCancelableToken());
expect(response,
isResponseFailure('0', RequestErrorCode.INVALID_OVERLAY_CHANGE));
}
@@ -156,7 +157,7 @@
var request = AnalysisSetPriorityFilesParams(
[convertPath('/project/lib.dart')],
).toRequest('0');
- var response = handler.handleRequest(request);
+ var response = handler.handleRequest(request, NotCancelableToken());
expect(response, isResponseSuccess('0'));
}
@@ -172,12 +173,13 @@
var setRootsRequest =
AnalysisSetAnalysisRootsParams([p1, p2], []).toRequest('0');
- var setRootsResponse = handler.handleRequest(setRootsRequest);
+ var setRootsResponse =
+ handler.handleRequest(setRootsRequest, NotCancelableToken());
expect(setRootsResponse, isResponseSuccess('0'));
void setPriorityFiles(List<String> fileList) {
var request = AnalysisSetPriorityFilesParams(fileList).toRequest('0');
- var response = handler.handleRequest(request);
+ var response = handler.handleRequest(request, NotCancelableToken());
expect(response, isResponseSuccess('0'));
// TODO(brianwilkerson) Enable the line below after getPriorityFiles
// has been implemented.
@@ -200,7 +202,7 @@
}
}
});
- var response = helper.handler.handleRequest(request);
+ var response = helper.handler.handleRequest(request, NotCancelableToken());
expect(response, isResponseFailure('0'));
}
@@ -290,7 +292,7 @@
var request = Request('0', ANALYSIS_REQUEST_UPDATE_OPTIONS, {
ANALYSIS_REQUEST_UPDATE_OPTIONS_OPTIONS: {'not-an-option': true}
});
- var response = handler.handleRequest(request);
+ var response = handler.handleRequest(request, NotCancelableToken());
// Invalid options should be silently ignored.
expect(response, isResponseSuccess('0'));
}
@@ -299,14 +301,14 @@
// null is allowed as a synonym for {}.
var request = Request('0', ANALYSIS_REQUEST_UPDATE_OPTIONS,
{ANALYSIS_REQUEST_UPDATE_OPTIONS_OPTIONS: null});
- var response = handler.handleRequest(request);
+ var response = handler.handleRequest(request, NotCancelableToken());
expect(response, isResponseSuccess('0'));
}
Response testSetAnalysisRoots(List<String> included, List<String> excluded) {
var request =
AnalysisSetAnalysisRootsParams(included, excluded).toRequest('0');
- return handler.handleRequest(request)!;
+ return handler.handleRequest(request, NotCancelableToken())!;
}
Future<void> xtest_getReachableSources_invalidSource() async {
@@ -319,7 +321,7 @@
var request = AnalysisGetReachableSourcesParams('/does/not/exist.dart')
.toRequest('0');
- var response = handler.handleRequest(request)!;
+ var response = handler.handleRequest(request, NotCancelableToken())!;
var error = response.error!;
expect(error.code, RequestErrorCode.GET_REACHABLE_SOURCES_INVALID_FILE);
}
@@ -335,7 +337,7 @@
await server.onAnalysisComplete;
var request = AnalysisGetReachableSourcesParams(fileA).toRequest('0');
- var response = handler.handleRequest(request)!;
+ var response = handler.handleRequest(request, NotCancelableToken())!;
var json = response.toJson()[Response.RESULT] as Map<String, dynamic>;
@@ -1577,7 +1579,7 @@
/// Validates that the given [request] is handled successfully.
void handleSuccessfulRequest(Request request) {
- var response = handler.handleRequest(request);
+ var response = handler.handleRequest(request, NotCancelableToken());
expect(response, isResponseSuccess('0'));
}
diff --git a/pkg/analysis_server/test/domain_diagnostic_test.dart b/pkg/analysis_server/test/domain_diagnostic_test.dart
index f83771a..92ab990 100644
--- a/pkg/analysis_server/test/domain_diagnostic_test.dart
+++ b/pkg/analysis_server/test/domain_diagnostic_test.dart
@@ -4,6 +4,7 @@
import 'package:analysis_server/protocol/protocol_generated.dart';
import 'package:analysis_server/src/domain_diagnostic.dart';
+import 'package:analysis_server/src/utilities/progress.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -33,7 +34,7 @@
await server.onAnalysisComplete;
var request = DiagnosticGetDiagnosticsParams().toRequest('0');
- var response = handler.handleRequest(request)!;
+ var response = handler.handleRequest(request, NotCancelableToken())!;
var result = DiagnosticGetDiagnosticsResult.fromResponse(response);
expect(result.contexts, hasLength(1));
@@ -49,7 +50,7 @@
Future<void> test_getDiagnostics_noRoot() async {
var request = DiagnosticGetDiagnosticsParams().toRequest('0');
- var response = handler.handleRequest(request)!;
+ var response = handler.handleRequest(request, NotCancelableToken())!;
var result = DiagnosticGetDiagnosticsResult.fromResponse(response);
expect(result.contexts, isEmpty);
}
diff --git a/pkg/analysis_server/test/domain_execution_test.dart b/pkg/analysis_server/test/domain_execution_test.dart
index 107cab5..7095b0c 100644
--- a/pkg/analysis_server/test/domain_execution_test.dart
+++ b/pkg/analysis_server/test/domain_execution_test.dart
@@ -8,6 +8,7 @@
import 'package:analysis_server/src/protocol_server.dart';
import 'package:analysis_server/src/server/crash_reporting_attachments.dart';
import 'package:analysis_server/src/utilities/mocks.dart';
+import 'package:analysis_server/src/utilities/progress.dart';
import 'package:analyzer/file_system/memory_file_system.dart';
import 'package:analyzer/instrumentation/instrumentation.dart';
import 'package:analyzer/src/generated/sdk.dart';
@@ -40,13 +41,13 @@
group('createContext/deleteContext', () {
test('create/delete multiple contexts', () {
var request = ExecutionCreateContextParams('/a/b.dart').toRequest('0');
- var response = handler.handleRequest(request)!;
+ var response = handler.handleRequest(request, NotCancelableToken())!;
expect(response, isResponseSuccess('0'));
var result = ExecutionCreateContextResult.fromResponse(response);
var id0 = result.id;
request = ExecutionCreateContextParams('/c/d.dart').toRequest('1');
- response = handler.handleRequest(request)!;
+ response = handler.handleRequest(request, NotCancelableToken())!;
expect(response, isResponseSuccess('1'));
result = ExecutionCreateContextResult.fromResponse(response);
var id1 = result.id;
@@ -54,17 +55,17 @@
expect(id0 == id1, isFalse);
request = ExecutionDeleteContextParams(id0).toRequest('2');
- response = handler.handleRequest(request)!;
+ response = handler.handleRequest(request, NotCancelableToken())!;
expect(response, isResponseSuccess('2'));
request = ExecutionDeleteContextParams(id1).toRequest('3');
- response = handler.handleRequest(request)!;
+ response = handler.handleRequest(request, NotCancelableToken())!;
expect(response, isResponseSuccess('3'));
});
test('delete non-existent context', () {
var request = ExecutionDeleteContextParams('13').toRequest('0');
- var response = handler.handleRequest(request);
+ var response = handler.handleRequest(request, NotCancelableToken());
// TODO(brianwilkerson) It isn't currently specified to be an error if a
// client attempts to delete a context that doesn't exist. Should it be?
// expect(response, isResponseFailure('0'));
@@ -79,7 +80,7 @@
//
// void createExecutionContextIdForFile(String path) {
// Request request = new ExecutionCreateContextParams(path).toRequest('0');
-// Response response = handler.handleRequest(request);
+// Response response = handler.handleRequest(request, NotCancelableToken());
// expect(response, isResponseSuccess('0'));
// ExecutionCreateContextResult result =
// new ExecutionCreateContextResult.fromResponse(response);
@@ -102,7 +103,7 @@
// tearDown(() {
// Request request =
// new ExecutionDeleteContextParams(contextId).toRequest('1');
-// Response response = handler.handleRequest(request);
+// Response response = handler.handleRequest(request, NotCancelableToken());
// expect(response, isResponseSuccess('1'));
// });
//
@@ -111,7 +112,7 @@
// Request request =
// new ExecutionMapUriParams(contextId, file: '/a/c.dart')
// .toRequest('2');
-// Response response = handler.handleRequest(request);
+// Response response = handler.handleRequest(request, NotCancelableToken());
// expect(response, isResponseFailure('2'));
// });
//
@@ -119,7 +120,7 @@
// provider.newFolder('/a/d');
// Request request =
// new ExecutionMapUriParams(contextId, file: '/a/d').toRequest('2');
-// Response response = handler.handleRequest(request);
+// Response response = handler.handleRequest(request, NotCancelableToken());
// expect(response, isResponseFailure('2'));
// });
// });
@@ -129,7 +130,7 @@
// Request request =
// new ExecutionMapUriParams(contextId, uri: 'foo:///a/b.dart')
// .toRequest('2');
-// Response response = handler.handleRequest(request);
+// Response response = handler.handleRequest(request, NotCancelableToken());
// expect(response, isResponseFailure('2'));
// });
// });
@@ -137,20 +138,20 @@
// test('invalid context id', () {
// Request request =
// new ExecutionMapUriParams('xxx', uri: '').toRequest('4');
-// Response response = handler.handleRequest(request);
+// Response response = handler.handleRequest(request, NotCancelableToken());
// expect(response, isResponseFailure('4'));
// });
//
// test('both file and uri', () {
// Request request =
// new ExecutionMapUriParams('xxx', file: '', uri: '').toRequest('5');
-// Response response = handler.handleRequest(request);
+// Response response = handler.handleRequest(request, NotCancelableToken());
// expect(response, isResponseFailure('5'));
// });
//
// test('neither file nor uri', () {
// Request request = new ExecutionMapUriParams('xxx').toRequest('6');
-// Response response = handler.handleRequest(request);
+// Response response = handler.handleRequest(request, NotCancelableToken());
// expect(response, isResponseFailure('6'));
// });
// });
@@ -237,7 +238,7 @@
void _createExecutionContext(String path) {
var request = ExecutionCreateContextParams(path).toRequest('0');
- var response = handler.handleRequest(request)!;
+ var response = handler.handleRequest(request, NotCancelableToken())!;
expect(response, isResponseSuccess('0'));
var result = ExecutionCreateContextResult.fromResponse(response);
contextId = result.id;
@@ -245,14 +246,14 @@
void _disposeExecutionContext() {
var request = ExecutionDeleteContextParams(contextId).toRequest('1');
- var response = handler.handleRequest(request);
+ var response = handler.handleRequest(request, NotCancelableToken());
expect(response, isResponseSuccess('1'));
}
ExecutionMapUriResult _mapUri({String? file, String? uri}) {
var request =
ExecutionMapUriParams(contextId, file: file, uri: uri).toRequest('2');
- var response = handler.handleRequest(request)!;
+ var response = handler.handleRequest(request, NotCancelableToken())!;
expect(response, isResponseSuccess('2'));
return ExecutionMapUriResult.fromResponse(response);
}
diff --git a/pkg/analysis_server/test/domain_server_test.dart b/pkg/analysis_server/test/domain_server_test.dart
index 2202712..b7bfaa8 100644
--- a/pkg/analysis_server/test/domain_server_test.dart
+++ b/pkg/analysis_server/test/domain_server_test.dart
@@ -9,6 +9,7 @@
import 'package:analysis_server/src/domain_server.dart';
import 'package:analysis_server/src/server/crash_reporting_attachments.dart';
import 'package:analysis_server/src/utilities/mocks.dart';
+import 'package:analysis_server/src/utilities/progress.dart';
import 'package:analyzer/file_system/memory_file_system.dart';
import 'package:analyzer/instrumentation/instrumentation.dart';
import 'package:analyzer/src/generated/sdk.dart';
@@ -38,7 +39,7 @@
group('ServerDomainHandler', () {
test('getVersion', () {
var request = ServerGetVersionParams().toRequest('0');
- var response = handler.handleRequest(request)!;
+ var response = handler.handleRequest(request, NotCancelableToken())!;
expect(
response.toJson(),
equals({
@@ -52,7 +53,7 @@
var request = Request('0', SERVER_REQUEST_SET_SUBSCRIPTIONS, {
SUBSCRIPTIONS: ['noSuchService']
});
- var response = handler.handleRequest(request);
+ var response = handler.handleRequest(request, NotCancelableToken());
expect(response, isResponseFailure('0'));
});
@@ -61,7 +62,7 @@
// send request
var request =
ServerSetSubscriptionsParams([ServerService.STATUS]).toRequest('0');
- var response = handler.handleRequest(request);
+ var response = handler.handleRequest(request, NotCancelableToken());
expect(response, isResponseSuccess('0'));
// set of services has been changed
expect(server.serverServices, contains(ServerService.STATUS));
diff --git a/pkg/analysis_server/test/edit/format_test.dart b/pkg/analysis_server/test/edit/format_test.dart
index 1990b31..e5576f7 100644
--- a/pkg/analysis_server/test/edit/format_test.dart
+++ b/pkg/analysis_server/test/edit/format_test.dart
@@ -4,6 +4,7 @@
import 'package:analysis_server/protocol/protocol_generated.dart';
import 'package:analysis_server/src/edit/edit_domain.dart';
+import 'package:analysis_server/src/utilities/progress.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -104,7 +105,7 @@
''');
return waitForTasksFinished().then((_) {
var request = EditFormatParams(testFile, 0, 3).toRequest('0');
- var response = handler.handleRequest(request);
+ var response = handler.handleRequest(request, NotCancelableToken());
expect(response, isResponseFailure('0'));
});
}
diff --git a/pkg/analysis_server/test/integration/coverage.md b/pkg/analysis_server/test/integration/coverage.md
index b91da0a..9cd7a76 100644
--- a/pkg/analysis_server/test/integration/coverage.md
+++ b/pkg/analysis_server/test/integration/coverage.md
@@ -84,6 +84,7 @@
- [ ] server.error
- [ ] server.log
- [x] server.status
+- [ ] server.cancelRequest
## analytics domain
- [x] analytics.isEnabled
diff --git a/pkg/analysis_server/test/integration/support/integration_test_methods.dart b/pkg/analysis_server/test/integration/support/integration_test_methods.dart
index aa0d470..b8704aa 100644
--- a/pkg/analysis_server/test/integration/support/integration_test_methods.dart
+++ b/pkg/analysis_server/test/integration/support/integration_test_methods.dart
@@ -64,6 +64,26 @@
return null;
}
+ /// Requests cancellation of a request sent by the client by id. This is
+ /// provided on a best-effort basis and there is no guarantee the server will
+ /// be able to cancel any specific request. The server will still always
+ /// produce a response to the request even in the case of cancellation, but
+ /// clients should discard any results of any cancelled request because they
+ /// may be incomplete or inaccurate. This request always completes without
+ /// error regardless of whether the request is successfully cancelled.
+ ///
+ /// Parameters
+ ///
+ /// id: String
+ ///
+ /// The id of the request that should be cancelled.
+ Future sendServerCancelRequest(String id) async {
+ var params = ServerCancelRequestParams(id).toJson();
+ var result = await server.send('server.cancelRequest', params);
+ outOfTestExpect(result, isNull);
+ return null;
+ }
+
/// Reports that the server is running. This notification is issued once
/// after the server has started running but before any requests are
/// processed to let the client know that it started correctly.
diff --git a/pkg/analysis_server/test/integration/support/protocol_matchers.dart b/pkg/analysis_server/test/integration/support/protocol_matchers.dart
index 70848d4..a7e358db 100644
--- a/pkg/analysis_server/test/integration/support/protocol_matchers.dart
+++ b/pkg/analysis_server/test/integration/support/protocol_matchers.dart
@@ -3014,6 +3014,17 @@
'search.results params',
{'id': isSearchId, 'results': isListOf(isSearchResult), 'isLast': isBool}));
+/// server.cancelRequest params
+///
+/// {
+/// "id": String
+/// }
+final Matcher isServerCancelRequestParams = LazyMatcher(
+ () => MatchesJsonObject('server.cancelRequest params', {'id': isString}));
+
+/// server.cancelRequest result
+final Matcher isServerCancelRequestResult = isNull;
+
/// server.connected params
///
/// {
diff --git a/pkg/analysis_server/test/socket_server_test.dart b/pkg/analysis_server/test/socket_server_test.dart
index 1c7bb82..1fbf2a5 100644
--- a/pkg/analysis_server/test/socket_server_test.dart
+++ b/pkg/analysis_server/test/socket_server_test.dart
@@ -10,6 +10,7 @@
import 'package:analysis_server/src/server/error_notifier.dart';
import 'package:analysis_server/src/socket_server.dart';
import 'package:analysis_server/src/utilities/mocks.dart';
+import 'package:analysis_server/src/utilities/progress.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/sdk.dart';
import 'package:test/test.dart';
@@ -123,7 +124,7 @@
_MockRequestHandler(this.futureException);
@override
- Response handleRequest(Request request) {
+ Response handleRequest(Request request, CancellationToken cancellationToken) {
if (futureException) {
Future(throwException);
return Response(request.id);
diff --git a/pkg/analysis_server/test/src/domain_abstract_test.dart b/pkg/analysis_server/test/src/domain_abstract_test.dart
index 496ba17..5a64d54 100644
--- a/pkg/analysis_server/test/src/domain_abstract_test.dart
+++ b/pkg/analysis_server/test/src/domain_abstract_test.dart
@@ -6,6 +6,7 @@
import 'package:analysis_server/src/domain_abstract.dart';
import 'package:analysis_server/src/plugin/plugin_manager.dart';
import 'package:analysis_server/src/protocol_server.dart' hide Element;
+import 'package:analysis_server/src/utilities/progress.dart';
import 'package:analyzer/instrumentation/service.dart';
import 'package:analyzer_plugin/protocol/protocol.dart' as plugin;
import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin;
@@ -96,7 +97,7 @@
TestAbstractRequestHandler(AnalysisServer server) : super(server);
@override
- Response handleRequest(Request request) {
+ Response handleRequest(Request request, CancellationToken cancellationToken) {
fail('Unexpected invocation of handleRequest');
}
}
diff --git a/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java b/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java
index 2108516..c5022ea 100644
--- a/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java
+++ b/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java
@@ -981,6 +981,20 @@
public void search_getTypeHierarchy(String file, int offset, boolean superOnly, GetTypeHierarchyConsumer consumer);
/**
+ * {@code server.cancelRequest}
+ *
+ * Requests cancellation of a request sent by the client by id. This is provided on a best-effort
+ * basis and there is no guarantee the server will be able to cancel any specific request. The
+ * server will still always produce a response to the request even in the case of cancellation, but
+ * clients should discard any results of any cancelled request because they may be incomplete or
+ * inaccurate. This request always completes without error regardless of whether the request is
+ * successfully cancelled.
+ *
+ * @param id The id of the request that should be cancelled.
+ */
+ public void server_cancelRequest(String id);
+
+ /**
* {@code server.getVersion}
*
* Return the version number of the analysis server.
diff --git a/pkg/analysis_server/tool/spec/spec_input.html b/pkg/analysis_server/tool/spec/spec_input.html
index d89a44b..c634b46 100644
--- a/pkg/analysis_server/tool/spec/spec_input.html
+++ b/pkg/analysis_server/tool/spec/spec_input.html
@@ -7,7 +7,7 @@
<body>
<h1>Analysis Server API Specification</h1>
<h1 style="color:#999999">Version
- <version>1.32.7</version>
+ <version>1.32.8</version>
</h1>
<p>
This document contains a specification of the API provided by the
@@ -134,6 +134,11 @@
ignoring the item or treating it with some default/fallback handling.
</p>
<h3>Changelog</h3>
+<h4>1.32.8</h4>
+<ul>
+ <li>Added <tt>server.cancelRequest</tt> to allow clients to request cancellation
+ of outstanding requests.</li>
+</ul>
<h4>1.32.7</h4>
<ul>
<li><tt>HoverInformation.elementDescription</tt> may now include linebreaks to
@@ -294,6 +299,26 @@
</field>
</params>
</request>
+ <request method="cancelRequest">
+ <p>Requests cancellation of a request sent by the client by id.
+ This is provided on a best-effort basis and there is no
+ guarantee the server will be able to cancel any specific
+ request.
+
+ The server will still always produce a response to the request
+ even in the case of cancellation, but clients should discard
+ any results of any cancelled request because they may be
+ incomplete or inaccurate.
+
+ This request always completes without error regardless of
+ whether the request is successfully cancelled.</p>
+ <params>
+ <field name="id">
+ <ref>String</ref>
+ <p>The id of the request that should be cancelled.</p>
+ </field>
+ </params>
+ </request>
<notification event="connected">
<p>
Reports that the server is running. This notification is
diff --git a/pkg/analysis_server_client/lib/src/protocol/protocol_constants.dart b/pkg/analysis_server_client/lib/src/protocol/protocol_constants.dart
index 85a4474..00b690a 100644
--- a/pkg/analysis_server_client/lib/src/protocol/protocol_constants.dart
+++ b/pkg/analysis_server_client/lib/src/protocol/protocol_constants.dart
@@ -6,7 +6,7 @@
// To regenerate the file, use the script
// "pkg/analysis_server/tool/spec/generate_files".
-const String PROTOCOL_VERSION = '1.32.7';
+const String PROTOCOL_VERSION = '1.32.8';
const String ANALYSIS_NOTIFICATION_ANALYZED_FILES = 'analysis.analyzedFiles';
const String ANALYSIS_NOTIFICATION_ANALYZED_FILES_DIRECTORIES = 'directories';
@@ -356,6 +356,8 @@
const String SERVER_NOTIFICATION_STATUS = 'server.status';
const String SERVER_NOTIFICATION_STATUS_ANALYSIS = 'analysis';
const String SERVER_NOTIFICATION_STATUS_PUB = 'pub';
+const String SERVER_REQUEST_CANCEL_REQUEST = 'server.cancelRequest';
+const String SERVER_REQUEST_CANCEL_REQUEST_ID = 'id';
const String SERVER_REQUEST_GET_VERSION = 'server.getVersion';
const String SERVER_REQUEST_SET_SUBSCRIPTIONS = 'server.setSubscriptions';
const String SERVER_REQUEST_SET_SUBSCRIPTIONS_SUBSCRIPTIONS = 'subscriptions';
diff --git a/pkg/analysis_server_client/lib/src/protocol/protocol_generated.dart b/pkg/analysis_server_client/lib/src/protocol/protocol_generated.dart
index 7bb9c83..c375b0c 100644
--- a/pkg/analysis_server_client/lib/src/protocol/protocol_generated.dart
+++ b/pkg/analysis_server_client/lib/src/protocol/protocol_generated.dart
@@ -15633,6 +15633,91 @@
);
}
+/// server.cancelRequest params
+///
+/// {
+/// "id": String
+/// }
+///
+/// Clients may not extend, implement or mix-in this class.
+class ServerCancelRequestParams implements RequestParams {
+ /// The id of the request that should be cancelled.
+ String id;
+
+ ServerCancelRequestParams(this.id);
+
+ factory ServerCancelRequestParams.fromJson(
+ JsonDecoder jsonDecoder, String jsonPath, Object? json) {
+ json ??= {};
+ if (json is Map) {
+ String id;
+ if (json.containsKey('id')) {
+ id = jsonDecoder.decodeString(jsonPath + '.id', json['id']);
+ } else {
+ throw jsonDecoder.mismatch(jsonPath, 'id');
+ }
+ return ServerCancelRequestParams(id);
+ } else {
+ throw jsonDecoder.mismatch(jsonPath, 'server.cancelRequest params', json);
+ }
+ }
+
+ factory ServerCancelRequestParams.fromRequest(Request request) {
+ return ServerCancelRequestParams.fromJson(
+ RequestDecoder(request), 'params', request.params);
+ }
+
+ @override
+ Map<String, Object> toJson() {
+ var result = <String, Object>{};
+ result['id'] = id;
+ return result;
+ }
+
+ @override
+ Request toRequest(String id) {
+ return Request(id, 'server.cancelRequest', toJson());
+ }
+
+ @override
+ String toString() => json.encode(toJson());
+
+ @override
+ bool operator ==(other) {
+ if (other is ServerCancelRequestParams) {
+ return id == other.id;
+ }
+ return false;
+ }
+
+ @override
+ int get hashCode => id.hashCode;
+}
+
+/// server.cancelRequest result
+///
+/// Clients may not extend, implement or mix-in this class.
+class ServerCancelRequestResult implements ResponseResult {
+ @override
+ Map<String, Object> toJson() => <String, Object>{};
+
+ @override
+ Response toResponse(String id) {
+ return Response(id, result: null);
+ }
+
+ @override
+ bool operator ==(other) {
+ if (other is ServerCancelRequestResult) {
+ return true;
+ }
+ return false;
+ }
+
+ @override
+ int get hashCode => 183255719;
+}
+
/// server.connected params
///
/// {
diff --git a/pkg/analyzer/test/generated/non_error_resolver_test.dart b/pkg/analyzer/test/generated/non_error_resolver_test.dart
index bf708fc..8891e87 100644
--- a/pkg/analyzer/test/generated/non_error_resolver_test.dart
+++ b/pkg/analyzer/test/generated/non_error_resolver_test.dart
@@ -1451,6 +1451,26 @@
''');
}
+ test_implicit_call_reference_in_top_level_type_inference() async {
+ // This test case is important because the variable `map` is subject to top
+ // level type inference, which means it gets resolved twice. We need to
+ // make sure that on the second resolution pass, the resolver can handle the
+ // ImplicitCallReference node
+ await assertNoErrorsInCode(r'''
+typedef Object Func(Object x);
+
+class Bar {
+ int x = 42;
+
+ Object call(Object x) {
+ return 'Bar $x';
+ }
+}
+
+var map = <String, Func>{'bar': new Bar()};
+''');
+ }
+
test_importDuplicatedLibraryName() async {
newFile("$testPackageLibPath/lib.dart", content: "library lib;");
await assertErrorsInCode(r'''
diff --git a/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_core.dart b/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_core.dart
index d2d24b8..ebb810a 100644
--- a/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_core.dart
+++ b/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_core.dart
@@ -130,6 +130,13 @@
if (builder == null) {
builder = await _createDartFileEditBuilder(path);
if (builder != null) {
+ // It's not currently supported to call this method twice concurrently
+ // for the same file as two builder may be produced because of the above
+ // `await` so detect this and throw to avoid losing edits.
+ if (_dartFileEditBuilders.containsKey(path)) {
+ throw StateError(
+ "Can't add multiple edits concurrently for the same file");
+ }
_dartFileEditBuilders[path] = builder;
}
}
diff --git a/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_dart_test.dart b/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_dart_test.dart
index 047e7a1..481147a 100644
--- a/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_dart_test.dart
+++ b/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_dart_test.dart
@@ -1868,6 +1868,42 @@
''');
}
+ Future<void> test_multipleEdits_concurrently() async {
+ var initialCode = '00';
+ var path = convertPath('/home/test/lib/test.dart');
+ newFile(path, content: initialCode);
+
+ var builder = newBuilder();
+ var future = Future.wait([
+ builder.addDartFileEdit(path, (builder) {
+ builder.addSimpleInsertion(0, '11');
+ }),
+ builder.addDartFileEdit(path, (builder) {
+ builder.addSimpleInsertion(2, '22');
+ }),
+ ]);
+
+ expect(future, throwsA(TypeMatcher<StateError>()));
+ }
+
+ Future<void> test_multipleEdits_sequentially() async {
+ var initialCode = '00';
+ var path = convertPath('/home/test/lib/test.dart');
+ newFile(path, content: initialCode);
+
+ var builder = newBuilder();
+ await builder.addDartFileEdit(path, (builder) {
+ builder.addSimpleInsertion(0, '11');
+ });
+ await builder.addDartFileEdit(path, (builder) {
+ builder.addSimpleInsertion(2, '22');
+ });
+
+ var edits = getEdits(builder);
+ var resultCode = SourceEdit.applySequence(initialCode, edits);
+ expect(resultCode, '110022');
+ }
+
Future<void> test_replaceTypeWithFuture() async {
var path = convertPath('/home/test/lib/test.dart');
addSource(path, 'String f() {}');
diff --git a/pkg/compiler/analysis_options.yaml b/pkg/compiler/analysis_options.yaml
index 2ab9f2f..1645941 100644
--- a/pkg/compiler/analysis_options.yaml
+++ b/pkg/compiler/analysis_options.yaml
@@ -5,9 +5,6 @@
analyzer:
errors:
todo: ignore
- # Allow cross-package deprecated calls
- # TODO(srawlins): clean these up and remove this "ignore."
- deprecated_member_use: ignore
# Allow deprecated calls from within the same package
deprecated_member_use_from_same_package: ignore
diff --git a/pkg/compiler/test/sourcemaps/nomapping_test.dart b/pkg/compiler/test/sourcemaps/nomapping_test.dart
index 7889b64..06cbf4f 100644
--- a/pkg/compiler/test/sourcemaps/nomapping_test.dart
+++ b/pkg/compiler/test/sourcemaps/nomapping_test.dart
@@ -31,7 +31,7 @@
} else if (arg == '--write-js') {
writeJs = true;
} else {
- int index = int.parse(arg, onError: (_) => null);
+ int index = int.tryParse(arg);
if (index != null) {
indices ??= <int>[];
if (index < 0 || index >= TESTS.length * 2) {
diff --git a/pkg/front_end/lib/src/fasta/builder/class_builder.dart b/pkg/front_end/lib/src/fasta/builder/class_builder.dart
index c8ffab5..c1a3b8a 100644
--- a/pkg/front_end/lib/src/fasta/builder/class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/class_builder.dart
@@ -23,7 +23,8 @@
TypeParameter,
getAsTypeArguments;
-import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
+import 'package:kernel/class_hierarchy.dart'
+ show ClassHierarchy, ClassHierarchyMembers;
import 'package:kernel/core_types.dart' show CoreTypes;
@@ -36,8 +37,6 @@
import 'package:kernel/src/legacy_erasure.dart';
-import 'package:kernel/src/types.dart' show Types;
-
import '../dill/dill_member_builder.dart';
import '../fasta_codes.dart';
@@ -178,7 +177,10 @@
void checkSupertypes(CoreTypes coreTypes);
- void handleSeenCovariant(Types types, Member interfaceMember, bool isSetter,
+ void handleSeenCovariant(
+ ClassHierarchyMembers memberHierarchy,
+ Member interfaceMember,
+ bool isSetter,
callback(Member interfaceMember, bool isSetter));
bool hasUserDefinedNoSuchMethod(
@@ -767,12 +769,15 @@
}
@override
- void handleSeenCovariant(Types types, Member interfaceMember, bool isSetter,
+ void handleSeenCovariant(
+ ClassHierarchyMembers memberHierarchy,
+ Member interfaceMember,
+ bool isSetter,
callback(Member interfaceMember, bool isSetter)) {
// When a parameter is covariant we have to check that we also
// override the same member in all parents.
for (Supertype supertype in interfaceMember.enclosingClass!.supers) {
- Member? member = types.hierarchy.getInterfaceMember(
+ Member? member = memberHierarchy.getInterfaceMember(
supertype.classNode, interfaceMember.name,
setter: isSetter);
if (member != null) {
diff --git a/pkg/front_end/lib/src/fasta/builder/constructor_builder.dart b/pkg/front_end/lib/src/fasta/builder/constructor_builder.dart
index 1031699..f53cbfa 100644
--- a/pkg/front_end/lib/src/fasta/builder/constructor_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/constructor_builder.dart
@@ -14,10 +14,10 @@
import '../dill/dill_member_builder.dart';
import '../kernel/body_builder.dart' show BodyBuilder;
-import '../kernel/class_hierarchy_builder.dart' show ClassMember;
import '../kernel/constructor_tearoff_lowering.dart';
import '../kernel/expression_generator_helper.dart'
show ExpressionGeneratorHelper;
+import '../kernel/hierarchy/class_member.dart' show ClassMember;
import '../kernel/utils.dart'
show isRedirectingGenerativeConstructorImplementation;
import '../kernel/kernel_helper.dart' show SynthesizedFunctionNode;
diff --git a/pkg/front_end/lib/src/fasta/builder/factory_builder.dart b/pkg/front_end/lib/src/fasta/builder/factory_builder.dart
index 5db68f5..86c7b96 100644
--- a/pkg/front_end/lib/src/fasta/builder/factory_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/factory_builder.dart
@@ -8,9 +8,9 @@
import '../dill/dill_member_builder.dart';
-import '../kernel/class_hierarchy_builder.dart';
import '../kernel/constructor_tearoff_lowering.dart';
import '../kernel/forest.dart';
+import '../kernel/hierarchy/class_member.dart';
import '../kernel/internal_ast.dart';
import '../kernel/kernel_helper.dart';
import '../kernel/redirecting_factory_body.dart'
diff --git a/pkg/front_end/lib/src/fasta/builder/field_builder.dart b/pkg/front_end/lib/src/fasta/builder/field_builder.dart
index 229ddf9..8acdc68 100644
--- a/pkg/front_end/lib/src/fasta/builder/field_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/field_builder.dart
@@ -16,7 +16,8 @@
import '../fasta_codes.dart' show messageInternalProblemAlreadyInitialized;
import '../kernel/body_builder.dart' show BodyBuilder;
-import '../kernel/class_hierarchy_builder.dart';
+import '../kernel/hierarchy/class_member.dart';
+import '../kernel/hierarchy/members_builder.dart';
import '../kernel/implicit_field_type.dart';
import '../kernel/kernel_helper.dart';
import '../kernel/late_lowering.dart' as late_lowering;
@@ -311,10 +312,10 @@
_overrideDependencies!.addAll(overriddenMembers);
}
- void _ensureType(ClassHierarchyBuilder hierarchy) {
+ void _ensureType(ClassMembersBuilder membersBuilder) {
if (_typeEnsured) return;
if (_overrideDependencies != null) {
- hierarchy.inferFieldType(this, _overrideDependencies!);
+ membersBuilder.inferFieldType(this, _overrideDependencies!);
_overrideDependencies = null;
} else {
inferType();
@@ -765,8 +766,8 @@
: assert(forSetter != null);
@override
- void inferType(ClassHierarchyBuilder hierarchy) {
- memberBuilder._ensureType(hierarchy);
+ void inferType(ClassMembersBuilder membersBuilder) {
+ memberBuilder._ensureType(membersBuilder);
}
@override
@@ -775,15 +776,16 @@
}
@override
- Member getMember(ClassHierarchyBuilder hierarchy) {
- memberBuilder._ensureType(hierarchy);
+ Member getMember(ClassMembersBuilder membersBuilder) {
+ memberBuilder._ensureType(membersBuilder);
return memberBuilder.field;
}
@override
- Covariance getCovariance(ClassHierarchyBuilder hierarchy) {
+ Covariance getCovariance(ClassMembersBuilder membersBuilder) {
return _covariance ??= forSetter
- ? new Covariance.fromMember(getMember(hierarchy), forSetter: forSetter)
+ ? new Covariance.fromMember(getMember(membersBuilder),
+ forSetter: forSetter)
: const Covariance.empty();
}
@@ -1433,20 +1435,20 @@
: assert(isInternalImplementation != null);
@override
- Member getMember(ClassHierarchyBuilder hierarchy) {
- fieldBuilder._ensureType(hierarchy);
+ Member getMember(ClassMembersBuilder membersBuilder) {
+ fieldBuilder._ensureType(membersBuilder);
return _member;
}
@override
- Covariance getCovariance(ClassHierarchyBuilder hierarchy) {
- return _covariance ??=
- new Covariance.fromMember(getMember(hierarchy), forSetter: forSetter);
+ Covariance getCovariance(ClassMembersBuilder membersBuilder) {
+ return _covariance ??= new Covariance.fromMember(getMember(membersBuilder),
+ forSetter: forSetter);
}
@override
- void inferType(ClassHierarchyBuilder hierarchy) {
- fieldBuilder._ensureType(hierarchy);
+ void inferType(ClassMembersBuilder membersBuilder) {
+ fieldBuilder._ensureType(membersBuilder);
}
@override
diff --git a/pkg/front_end/lib/src/fasta/builder/member_builder.dart b/pkg/front_end/lib/src/fasta/builder/member_builder.dart
index 9035466..5fc860b 100644
--- a/pkg/front_end/lib/src/fasta/builder/member_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/member_builder.dart
@@ -9,7 +9,7 @@
import '../../base/common.dart';
-import '../kernel/class_hierarchy_builder.dart';
+import '../kernel/hierarchy/class_member.dart';
import '../kernel/kernel_helper.dart';
import '../modifier.dart';
import '../problems.dart' show unsupported;
diff --git a/pkg/front_end/lib/src/fasta/builder/procedure_builder.dart b/pkg/front_end/lib/src/fasta/builder/procedure_builder.dart
index a1118c6..9439453 100644
--- a/pkg/front_end/lib/src/fasta/builder/procedure_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/procedure_builder.dart
@@ -5,7 +5,8 @@
import 'package:kernel/ast.dart';
import 'package:kernel/type_algebra.dart';
-import '../kernel/class_hierarchy_builder.dart';
+import '../kernel/hierarchy/class_member.dart';
+import '../kernel/hierarchy/members_builder.dart';
import '../kernel/member_covariance.dart';
import '../source/name_scheme.dart';
@@ -197,15 +198,15 @@
_overrideDependencies!.addAll(overriddenMembers);
}
- void _ensureTypes(ClassHierarchyBuilder hierarchy) {
+ void _ensureTypes(ClassMembersBuilder membersBuilder) {
if (_typeEnsured) return;
if (_overrideDependencies != null) {
if (isGetter) {
- hierarchy.inferGetterType(this, _overrideDependencies!);
+ membersBuilder.inferGetterType(this, _overrideDependencies!);
} else if (isSetter) {
- hierarchy.inferSetterType(this, _overrideDependencies!);
+ membersBuilder.inferSetterType(this, _overrideDependencies!);
} else {
- hierarchy.inferMethodType(this, _overrideDependencies!);
+ membersBuilder.inferMethodType(this, _overrideDependencies!);
}
_overrideDependencies = null;
}
@@ -527,8 +528,8 @@
bool get isSourceDeclaration => true;
@override
- void inferType(ClassHierarchyBuilder hierarchy) {
- memberBuilder._ensureTypes(hierarchy);
+ void inferType(ClassMembersBuilder membersBuilder) {
+ memberBuilder._ensureTypes(membersBuilder);
}
@override
@@ -537,15 +538,15 @@
}
@override
- Member getMember(ClassHierarchyBuilder hierarchy) {
- memberBuilder._ensureTypes(hierarchy);
+ Member getMember(ClassMembersBuilder membersBuilder) {
+ memberBuilder._ensureTypes(membersBuilder);
return memberBuilder.member;
}
@override
- Covariance getCovariance(ClassHierarchyBuilder hierarchy) {
- return _covariance ??=
- new Covariance.fromMember(getMember(hierarchy), forSetter: forSetter);
+ Covariance getCovariance(ClassMembersBuilder membersBuilder) {
+ return _covariance ??= new Covariance.fromMember(getMember(membersBuilder),
+ forSetter: forSetter);
}
@override
diff --git a/pkg/front_end/lib/src/fasta/dill/dill_member_builder.dart b/pkg/front_end/lib/src/fasta/dill/dill_member_builder.dart
index 4917953..d800f03 100644
--- a/pkg/front_end/lib/src/fasta/dill/dill_member_builder.dart
+++ b/pkg/front_end/lib/src/fasta/dill/dill_member_builder.dart
@@ -11,8 +11,8 @@
import '../builder/member_builder.dart';
import '../builder/library_builder.dart';
-import '../kernel/class_hierarchy_builder.dart'
- show ClassHierarchyBuilder, ClassMember;
+import '../kernel/hierarchy/class_member.dart' show ClassMember;
+import '../kernel/hierarchy/members_builder.dart' show ClassMembersBuilder;
import '../kernel/member_covariance.dart';
import '../kernel/utils.dart'
show isRedirectingGenerativeConstructorImplementation;
@@ -282,16 +282,16 @@
}
@override
- Member getMember(ClassHierarchyBuilder hierarchy) => memberBuilder.member;
+ Member getMember(ClassMembersBuilder membersBuilder) => memberBuilder.member;
@override
- Covariance getCovariance(ClassHierarchyBuilder hierarchy) {
+ Covariance getCovariance(ClassMembersBuilder membersBuilder) {
return _covariance ??=
new Covariance.fromMember(memberBuilder.member, forSetter: forSetter);
}
@override
- void inferType(ClassHierarchyBuilder hierarchy) {
+ void inferType(ClassMembersBuilder hierarchy) {
// Do nothing; this is only for source members.
}
diff --git a/pkg/front_end/lib/src/fasta/incremental_compiler.dart b/pkg/front_end/lib/src/fasta/incremental_compiler.dart
index 03b4da8..c693edd 100644
--- a/pkg/front_end/lib/src/fasta/incremental_compiler.dart
+++ b/pkg/front_end/lib/src/fasta/incremental_compiler.dart
@@ -122,7 +122,7 @@
import 'hybrid_file_system.dart' show HybridFileSystem;
-import 'kernel/class_hierarchy_builder.dart' show ClassHierarchyBuilder;
+import 'kernel/hierarchy/hierarchy_builder.dart' show ClassHierarchyBuilder;
import 'kernel/internal_ast.dart' show VariableDeclarationImpl;
@@ -527,7 +527,7 @@
}
}
nextGoodKernelTarget.loader.buildersCreatedWithReferences.clear();
- nextGoodKernelTarget.loader.builderHierarchy.clear();
+ nextGoodKernelTarget.loader.hierarchyBuilder.clear();
nextGoodKernelTarget.loader.referenceFromIndex = null;
convertedLibraries = null;
experimentalInvalidation = null;
@@ -703,7 +703,7 @@
}
updateNeededDillLibrariesWithHierarchy(
- neededDillLibraries, hierarchy, target.loader.builderHierarchy);
+ neededDillLibraries, hierarchy, target.loader.hierarchyBuilder);
return neededDillLibraries;
}
diff --git a/pkg/front_end/lib/src/fasta/kernel/combined_member_signature.dart b/pkg/front_end/lib/src/fasta/kernel/combined_member_signature.dart
index abff877..ae2efed 100644
--- a/pkg/front_end/lib/src/fasta/kernel/combined_member_signature.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/combined_member_signature.dart
@@ -20,7 +20,9 @@
import '../source/source_class_builder.dart';
-import 'class_hierarchy_builder.dart';
+import 'hierarchy/class_member.dart';
+import 'hierarchy/hierarchy_builder.dart';
+import 'hierarchy/members_builder.dart';
import 'member_covariance.dart';
/// Class used for computing and inspecting the combined member signature for
@@ -736,9 +738,11 @@
/// a set of overridden/inherited [ClassMember]s.
class CombinedClassMemberSignature
extends CombinedMemberSignatureBase<ClassMember> {
- /// The class hierarchy builder used for building this class.
+ /// The class members builder used for building this class.
+ final ClassMembersBuilder membersBuilder;
+
@override
- final ClassHierarchyBuilder hierarchy;
+ ClassHierarchyBuilder get hierarchy => membersBuilder.hierarchyBuilder;
/// The list of the members inherited into or overridden in [classBuilder].
@override
@@ -746,7 +750,7 @@
/// Creates a [CombinedClassMemberSignature] whose canonical member is already
/// defined.
- CombinedClassMemberSignature.internal(this.hierarchy,
+ CombinedClassMemberSignature.internal(this.membersBuilder,
SourceClassBuilder classBuilder, int canonicalMemberIndex, this.members,
{required bool forSetter})
: super.internal(classBuilder, canonicalMemberIndex, forSetter);
@@ -758,7 +762,7 @@
/// compute the most specific member type. Otherwise covariance of the getter
/// types or function types is used.
CombinedClassMemberSignature(
- this.hierarchy, SourceClassBuilder classBuilder, this.members,
+ this.membersBuilder, SourceClassBuilder classBuilder, this.members,
{required bool forSetter})
: super(classBuilder, forSetter: forSetter);
@@ -771,7 +775,7 @@
@override
Member _getMember(int index) {
ClassMember candidate = members[index];
- Member target = candidate.getMember(hierarchy);
+ Member target = candidate.getMember(membersBuilder);
// ignore: unnecessary_null_comparison
assert(target != null,
"No member computed for ${candidate} (${candidate.runtimeType})");
@@ -781,7 +785,7 @@
@override
Covariance _getMemberCovariance(int index) {
ClassMember candidate = members[index];
- Covariance covariance = candidate.getCovariance(hierarchy);
+ Covariance covariance = candidate.getCovariance(membersBuilder);
// ignore: unnecessary_null_comparison
assert(covariance != null,
"No covariance computed for ${candidate} (${candidate.runtimeType})");
diff --git a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
index bc2af8b..cf785bd 100644
--- a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
@@ -2464,9 +2464,8 @@
functionEnvironment: receiver.environment);
} else if (receiver is InstanceConstant) {
final Class instanceClass = receiver.classNode;
- assert(typeEnvironment.hierarchy is ClassHierarchy);
- final Member member = (typeEnvironment.hierarchy as ClassHierarchy)
- .getDispatchTarget(instanceClass, name)!;
+ final Member member =
+ typeEnvironment.hierarchy.getDispatchTarget(instanceClass, name)!;
final FunctionNode? function = member.function;
// TODO(kallentu): Implement [Object] class methods which have backend
diff --git a/pkg/front_end/lib/src/fasta/kernel/forwarding_node.dart b/pkg/front_end/lib/src/fasta/kernel/forwarding_node.dart
index f05f378..b5b8b97 100644
--- a/pkg/front_end/lib/src/fasta/kernel/forwarding_node.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/forwarding_node.dart
@@ -12,7 +12,7 @@
import "../problems.dart" show unhandled;
-import 'class_hierarchy_builder.dart';
+import 'hierarchy/class_member.dart';
import 'combined_member_signature.dart';
class ForwardingNode {
@@ -49,7 +49,7 @@
SourceClassBuilder classBuilder = _combinedMemberSignature.classBuilder;
ClassMember canonicalMember = _combinedMemberSignature.canonicalMember!;
Member interfaceMember =
- canonicalMember.getMember(_combinedMemberSignature.hierarchy);
+ canonicalMember.getMember(_combinedMemberSignature.membersBuilder);
bool needMixinStub =
classBuilder.isMixinApplication && _mixedInMember != null;
@@ -83,7 +83,8 @@
needsTypeOrCovarianceUpdate) ||
needMixinStub;
bool needsSuperImpl = _superClassMember != null &&
- _superClassMember!.getCovariance(_combinedMemberSignature.hierarchy) !=
+ _superClassMember!
+ .getCovariance(_combinedMemberSignature.membersBuilder) !=
_combinedMemberSignature.combinedMemberSignatureCovariance;
if (stubNeeded) {
Procedure stub = _combinedMemberSignature.createMemberFromSignature(
@@ -114,8 +115,8 @@
}
} else {
stubKind = ProcedureStubKind.AbstractMixinStub;
- finalTarget =
- _mixedInMember!.getMember(_combinedMemberSignature.hierarchy);
+ finalTarget = _mixedInMember!
+ .getMember(_combinedMemberSignature.membersBuilder);
}
stub.stubKind = stubKind;
@@ -159,7 +160,7 @@
}
Procedure procedure = function.parent as Procedure;
Member superTarget =
- _superClassMember!.getMember(_combinedMemberSignature.hierarchy);
+ _superClassMember!.getMember(_combinedMemberSignature.membersBuilder);
if (superTarget is Procedure && superTarget.isForwardingStub) {
Procedure superProcedure = superTarget;
superTarget = superProcedure.concreteForwardingStubTarget!;
diff --git a/pkg/front_end/lib/src/fasta/kernel/hierarchy/class_member.dart b/pkg/front_end/lib/src/fasta/kernel/hierarchy/class_member.dart
new file mode 100644
index 0000000..f45ba32
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/kernel/hierarchy/class_member.dart
@@ -0,0 +1,609 @@
+// 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.
+
+library fasta.class_hierarchy_builder;
+
+import 'package:kernel/ast.dart';
+
+import '../../builder/class_builder.dart';
+import '../../messages.dart'
+ show
+ LocatedMessage,
+ messageDeclaredMemberConflictsWithOverriddenMembersCause,
+ templateCombinedMemberSignatureFailed;
+import '../../source/source_class_builder.dart';
+import '../../source/source_library_builder.dart' show SourceLibraryBuilder;
+import '../combined_member_signature.dart';
+import '../forwarding_node.dart' show ForwardingNode;
+import '../member_covariance.dart';
+import 'members_builder.dart';
+
+abstract class ClassMember {
+ Name get name;
+ bool get isStatic;
+ bool get isField;
+ bool get isAssignable;
+ bool get isSetter;
+ bool get isGetter;
+ bool get isFinal;
+ bool get isConst;
+ bool get forSetter;
+
+ /// Returns `true` if this member corresponds to a declaration in the source
+ /// code.
+ bool get isSourceDeclaration;
+
+ /// Returns `true` if this member is a field, getter or setter.
+ bool get isProperty;
+
+ /// Computes the [Member] node resulting from this class member.
+ Member getMember(ClassMembersBuilder membersBuilder);
+
+ /// Returns the member [Covariance] for this class member.
+ Covariance getCovariance(ClassMembersBuilder membersBuilder);
+
+ bool get isDuplicate;
+ String get fullName;
+ String get fullNameForErrors;
+ ClassBuilder get classBuilder;
+
+ /// Returns `true` if this class member is declared in Object from dart:core.
+ bool isObjectMember(ClassBuilder objectClass);
+ Uri get fileUri;
+ int get charOffset;
+
+ /// Returns `true` if this class member is an interface member.
+ bool get isAbstract;
+
+ /// Returns `true` if this member doesn't corresponds to a declaration in the
+ /// source code.
+ bool get isSynthesized;
+
+ // If `true` this member is not part of the interface but only part of the
+ // class members.
+ //
+ // This is `true` for instance for synthesized fields added for the late
+ // lowering.
+ bool get isInternalImplementation;
+
+ /// Returns `true` if this member is composed from a list of class members
+ /// accessible through [declarations].
+ bool get hasDeclarations;
+
+ /// If [hasDeclaration] is `true`, this returns the list of class members
+ /// from which this class member is composed.
+ ///
+ /// This is used in [unfoldDeclarations] to retrieve all underlying member
+ /// source declarations, and in [toSet] to retrieve all members used for
+ /// this class member wrt. certain level of the hierarchy.
+ /// TODO(johnniwinther): Can the use of [toSet] be replaced with a direct
+ /// use of [declarations]?
+ List<ClassMember> get declarations;
+
+ /// The interface member corresponding to this member.
+ ///
+ /// If this member is declared on the source, the interface member is
+ /// the member itself. For instance
+ ///
+ /// abstract class Class {
+ /// void concreteMethod() {}
+ /// void abstractMethod();
+ /// }
+ ///
+ /// the interface members for `concreteMethod` and `abstractMethod` are the
+ /// members themselves.
+ ///
+ /// If this member is a synthesized interface member, the
+ /// interface member is the member itself. For instance
+ ///
+ /// abstract class Interface1 {
+ /// void method() {}
+ /// }
+ /// abstract class Interface2 {
+ /// void method() {}
+ /// }
+ /// abstract class Class implements Interface1, Interface2 {}
+ ///
+ /// the interface member for `method` in `Class` is the synthesized interface
+ /// member created for the implemented members `Interface1.method` and
+ /// `Interface2.method`.
+ ///
+ /// If this member is a concrete member that implements an interface member,
+ /// the interface member is the implemented interface member. For instance
+ ///
+ /// class Super {
+ /// void method() {}
+ /// }
+ /// class Interface {
+ /// void method() {}
+ /// }
+ /// class Class extends Super implements Interface {}
+ ///
+ /// the interface member for `Super.method` implementing `method` in `Class`
+ /// is the synthesized interface member created for the implemented members
+ /// `Super.method` and `Interface.method`.
+ ClassMember get interfaceMember;
+
+ void inferType(ClassMembersBuilder membersBuilder);
+ void registerOverrideDependency(Set<ClassMember> overriddenMembers);
+
+ /// Returns `true` if this has the same underlying declaration as [other].
+ ///
+ /// This is used for avoiding unnecessary checks and can this trivially
+ /// return `false`.
+ bool isSameDeclaration(ClassMember other);
+}
+
+abstract class SynthesizedMember extends ClassMember {
+ @override
+ final ClassBuilder classBuilder;
+
+ @override
+ final Name name;
+
+ @override
+ final bool forSetter;
+
+ @override
+ final bool isProperty;
+
+ SynthesizedMember(this.classBuilder, this.name,
+ {required this.forSetter, required this.isProperty})
+ // ignore: unnecessary_null_comparison
+ : assert(forSetter != null),
+ // ignore: unnecessary_null_comparison
+ assert(isProperty != null);
+
+ @override
+ List<ClassMember> get declarations => throw new UnimplementedError();
+
+ @override
+ void inferType(ClassMembersBuilder membersBuilder) {}
+
+ @override
+ bool get isAssignable => throw new UnimplementedError();
+
+ @override
+ bool get isConst => throw new UnimplementedError();
+
+ @override
+ bool get isDuplicate => false;
+
+ @override
+ bool get isField => throw new UnimplementedError();
+
+ @override
+ bool get isFinal => throw new UnimplementedError();
+
+ @override
+ bool get isGetter => throw new UnimplementedError();
+
+ @override
+ bool get isInternalImplementation => false;
+
+ @override
+ bool get isSetter => forSetter;
+
+ @override
+ bool get isSourceDeclaration => false;
+
+ @override
+ bool get isStatic => false;
+
+ @override
+ bool get isSynthesized => true;
+
+ @override
+ void registerOverrideDependency(Set<ClassMember> overriddenMembers) {}
+}
+
+/// Class member for a set of interface members.
+///
+/// This is used to compute combined member signature of a set of interface
+/// members inherited into the same class, and to insert forwarding stubs,
+/// mixin stubs, and member signatures where needed.
+class SynthesizedInterfaceMember extends SynthesizedMember {
+ @override
+ final List<ClassMember> declarations;
+
+ /// The concrete member in the super class overridden by [declarations], if
+ /// any.
+ ///
+ /// This is used to as the target when creating concrete forwarding and mixin
+ /// stub. For instance:
+ ///
+ /// class Super {
+ /// method(int i) {}
+ /// }
+ /// class Interface {
+ /// method(covariant int i) {}
+ /// }
+ /// class Class extends Super implements Interface {
+ /// // Concrete forwarding stub calling [_superClassMember]:
+ /// method(covariant int i) => super.method(i);
+ ///
+ final ClassMember? _superClassMember;
+
+ /// The canonical member of the combined member signature if it is known by
+ /// construction. The canonical member defines the type of combined member
+ /// signature.
+ ///
+ /// This is used when a declared member is part of a set of implemented
+ /// members. For instance
+ ///
+ /// class Super {
+ /// method(int i) {}
+ /// }
+ /// class Interface {
+ /// method(covariant num i) {}
+ /// }
+ /// class Class implements Interface {
+ /// // This member is updated to be a concrete forwarding stub with an
+ /// // covariant parameter but with its declared parameter type:
+ /// // method(covariant int i) => super.method(i);
+ /// method(int i);
+ /// }
+ final ClassMember? _canonicalMember;
+
+ /// The member in [declarations] that is mixed in, if any.
+ ///
+ /// This is used to create mixin stubs. If the mixed in member is abstract,
+ /// an abstract mixin stub is created:
+ ///
+ /// class Super {
+ /// void method() {}
+ /// }
+ /// class Mixin {
+ /// void method();
+ /// }
+ /// // Abstract mixin stub with `Mixin.method` as target inserted:
+ /// // void method();
+ /// class Class = Super with Mixin;
+ ///
+ /// If the mixed in member is concrete, a concrete mixin member is created:
+ ///
+ /// class Super {
+ /// void method() {}
+ /// }
+ /// class Mixin {
+ /// void method() {}
+ /// }
+ /// // Concrete mixin stub with `Mixin.method` as target inserted:
+ /// // void method() => super.method();
+ /// class Class = Super with Mixin;
+ ///
+ /// If a forwarding stub is needed, the created stub will be a possibly
+ /// concrete forwarding stub:
+ ///
+ /// class Super {
+ /// void method(int i) {}
+ /// }
+ /// class Interface {
+ /// void method(covariant num i) {}
+ /// }
+ /// class Mixin {
+ /// void method(int i);
+ /// }
+ /// // Concrete forwarding stub with `Super.method` as target inserted:
+ /// // void method(covariant int i) => super.method(i);
+ /// class Class = Super with Mixin implements Interface;
+ ///
+ final ClassMember? _mixedInMember;
+
+ /// If `true`, a stub should be inserted, if needed.
+ final bool _shouldModifyKernel;
+
+ Member? _member;
+ Covariance? _covariance;
+
+ SynthesizedInterfaceMember(
+ ClassBuilder classBuilder, Name name, this.declarations,
+ {ClassMember? superClassMember,
+ ClassMember? canonicalMember,
+ ClassMember? mixedInMember,
+ required bool isProperty,
+ required bool forSetter,
+ required bool shouldModifyKernel})
+ : this._superClassMember = superClassMember,
+ this._canonicalMember = canonicalMember,
+ this._mixedInMember = mixedInMember,
+ this._shouldModifyKernel = shouldModifyKernel,
+ super(classBuilder, name, isProperty: isProperty, forSetter: forSetter);
+
+ @override
+ bool get hasDeclarations => true;
+
+ void _ensureMemberAndCovariance(ClassMembersBuilder membersBuilder) {
+ if (_member != null) {
+ return;
+ }
+ if (classBuilder.library is! SourceLibraryBuilder) {
+ if (_canonicalMember != null) {
+ _member = _canonicalMember!.getMember(membersBuilder);
+ _covariance = _canonicalMember!.getCovariance(membersBuilder);
+ } else {
+ _member = declarations.first.getMember(membersBuilder);
+ _covariance = declarations.first.getCovariance(membersBuilder);
+ }
+ return;
+ }
+ CombinedClassMemberSignature combinedMemberSignature;
+ if (_canonicalMember != null) {
+ combinedMemberSignature = new CombinedClassMemberSignature.internal(
+ membersBuilder,
+ classBuilder as SourceClassBuilder,
+ declarations.indexOf(_canonicalMember!),
+ declarations,
+ forSetter: isSetter);
+ } else {
+ combinedMemberSignature = new CombinedClassMemberSignature(
+ membersBuilder, classBuilder as SourceClassBuilder, declarations,
+ forSetter: isSetter);
+
+ if (combinedMemberSignature.canonicalMember == null) {
+ String name = classBuilder.fullNameForErrors;
+ int length = classBuilder.isAnonymousMixinApplication ? 1 : name.length;
+ List<LocatedMessage> context = declarations.map((ClassMember d) {
+ return messageDeclaredMemberConflictsWithOverriddenMembersCause
+ .withLocation(
+ d.fileUri, d.charOffset, d.fullNameForErrors.length);
+ }).toList();
+
+ classBuilder.addProblem(
+ templateCombinedMemberSignatureFailed.withArguments(
+ classBuilder.fullNameForErrors,
+ declarations.first.fullNameForErrors),
+ classBuilder.charOffset,
+ length,
+ context: context);
+ // TODO(johnniwinther): Maybe we should have an invalid marker to avoid
+ // cascading errors.
+ _member = declarations.first.getMember(membersBuilder);
+ _covariance = declarations.first.getCovariance(membersBuilder);
+ return;
+ }
+ }
+
+ if (_shouldModifyKernel) {
+ ProcedureKind kind = ProcedureKind.Method;
+ Member canonicalMember =
+ combinedMemberSignature.canonicalMember!.getMember(membersBuilder);
+ if (combinedMemberSignature.canonicalMember!.isProperty) {
+ kind = isSetter ? ProcedureKind.Setter : ProcedureKind.Getter;
+ } else if (canonicalMember is Procedure &&
+ canonicalMember.kind == ProcedureKind.Operator) {
+ kind = ProcedureKind.Operator;
+ }
+
+ Procedure? stub = new ForwardingNode(
+ combinedMemberSignature, kind, _superClassMember, _mixedInMember)
+ .finalize();
+ if (stub != null) {
+ assert(classBuilder.cls == stub.enclosingClass);
+ assert(stub != canonicalMember);
+ classBuilder.cls.addProcedure(stub);
+ SourceLibraryBuilder library =
+ classBuilder.library as SourceLibraryBuilder;
+ if (canonicalMember is Procedure) {
+ library.forwardersOrigins
+ ..add(stub)
+ ..add(canonicalMember);
+ }
+ _member = stub;
+ _covariance = combinedMemberSignature.combinedMemberSignatureCovariance;
+ assert(
+ _covariance ==
+ new Covariance.fromMember(_member!, forSetter: forSetter),
+ "Unexpected covariance for combined members signature "
+ "$_member. Found $_covariance, expected "
+ "${new Covariance.fromMember(_member!, forSetter: forSetter)}.");
+ return;
+ }
+ }
+
+ _member =
+ combinedMemberSignature.canonicalMember!.getMember(membersBuilder);
+ _covariance = combinedMemberSignature.combinedMemberSignatureCovariance;
+ }
+
+ @override
+ Member getMember(ClassMembersBuilder membersBuilder) {
+ _ensureMemberAndCovariance(membersBuilder);
+ return _member!;
+ }
+
+ @override
+ Covariance getCovariance(ClassMembersBuilder membersBuilder) {
+ _ensureMemberAndCovariance(membersBuilder);
+ return _covariance!;
+ }
+
+ @override
+ ClassMember get interfaceMember => this;
+
+ @override
+ bool isObjectMember(ClassBuilder objectClass) {
+ return false;
+ }
+
+ @override
+ bool isSameDeclaration(ClassMember other) {
+ // TODO(johnniwinther): Optimize this.
+ return false;
+ }
+
+ @override
+ int get charOffset => declarations.first.charOffset;
+
+ @override
+ Uri get fileUri => declarations.first.fileUri;
+
+ @override
+ bool get isAbstract => true;
+
+ @override
+ String get fullNameForErrors =>
+ declarations.map((ClassMember m) => m.fullName).join("%");
+
+ @override
+ String get fullName {
+ String suffix = isSetter ? "=" : "";
+ return "${fullNameForErrors}$suffix";
+ }
+
+ @override
+ String toString() => 'SynthesizedInterfaceMember($classBuilder,$name,'
+ '$declarations,forSetter=$forSetter)';
+}
+
+/// Class member for an inherited concrete member that implements an interface
+/// member.
+///
+/// This is used to ensure that both the inherited concrete member and the
+/// interface member is taken into account when computing the resulting [Member]
+/// node.
+///
+/// This is needed because an interface member, though initially abstract, can
+/// result in a concrete stub that overrides the concrete member. For instance
+///
+/// class Super {
+/// method(int i) {}
+/// }
+/// class Interface {
+/// method(covariant int i) {}
+/// }
+/// class Class extends Super implements Interface {
+/// // A concrete forwarding stub is inserted:
+/// method(covariant int i) => super.method(i);
+/// }
+/// class Sub extends Class implements Interface {
+/// // No forwarding stub should be inserted since `Class.method` is
+/// // adequate.
+/// }
+///
+///
+/// Here the create stub `Class.method` overrides `Super.method` and should
+/// be used to determine whether to insert a forwarding stub in subclasses.
+class InheritedClassMemberImplementsInterface extends SynthesizedMember {
+ final ClassMember inheritedClassMember;
+ final ClassMember implementedInterfaceMember;
+
+ Member? _member;
+ Covariance? _covariance;
+
+ InheritedClassMemberImplementsInterface(ClassBuilder classBuilder, Name name,
+ {required this.inheritedClassMember,
+ required this.implementedInterfaceMember,
+ required bool isProperty,
+ required bool forSetter})
+ // ignore: unnecessary_null_comparison
+ : assert(inheritedClassMember != null),
+ // ignore: unnecessary_null_comparison
+ assert(implementedInterfaceMember != null),
+ super(classBuilder, name, isProperty: isProperty, forSetter: forSetter);
+
+ void _ensureMemberAndCovariance(ClassMembersBuilder membersBuilder) {
+ if (_member == null) {
+ Member classMember = inheritedClassMember.getMember(membersBuilder);
+ Member interfaceMember =
+ implementedInterfaceMember.getMember(membersBuilder);
+ if (!interfaceMember.isAbstract &&
+ interfaceMember.enclosingClass == classBuilder.cls) {
+ /// The interface member resulted in a concrete stub being inserted.
+ /// For instance for `method1` but _not_ for `method2` here:
+ ///
+ /// class Super {
+ /// method1(int i) {}
+ /// method2(covariant int i) {}
+ /// }
+ /// class Interface {
+ /// method1(covariant int i) {}
+ /// method2(int i) {}
+ /// }
+ /// class Class extends Super implements Interface {
+ /// // A concrete forwarding stub is inserted for `method1` since
+ /// // the parameter on `Super.method1` is _not_ marked as
+ /// // covariant:
+ /// method1(covariant int i) => super.method(i);
+ /// // No concrete forwarding stub is inserted for `method2` since
+ /// // the parameter on `Super.method2` is already marked as
+ /// // covariant.
+ /// }
+ ///
+ /// The inserted stub should be used as the resulting member.
+ _member = interfaceMember;
+ _covariance = implementedInterfaceMember.getCovariance(membersBuilder);
+ } else {
+ /// The interface member did not result in an inserted stub or the
+ /// inserted stub was abstract. For instance:
+ ///
+ /// // Opt-in:
+ /// class Super {
+ /// method(int? i) {}
+ /// }
+ /// // Opt-out:
+ /// class Class extends Super {
+ /// // An abstract member signature stub is inserted:
+ /// method(int* i);
+ /// }
+ ///
+ /// The inserted stub should _not_ be used as the resulting member
+ /// since it is abstract and therefore not a class member.
+ _member = classMember;
+ _covariance = inheritedClassMember.getCovariance(membersBuilder);
+ }
+ }
+ }
+
+ @override
+ Member getMember(ClassMembersBuilder membersBuilder) {
+ _ensureMemberAndCovariance(membersBuilder);
+ return _member!;
+ }
+
+ @override
+ Covariance getCovariance(ClassMembersBuilder membersBuilder) {
+ _ensureMemberAndCovariance(membersBuilder);
+ return _covariance!;
+ }
+
+ @override
+ ClassMember get interfaceMember => implementedInterfaceMember;
+
+ @override
+ bool isObjectMember(ClassBuilder objectClass) {
+ return inheritedClassMember.isObjectMember(objectClass);
+ }
+
+ @override
+ bool isSameDeclaration(ClassMember other) {
+ // TODO(johnniwinther): Optimize this.
+ return false;
+ }
+
+ @override
+ int get charOffset => inheritedClassMember.charOffset;
+
+ @override
+ Uri get fileUri => inheritedClassMember.fileUri;
+
+ @override
+ bool get hasDeclarations => false;
+
+ @override
+ bool get isAbstract => false;
+
+ @override
+ String get fullNameForErrors => inheritedClassMember.fullNameForErrors;
+
+ @override
+ String get fullName => inheritedClassMember.fullName;
+
+ @override
+ String toString() =>
+ 'InheritedClassMemberImplementsInterface($classBuilder,$name,'
+ 'inheritedClassMember=$inheritedClassMember,'
+ 'implementedInterfaceMember=$implementedInterfaceMember,'
+ 'forSetter=$forSetter)';
+}
diff --git a/pkg/front_end/lib/src/fasta/kernel/hierarchy/delayed.dart b/pkg/front_end/lib/src/fasta/kernel/hierarchy/delayed.dart
new file mode 100644
index 0000000..61cd149
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/kernel/hierarchy/delayed.dart
@@ -0,0 +1,122 @@
+// 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.
+
+library fasta.class_hierarchy_builder;
+
+import 'package:kernel/ast.dart';
+import 'package:kernel/src/legacy_erasure.dart';
+
+import '../../source/source_class_builder.dart';
+import 'class_member.dart';
+import 'members_builder.dart';
+import 'members_node.dart';
+
+abstract class DelayedCheck {
+ void check(ClassMembersBuilder membersBuilder);
+}
+
+class DelayedOverrideCheck implements DelayedCheck {
+ final SourceClassBuilder _classBuilder;
+ final ClassMember _declaredMember;
+ final Set<ClassMember> _overriddenMembers;
+
+ DelayedOverrideCheck(
+ this._classBuilder, this._declaredMember, this._overriddenMembers);
+
+ @override
+ void check(ClassMembersBuilder membersBuilder) {
+ Member declaredMember = _declaredMember.getMember(membersBuilder);
+
+ /// If [_declaredMember] is a class member that is declared in an opt-in
+ /// library but inherited to [_classBuilder] through an opt-out class then
+ /// we need to apply legacy erasure to the declared type to get the
+ /// inherited type.
+ ///
+ /// For interface members this is handled by member signatures but since
+ /// these are abstract they will never be the inherited class member.
+ ///
+ /// For instance:
+ ///
+ /// // Opt in:
+ /// class Super {
+ /// int extendedMethod(int i, {required int j}) => i;
+ /// }
+ /// class Mixin {
+ /// int mixedInMethod(int i, {required int j}) => i;
+ /// }
+ /// // Opt out:
+ /// class Legacy extends Super with Mixin {}
+ /// // Opt in:
+ /// class Class extends Legacy {
+ /// // Valid overrides since the type of `Legacy.extendedMethod` is
+ /// // `int* Function(int*, {int* j})`.
+ /// int? extendedMethod(int? i, {int? j}) => i;
+ /// // Valid overrides since the type of `Legacy.mixedInMethod` is
+ /// // `int* Function(int*, {int* j})`.
+ /// int? mixedInMethod(int? i, {int? j}) => i;
+ /// }
+ ///
+ bool declaredNeedsLegacyErasure =
+ needsLegacyErasure(_classBuilder.cls, declaredMember.enclosingClass!);
+ void callback(Member interfaceMember, bool isSetter) {
+ _classBuilder.checkOverride(membersBuilder.hierarchyBuilder.types,
+ membersBuilder, declaredMember, interfaceMember, isSetter, callback,
+ isInterfaceCheck: !_classBuilder.isMixinApplication,
+ declaredNeedsLegacyErasure: declaredNeedsLegacyErasure);
+ }
+
+ for (ClassMember overriddenMember in _overriddenMembers) {
+ callback(
+ overriddenMember.getMember(membersBuilder), _declaredMember.isSetter);
+ }
+ }
+}
+
+class DelayedGetterSetterCheck implements DelayedCheck {
+ final SourceClassBuilder classBuilder;
+ final ClassMember getter;
+ final ClassMember setter;
+
+ const DelayedGetterSetterCheck(this.classBuilder, this.getter, this.setter);
+
+ @override
+ void check(ClassMembersBuilder membersBuilder) {
+ classBuilder.checkGetterSetter(membersBuilder.hierarchyBuilder.types,
+ getter.getMember(membersBuilder), setter.getMember(membersBuilder));
+ }
+}
+
+class DelayedTypeComputation {
+ final ClassMembersNodeBuilder builder;
+ final ClassMember declaredMember;
+ final Set<ClassMember> overriddenMembers;
+ bool _computed = false;
+
+ DelayedTypeComputation(
+ this.builder, this.declaredMember, this.overriddenMembers)
+ : assert(declaredMember.isSourceDeclaration);
+
+ void compute(ClassMembersBuilder membersBuilder) {
+ if (_computed) return;
+ declaredMember.inferType(membersBuilder);
+ _computed = true;
+ if (declaredMember.isField) {
+ builder.inferFieldSignature(
+ membersBuilder, declaredMember, overriddenMembers);
+ } else if (declaredMember.isGetter) {
+ builder.inferGetterSignature(
+ membersBuilder, declaredMember, overriddenMembers);
+ } else if (declaredMember.isSetter) {
+ builder.inferSetterSignature(
+ membersBuilder, declaredMember, overriddenMembers);
+ } else {
+ builder.inferMethodSignature(
+ membersBuilder, declaredMember, overriddenMembers);
+ }
+ }
+
+ @override
+ String toString() => 'DelayedTypeComputation('
+ '${builder.classBuilder.name},$declaredMember,$overriddenMembers)';
+}
diff --git a/pkg/front_end/lib/src/fasta/kernel/hierarchy/hierarchy_builder.dart b/pkg/front_end/lib/src/fasta/kernel/hierarchy/hierarchy_builder.dart
new file mode 100644
index 0000000..b40523a
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/kernel/hierarchy/hierarchy_builder.dart
@@ -0,0 +1,194 @@
+// 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.
+
+library fasta.class_hierarchy_builder;
+
+import 'package:kernel/ast.dart';
+import 'package:kernel/class_hierarchy.dart' show ClassHierarchyBase;
+import 'package:kernel/core_types.dart' show CoreTypes;
+import 'package:kernel/src/types.dart' show Types;
+import 'package:kernel/type_algebra.dart' show Substitution, uniteNullabilities;
+
+import '../../builder/class_builder.dart';
+import '../../builder/type_builder.dart';
+import '../../loader.dart' show Loader;
+import '../../source/source_loader.dart' show SourceLoader;
+import 'hierarchy_node.dart';
+
+class ClassHierarchyBuilder implements ClassHierarchyBase {
+ final Map<Class, ClassHierarchyNode> nodes = <Class, ClassHierarchyNode>{};
+
+ final Map<ClassBuilder, Map<Class, Substitution>> substitutions =
+ <ClassBuilder, Map<Class, Substitution>>{};
+
+ final ClassBuilder objectClassBuilder;
+
+ final Loader loader;
+
+ final Class objectClass;
+
+ final Class futureClass;
+
+ final Class functionClass;
+
+ @override
+ final CoreTypes coreTypes;
+
+ late Types types;
+
+ ClassHierarchyBuilder(this.objectClassBuilder, this.loader, this.coreTypes)
+ : objectClass = objectClassBuilder.cls,
+ futureClass = coreTypes.futureClass,
+ functionClass = coreTypes.functionClass {
+ types = new Types(this);
+ }
+
+ void clear() {
+ nodes.clear();
+ substitutions.clear();
+ }
+
+ ClassHierarchyNode getNodeFromClassBuilder(ClassBuilder classBuilder) {
+ return nodes[classBuilder.cls] ??= new ClassHierarchyNodeBuilder(
+ this, classBuilder, substitutions[classBuilder] ??= {})
+ .build();
+ }
+
+ ClassHierarchyNode? getNodeFromTypeBuilder(TypeBuilder type) {
+ ClassBuilder? cls = getClass(type);
+ return cls == null ? null : getNodeFromClassBuilder(cls);
+ }
+
+ ClassHierarchyNode getNodeFromClass(Class cls) {
+ return nodes[cls] ??
+ getNodeFromClassBuilder(loader.computeClassBuilderFromTargetClass(cls));
+ }
+
+ Supertype? asSupertypeOf(InterfaceType subtype, Class supertype) {
+ if (subtype.classNode == supertype) {
+ return new Supertype(supertype, subtype.typeArguments);
+ }
+ ClassHierarchyNode clsNode = getNodeFromClass(subtype.classNode);
+ ClassHierarchyNode supertypeNode = getNodeFromClass(supertype);
+ List<Supertype> superclasses = clsNode.superclasses;
+ int depth = supertypeNode.depth;
+ if (depth < superclasses.length) {
+ Supertype superclass = superclasses[depth];
+ if (superclass.classNode == supertype) {
+ return Substitution.fromInterfaceType(subtype)
+ .substituteSupertype(superclass);
+ }
+ }
+ List<Supertype> superinterfaces = clsNode.interfaces;
+ for (int i = 0; i < superinterfaces.length; i++) {
+ Supertype superinterface = superinterfaces[i];
+ if (superinterface.classNode == supertype) {
+ return Substitution.fromInterfaceType(subtype)
+ .substituteSupertype(superinterface);
+ }
+ }
+ return null;
+ }
+
+ @override
+ InterfaceType getTypeAsInstanceOf(
+ InterfaceType type, Class superclass, Library clientLibrary) {
+ if (type.classNode == superclass) return type;
+ return asSupertypeOf(type, superclass)!
+ .asInterfaceType
+ .withDeclaredNullability(type.nullability);
+ }
+
+ @override
+ List<DartType>? getTypeArgumentsAsInstanceOf(
+ InterfaceType type, Class superclass) {
+ if (type.classNode == superclass) return type.typeArguments;
+ return asSupertypeOf(type, superclass)?.typeArguments;
+ }
+
+ @override
+ InterfaceType getLegacyLeastUpperBound(
+ InterfaceType type1, InterfaceType type2, Library clientLibrary) {
+ if (type1 == type2) return type1;
+
+ // LLUB(Null, List<dynamic>*) works differently for opt-in and opt-out
+ // libraries. In opt-out libraries the legacy behavior is preserved, so
+ // LLUB(Null, List<dynamic>*) = List<dynamic>*. In opt-out libraries the
+ // rules imply that LLUB(Null, List<dynamic>*) = List<dynamic>?.
+ if (!clientLibrary.isNonNullableByDefault) {
+ if (type1 is NullType) {
+ return type2;
+ }
+ if (type2 is NullType) {
+ return type1;
+ }
+ }
+
+ ClassHierarchyNode node1 = getNodeFromClass(type1.classNode);
+ ClassHierarchyNode node2 = getNodeFromClass(type2.classNode);
+ Set<ClassHierarchyNode> nodes1 = node1.computeAllSuperNodes(this).toSet();
+ List<ClassHierarchyNode> nodes2 = node2.computeAllSuperNodes(this);
+ List<ClassHierarchyNode> common = <ClassHierarchyNode>[];
+
+ for (int i = 0; i < nodes2.length; i++) {
+ ClassHierarchyNode node = nodes2[i];
+ // ignore: unnecessary_null_comparison
+ if (node == null) continue;
+ if (node.classBuilder.cls.isAnonymousMixin) {
+ // Never find unnamed mixin application in least upper bound.
+ continue;
+ }
+ if (nodes1.contains(node)) {
+ DartType candidate1 =
+ getTypeAsInstanceOf(type1, node.classBuilder.cls, clientLibrary);
+ DartType candidate2 =
+ getTypeAsInstanceOf(type2, node.classBuilder.cls, clientLibrary);
+ if (candidate1 == candidate2) {
+ common.add(node);
+ }
+ }
+ }
+
+ if (common.length == 1) {
+ return coreTypes.objectRawType(
+ uniteNullabilities(type1.nullability, type2.nullability));
+ }
+ common.sort(ClassHierarchyNode.compareMaxInheritancePath);
+
+ for (int i = 0; i < common.length - 1; i++) {
+ ClassHierarchyNode node = common[i];
+ if (node.maxInheritancePath != common[i + 1].maxInheritancePath) {
+ return getTypeAsInstanceOf(type1, node.classBuilder.cls, clientLibrary)
+ .withDeclaredNullability(
+ uniteNullabilities(type1.nullability, type2.nullability));
+ } else {
+ do {
+ i++;
+ } while (node.maxInheritancePath == common[i + 1].maxInheritancePath);
+ }
+ }
+ return coreTypes.objectRawType(
+ uniteNullabilities(type1.nullability, type2.nullability));
+ }
+
+ static ClassHierarchyBuilder build(ClassBuilder objectClass,
+ List<ClassBuilder> classes, SourceLoader loader, CoreTypes coreTypes) {
+ ClassHierarchyBuilder hierarchy =
+ new ClassHierarchyBuilder(objectClass, loader, coreTypes);
+ for (int i = 0; i < classes.length; i++) {
+ ClassBuilder classBuilder = classes[i];
+ if (!classBuilder.isPatch) {
+ hierarchy.nodes[classBuilder.cls] = new ClassHierarchyNodeBuilder(
+ hierarchy,
+ classBuilder,
+ hierarchy.substitutions[classBuilder] ??= {})
+ .build();
+ } else {
+ // TODO(ahe): Merge the injected members of patch into the hierarchy
+ // node of `cls.origin`.
+ }
+ }
+ return hierarchy;
+ }
+}
diff --git a/pkg/front_end/lib/src/fasta/kernel/hierarchy/hierarchy_node.dart b/pkg/front_end/lib/src/fasta/kernel/hierarchy/hierarchy_node.dart
new file mode 100644
index 0000000..a5e89b9
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/kernel/hierarchy/hierarchy_node.dart
@@ -0,0 +1,481 @@
+// 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.
+
+library fasta.class_hierarchy_builder;
+
+import 'package:kernel/ast.dart';
+import 'package:kernel/src/legacy_erasure.dart';
+import 'package:kernel/src/nnbd_top_merge.dart';
+import 'package:kernel/src/norm.dart';
+import 'package:kernel/type_algebra.dart' show Substitution;
+
+import '../../../testing/id_testing_utils.dart' show typeToText;
+import '../../builder/builder.dart';
+import '../../builder/class_builder.dart';
+import '../../builder/named_type_builder.dart';
+import '../../builder/type_alias_builder.dart';
+import '../../builder/type_builder.dart';
+import '../../type_inference/type_schema.dart' show UnknownType;
+import 'hierarchy_builder.dart';
+import 'mixin_inferrer.dart';
+
+class ClassHierarchyNodeBuilder {
+ final ClassHierarchyBuilder hierarchy;
+
+ final ClassBuilder classBuilder;
+
+ bool hasNoSuchMethod = false;
+
+ final Map<Class, Substitution> substitutions;
+
+ ClassHierarchyNodeBuilder(
+ this.hierarchy, this.classBuilder, this.substitutions);
+
+ ClassBuilder get objectClass => hierarchy.objectClassBuilder;
+
+ ClassHierarchyNode build() {
+ assert(!classBuilder.isPatch);
+ ClassHierarchyNode? supernode;
+ if (objectClass != classBuilder.origin) {
+ supernode =
+ hierarchy.getNodeFromTypeBuilder(classBuilder.supertypeBuilder!);
+ if (supernode == null) {
+ supernode = hierarchy.getNodeFromClassBuilder(objectClass);
+ }
+ // ignore: unnecessary_null_comparison
+ assert(supernode != null);
+ }
+
+ List<Supertype> superclasses;
+
+ List<Supertype> interfaces;
+
+ int maxInheritancePath;
+
+ List<TypeBuilder>? directInterfaceBuilders;
+
+ if (classBuilder.isMixinApplication) {
+ inferMixinApplication();
+ }
+
+ if (supernode == null) {
+ // This should be Object.
+ superclasses = new List<Supertype>.filled(0, dummySupertype);
+ interfaces = new List<Supertype>.filled(0, dummySupertype);
+ maxInheritancePath = 0;
+ } else {
+ maxInheritancePath = supernode.maxInheritancePath + 1;
+
+ superclasses = new List<Supertype>.filled(
+ supernode.superclasses.length + 1, dummySupertype);
+ Supertype? supertype = classBuilder.supertypeBuilder!.buildSupertype(
+ classBuilder.library, classBuilder.charOffset, classBuilder.fileUri);
+ if (supertype == null) {
+ // If the superclass is not an interface type we use Object instead.
+ // A similar normalization is performed on [supernode] above.
+ supertype =
+ new Supertype(hierarchy.coreTypes.objectClass, const <DartType>[]);
+ }
+ superclasses.setRange(0, superclasses.length - 1,
+ substSupertypes(supertype, supernode.superclasses));
+ superclasses[superclasses.length - 1] = supertype;
+ if (!classBuilder.library.isNonNullableByDefault &&
+ supernode.classBuilder.library.isNonNullableByDefault) {
+ for (int i = 0; i < superclasses.length; i++) {
+ superclasses[i] = legacyErasureSupertype(superclasses[i]);
+ }
+ }
+
+ directInterfaceBuilders = ignoreFunction(classBuilder.interfaceBuilders);
+ if (classBuilder.isMixinApplication) {
+ if (directInterfaceBuilders == null) {
+ directInterfaceBuilders = <TypeBuilder>[
+ classBuilder.mixedInTypeBuilder!
+ ];
+ } else {
+ directInterfaceBuilders = <TypeBuilder>[
+ classBuilder.mixedInTypeBuilder!
+ ]..addAll(directInterfaceBuilders);
+ }
+ }
+
+ List<Supertype> superclassInterfaces = supernode.interfaces;
+ // ignore: unnecessary_null_comparison
+ if (superclassInterfaces != null) {
+ superclassInterfaces = substSupertypes(supertype, superclassInterfaces);
+ }
+
+ if (directInterfaceBuilders != null) {
+ interfaces = <Supertype>[];
+ // ignore: unnecessary_null_comparison
+ if (superclassInterfaces != null) {
+ for (int i = 0; i < superclassInterfaces.length; i++) {
+ addInterface(interfaces, superclasses, superclassInterfaces[i]);
+ }
+ }
+
+ for (int i = 0; i < directInterfaceBuilders.length; i++) {
+ Supertype? directInterface = directInterfaceBuilders[i]
+ .buildSupertype(classBuilder.library, classBuilder.charOffset,
+ classBuilder.fileUri);
+ if (directInterface != null) {
+ addInterface(interfaces, superclasses, directInterface);
+ ClassHierarchyNode interfaceNode =
+ hierarchy.getNodeFromClass(directInterface.classNode);
+ // ignore: unnecessary_null_comparison
+ if (interfaceNode != null) {
+ if (maxInheritancePath < interfaceNode.maxInheritancePath + 1) {
+ maxInheritancePath = interfaceNode.maxInheritancePath + 1;
+ }
+
+ List<Supertype> types =
+ substSupertypes(directInterface, interfaceNode.superclasses);
+ for (int i = 0; i < types.length; i++) {
+ addInterface(interfaces, superclasses, types[i]);
+ }
+ // ignore: unnecessary_null_comparison
+ if (interfaceNode.interfaces != null) {
+ List<Supertype> types =
+ substSupertypes(directInterface, interfaceNode.interfaces);
+ for (int i = 0; i < types.length; i++) {
+ addInterface(interfaces, superclasses, types[i]);
+ }
+ }
+ }
+ }
+ }
+ // ignore: unnecessary_null_comparison
+ } else if (superclassInterfaces != null &&
+ !classBuilder.library.isNonNullableByDefault &&
+ supernode.classBuilder.library.isNonNullableByDefault) {
+ interfaces = <Supertype>[];
+ for (int i = 0; i < superclassInterfaces.length; i++) {
+ addInterface(interfaces, superclasses, superclassInterfaces[i]);
+ }
+ } else {
+ interfaces = superclassInterfaces;
+ }
+ }
+
+ for (Supertype superclass in superclasses) {
+ recordSupertype(superclass);
+ }
+ // ignore: unnecessary_null_comparison
+ if (interfaces != null) {
+ for (Supertype superinterface in interfaces) {
+ recordSupertype(superinterface);
+ }
+ }
+
+ /*ClassHierarchyMemberNode memberNode =
+ buildMemberNode(supernode, directInterfaceBuilders);*/
+
+ return new ClassHierarchyNode(
+ classBuilder,
+ supernode,
+ directInterfaceBuilders,
+ /*classMemberMap,
+ classSetterMap,
+ interfaceMemberMap,
+ interfaceSetterMap,*/
+ superclasses,
+ interfaces,
+ maxInheritancePath,
+ /*hasNoSuchMethod,
+ dataForTesting,*/
+ /*memberNode*/
+ );
+ }
+
+ Supertype recordSupertype(Supertype supertype) {
+ debug?.log("In ${this.classBuilder.fullNameForErrors} "
+ "recordSupertype(${supertype})");
+ Class cls = supertype.classNode;
+ List<TypeParameter> supertypeTypeParameters = cls.typeParameters;
+ if (supertypeTypeParameters.isEmpty) {
+ substitutions[cls] = Substitution.empty;
+ } else {
+ List<DartType> arguments = supertype.typeArguments;
+ List<DartType> typeArguments =
+ new List<DartType>.filled(arguments.length, dummyDartType);
+ List<TypeParameter> typeParameters =
+ new List<TypeParameter>.filled(arguments.length, dummyTypeParameter);
+ for (int i = 0; i < arguments.length; i++) {
+ typeParameters[i] = supertypeTypeParameters[i];
+ typeArguments[i] = arguments[i];
+ }
+ substitutions[cls] =
+ Substitution.fromPairs(typeParameters, typeArguments);
+ }
+ return supertype;
+ }
+
+ List<Supertype> substSupertypes(
+ Supertype supertype, List<Supertype> supertypes) {
+ List<TypeParameter> typeVariables = supertype.classNode.typeParameters;
+ if (typeVariables.isEmpty) {
+ debug?.log("In ${this.classBuilder.fullNameForErrors} "
+ "$supertypes aren't substed");
+ return supertypes;
+ }
+ Map<TypeParameter, DartType> map = <TypeParameter, DartType>{};
+ List<DartType> arguments = supertype.typeArguments;
+ for (int i = 0; i < typeVariables.length; i++) {
+ map[typeVariables[i]] = arguments[i];
+ }
+ Substitution substitution = Substitution.fromMap(map);
+ List<Supertype>? result;
+ for (int i = 0; i < supertypes.length; i++) {
+ Supertype supertype = supertypes[i];
+ Supertype substituted = substitution.substituteSupertype(supertype);
+ if (supertype != substituted) {
+ debug?.log("In ${this.classBuilder.fullNameForErrors} $supertype"
+ " -> $substituted");
+ result ??= supertypes.toList();
+ result[i] = substituted;
+ } else {
+ debug?.log("In ${this.classBuilder.fullNameForErrors} "
+ "$supertype isn't substed");
+ }
+ }
+ return result ?? supertypes;
+ }
+
+ void addInterface(List<Supertype> interfaces, List<Supertype> superclasses,
+ Supertype type) {
+ // ignore: unnecessary_null_comparison
+ if (type == null) return null;
+ if (!classBuilder.library.isNonNullableByDefault) {
+ type = legacyErasureSupertype(type);
+ }
+ ClassHierarchyNode node = hierarchy.getNodeFromClass(type.classNode);
+ // ignore: unnecessary_null_comparison
+ if (node == null) return null;
+ int depth = node.depth;
+ int myDepth = superclasses.length;
+ Supertype? superclass = depth < myDepth ? superclasses[depth] : null;
+ if (superclass != null && superclass.classNode == type.classNode) {
+ // This is a potential conflict.
+ if (classBuilder.library.isNonNullableByDefault) {
+ superclass = nnbdTopMergeSupertype(
+ hierarchy.coreTypes,
+ normSupertype(hierarchy.coreTypes, superclass),
+ normSupertype(hierarchy.coreTypes, type));
+ if (superclass == null) {
+ // This is a conflict.
+ // TODO(johnniwinther): Report errors here instead of through
+ // the computation of the [ClassHierarchy].
+ superclass = superclasses[depth];
+ } else {
+ superclasses[depth] = superclass;
+ }
+ }
+ return;
+ } else {
+ for (int i = 0; i < interfaces.length; i++) {
+ // This is a quadratic algorithm, but normally, the number of
+ // interfaces is really small.
+ Supertype? interface = interfaces[i];
+ if (interface.classNode == type.classNode) {
+ // This is a potential conflict.
+ if (classBuilder.library.isNonNullableByDefault) {
+ interface = nnbdTopMergeSupertype(
+ hierarchy.coreTypes,
+ normSupertype(hierarchy.coreTypes, interface),
+ normSupertype(hierarchy.coreTypes, type));
+ if (interface == null) {
+ // This is a conflict.
+ // TODO(johnniwinther): Report errors here instead of through
+ // the computation of the [ClassHierarchy].
+ interface = interfaces[i];
+ } else {
+ interfaces[i] = interface;
+ }
+ }
+ return;
+ }
+ }
+ }
+ interfaces.add(type);
+ }
+
+ void inferMixinApplication() {
+ Class cls = classBuilder.cls;
+ Supertype? mixedInType = cls.mixedInType;
+ if (mixedInType == null) return;
+ List<DartType> typeArguments = mixedInType.typeArguments;
+ if (typeArguments.isEmpty || typeArguments.first is! UnknownType) return;
+ new BuilderMixinInferrer(
+ classBuilder,
+ hierarchy.coreTypes,
+ new TypeBuilderConstraintGatherer(hierarchy,
+ mixedInType.classNode.typeParameters, cls.enclosingLibrary))
+ .infer(cls);
+ List<TypeBuilder> inferredArguments = new List<TypeBuilder>.generate(
+ typeArguments.length,
+ (int i) => hierarchy.loader.computeTypeBuilder(typeArguments[i]),
+ growable: false);
+ NamedTypeBuilder mixedInTypeBuilder =
+ classBuilder.mixedInTypeBuilder as NamedTypeBuilder;
+ mixedInTypeBuilder.arguments = inferredArguments;
+ }
+
+ /// The class Function from dart:core is supposed to be ignored when used as
+ /// an interface.
+ List<TypeBuilder>? ignoreFunction(List<TypeBuilder>? interfaces) {
+ if (interfaces == null) return null;
+ for (int i = 0; i < interfaces!.length; i++) {
+ ClassBuilder? classBuilder = getClass(interfaces[i]);
+ if (classBuilder != null && classBuilder.cls == hierarchy.functionClass) {
+ if (interfaces.length == 1) {
+ return null;
+ } else {
+ interfaces = interfaces.toList();
+ interfaces.removeAt(i);
+ return ignoreFunction(interfaces);
+ }
+ }
+ }
+ return interfaces;
+ }
+}
+
+class ClassHierarchyNode {
+ /// The class corresponding to this hierarchy node.
+ final ClassBuilder classBuilder;
+
+ final ClassHierarchyNode? supernode;
+
+ final List<TypeBuilder>? directInterfaceBuilders;
+
+ /*/// All the members of this class including [classMembers] of its
+ /// superclasses. The members are sorted by [compareDeclarations].
+ final Map<Name, ClassMember> classMemberMap;
+
+ /// Similar to [classMembers] but for setters.
+ final Map<Name, ClassMember> classSetterMap;
+
+ /// All the interface members of this class including [interfaceMembers] of
+ /// its supertypes. The members are sorted by [compareDeclarations].
+ ///
+ /// In addition to the members of [classMembers] this also contains members
+ /// from interfaces.
+ ///
+ /// This may be null, in which case [classMembers] is the interface members.
+ final Map<Name, ClassMember>? interfaceMemberMap;
+
+ /// Similar to [interfaceMembers] but for setters.
+ ///
+ /// This may be null, in which case [classSetters] is the interface setters.
+ final Map<Name, ClassMember>? interfaceSetterMap;*/
+
+ /// All superclasses of [classBuilder] excluding itself. The classes are
+ /// sorted by depth from the root (Object) in ascending order.
+ final List<Supertype> superclasses;
+
+ /// The list of all classes implemented by [classBuilder] and its supertypes
+ /// excluding any classes from [superclasses].
+ final List<Supertype> interfaces;
+
+ /// The longest inheritance path from [classBuilder] to `Object`.
+ final int maxInheritancePath;
+
+ int get depth => superclasses.length;
+
+ /*final bool hasNoSuchMethod;
+
+ final ClassHierarchyNodeDataForTesting? dataForTesting;*/
+
+ //final ClassHierarchyMemberNode memberNode;
+
+ ClassHierarchyNode(
+ this.classBuilder,
+ this.supernode,
+ this.directInterfaceBuilders,
+ /*this.classMemberMap,
+ this.classSetterMap,
+ this.interfaceMemberMap,
+ this.interfaceSetterMap,*/
+ this.superclasses,
+ this.interfaces,
+ this.maxInheritancePath,
+ /*this.hasNoSuchMethod,
+ this.dataForTesting,*/
+ /*this.memberNode*/
+ );
+
+ /// Returns a list of all supertypes of [classBuilder], including this node.
+ List<ClassHierarchyNode> computeAllSuperNodes(
+ ClassHierarchyBuilder hierarchy) {
+ List<ClassHierarchyNode> result = [];
+ for (int i = 0; i < superclasses.length; i++) {
+ Supertype type = superclasses[i];
+ result.add(hierarchy.getNodeFromClass(type.classNode));
+ }
+ for (int i = 0; i < interfaces.length; i++) {
+ Supertype type = interfaces[i];
+ result.add(hierarchy.getNodeFromClass(type.classNode));
+ }
+ result.add(this);
+ return result;
+ }
+
+ @override
+ String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb
+ ..write(classBuilder.fullNameForErrors)
+ ..writeln(":");
+ if (maxInheritancePath != this.depth) {
+ sb
+ ..write(" Longest path to Object: ")
+ ..writeln(maxInheritancePath);
+ }
+ sb..writeln(" superclasses:");
+ int depth = 0;
+ for (Supertype superclass in superclasses) {
+ sb.write(" " * (depth + 2));
+ if (depth != 0) sb.write("-> ");
+ sb.write(typeToText(superclass.asInterfaceType));
+ sb.writeln();
+ depth++;
+ }
+ // ignore: unnecessary_null_comparison
+ if (interfaces != null) {
+ sb.write(" interfaces:");
+ bool first = true;
+ for (Supertype i in interfaces) {
+ if (!first) sb.write(",");
+ sb.write(" ");
+ sb.write(typeToText(i.asInterfaceType));
+ first = false;
+ }
+ sb.writeln();
+ }
+ return "$sb";
+ }
+
+ static int compareMaxInheritancePath(
+ ClassHierarchyNode a, ClassHierarchyNode b) {
+ return b.maxInheritancePath.compareTo(a.maxInheritancePath);
+ }
+}
+
+ClassBuilder? getClass(TypeBuilder type) {
+ Builder? declaration = type.declaration;
+ if (declaration is TypeAliasBuilder) {
+ TypeAliasBuilder aliasBuilder = declaration;
+ NamedTypeBuilder namedBuilder = type as NamedTypeBuilder;
+ declaration = aliasBuilder.unaliasDeclaration(namedBuilder.arguments);
+ }
+ return declaration is ClassBuilder ? declaration : null;
+}
+
+const DebugLogger? debug =
+ const bool.fromEnvironment("debug.hierarchy") ? const DebugLogger() : null;
+
+class DebugLogger {
+ const DebugLogger();
+ void log(Object message) => print(message);
+}
diff --git a/pkg/front_end/lib/src/fasta/kernel/hierarchy/members_builder.dart b/pkg/front_end/lib/src/fasta/kernel/hierarchy/members_builder.dart
new file mode 100644
index 0000000..f50343a
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/kernel/hierarchy/members_builder.dart
@@ -0,0 +1,182 @@
+// 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.
+
+library fasta.class_hierarchy_builder;
+
+import 'package:kernel/ast.dart';
+import 'package:kernel/class_hierarchy.dart' show ClassHierarchyMembers;
+
+import '../../builder/class_builder.dart';
+import '../../builder/field_builder.dart';
+import '../../builder/procedure_builder.dart';
+import '../../builder/type_builder.dart';
+import '../../source/source_class_builder.dart';
+import 'class_member.dart';
+import 'delayed.dart';
+import 'hierarchy_builder.dart';
+import 'hierarchy_node.dart';
+import 'members_node.dart';
+
+class ClassMembersBuilder implements ClassHierarchyMembers {
+ final ClassHierarchyBuilder hierarchyBuilder;
+
+ final Map<Class, ClassMembersNode> nodes = <Class, ClassMembersNode>{};
+
+ final List<DelayedTypeComputation> _delayedTypeComputations =
+ <DelayedTypeComputation>[];
+
+ final List<DelayedCheck> _delayedChecks = <DelayedCheck>[];
+
+ final List<ClassMember> _delayedMemberComputations = <ClassMember>[];
+
+ ClassMembersBuilder(this.hierarchyBuilder);
+
+ void clear() {
+ nodes.clear();
+ _delayedChecks.clear();
+ _delayedTypeComputations.clear();
+ _delayedMemberComputations.clear();
+ }
+
+ void registerDelayedTypeComputation(DelayedTypeComputation computation) {
+ _delayedTypeComputations.add(computation);
+ }
+
+ void registerOverrideCheck(SourceClassBuilder classBuilder,
+ ClassMember declaredMember, Set<ClassMember> overriddenMembers) {
+ _delayedChecks.add(new DelayedOverrideCheck(
+ classBuilder, declaredMember, overriddenMembers));
+ }
+
+ void registerGetterSetterCheck(
+ SourceClassBuilder classBuilder, ClassMember getter, ClassMember setter) {
+ _delayedChecks
+ .add(new DelayedGetterSetterCheck(classBuilder, getter, setter));
+ }
+
+ void registerMemberComputation(ClassMember member) {
+ _delayedMemberComputations.add(member);
+ }
+
+ List<DelayedTypeComputation> takeDelayedTypeComputations() {
+ List<DelayedTypeComputation> list = _delayedTypeComputations.toList();
+ _delayedTypeComputations.clear();
+ return list;
+ }
+
+ List<DelayedCheck> takeDelayedChecks() {
+ List<DelayedCheck> list = _delayedChecks.toList();
+ _delayedChecks.clear();
+ return list;
+ }
+
+ List<ClassMember> takeDelayedMemberComputations() {
+ List<ClassMember> list = _delayedMemberComputations.toList();
+ _delayedMemberComputations.clear();
+ return list;
+ }
+
+ void inferFieldType(SourceFieldBuilder declaredMember,
+ Iterable<ClassMember> overriddenMembers) {
+ ClassMembersNodeBuilder.inferFieldType(
+ hierarchyBuilder,
+ this,
+ declaredMember.classBuilder as SourceClassBuilder,
+ declaredMember,
+ overriddenMembers);
+ }
+
+ void inferGetterType(SourceProcedureBuilder declaredMember,
+ Iterable<ClassMember> overriddenMembers) {
+ ClassMembersNodeBuilder.inferGetterType(
+ hierarchyBuilder,
+ this,
+ declaredMember.classBuilder as SourceClassBuilder,
+ declaredMember,
+ overriddenMembers);
+ }
+
+ void inferSetterType(SourceProcedureBuilder declaredMember,
+ Iterable<ClassMember> overriddenMembers) {
+ ClassMembersNodeBuilder.inferSetterType(
+ hierarchyBuilder,
+ this,
+ declaredMember.classBuilder as SourceClassBuilder,
+ declaredMember,
+ overriddenMembers);
+ }
+
+ void inferMethodType(SourceProcedureBuilder declaredMember,
+ Iterable<ClassMember> overriddenMembers) {
+ ClassMembersNodeBuilder.inferMethodType(
+ hierarchyBuilder,
+ this,
+ declaredMember.classBuilder as SourceClassBuilder,
+ declaredMember,
+ overriddenMembers);
+ }
+
+ ClassMembersNode getNodeFromClassBuilder(ClassBuilder classBuilder) {
+ return nodes[classBuilder.cls] ??= new ClassMembersNodeBuilder(
+ this,
+ hierarchyBuilder.getNodeFromClassBuilder(classBuilder),
+ hierarchyBuilder.substitutions[classBuilder] ??= {})
+ .build();
+ }
+
+ ClassMembersNode? getNodeFromTypeBuilder(TypeBuilder type) {
+ ClassBuilder? cls = getClass(type);
+ return cls == null ? null : getNodeFromClassBuilder(cls);
+ }
+
+ ClassMembersNode getNodeFromClass(Class cls) {
+ return nodes[cls] ??
+ getNodeFromClassBuilder(
+ hierarchyBuilder.loader.computeClassBuilderFromTargetClass(cls));
+ }
+
+ @override
+ Member? getInterfaceMember(Class cls, Name name, {bool setter: false}) {
+ return getNodeFromClass(cls)
+ .getInterfaceMember(name, setter)
+ ?.getMember(this);
+ }
+
+ ClassMember? getInterfaceClassMember(Class cls, Name name,
+ {bool setter: false}) {
+ return getNodeFromClass(cls).getInterfaceMember(name, setter);
+ }
+
+ static ClassMembersBuilder build(
+ ClassHierarchyBuilder hierarchyBuilder, List<ClassBuilder> classes) {
+ ClassMembersBuilder membersBuilder =
+ new ClassMembersBuilder(hierarchyBuilder);
+ for (int i = 0; i < classes.length; i++) {
+ ClassBuilder classBuilder = classes[i];
+ if (!classBuilder.isPatch) {
+ membersBuilder.nodes[classBuilder.cls] = new ClassMembersNodeBuilder(
+ membersBuilder,
+ hierarchyBuilder.getNodeFromClassBuilder(classBuilder),
+ hierarchyBuilder.substitutions[classBuilder] ??= {})
+ .build();
+ } else {
+ // TODO(ahe): Merge the injected members of patch into the hierarchy
+ // node of `cls.origin`.
+ }
+ }
+ return membersBuilder;
+ }
+
+ void computeTypes() {
+ List<DelayedTypeComputation> typeComputations =
+ takeDelayedTypeComputations();
+ for (int i = 0; i < typeComputations.length; i++) {
+ typeComputations[i].compute(this);
+ }
+ }
+}
+
+int compareNamedParameters(VariableDeclaration a, VariableDeclaration b) {
+ return a.name!.compareTo(b.name!);
+}
diff --git a/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart b/pkg/front_end/lib/src/fasta/kernel/hierarchy/members_node.dart
similarity index 65%
rename from pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart
rename to pkg/front_end/lib/src/fasta/kernel/hierarchy/members_node.dart
index 8508470..b2fc124 100644
--- a/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/hierarchy/members_node.dart
@@ -1,46 +1,31 @@
-// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// 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.
library fasta.class_hierarchy_builder;
import 'package:kernel/ast.dart';
-
-import 'package:kernel/class_hierarchy.dart'
- show ClassHierarchy, ClassHierarchyBase;
-
-import 'package:kernel/core_types.dart' show CoreTypes;
-
-import 'package:kernel/type_algebra.dart' show Substitution, uniteNullabilities;
-import 'package:kernel/type_environment.dart';
-
+import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
import 'package:kernel/src/legacy_erasure.dart';
import 'package:kernel/src/nnbd_top_merge.dart';
import 'package:kernel/src/norm.dart';
-import 'package:kernel/src/standard_bounds.dart';
-import 'package:kernel/src/types.dart' show Types;
+import 'package:kernel/type_algebra.dart' show Substitution;
-import '../../base/common.dart';
-import '../../testing/id_testing_utils.dart' show typeToText;
-
-import '../builder/builder.dart';
-import '../builder/class_builder.dart';
-import '../builder/field_builder.dart';
-import '../builder/formal_parameter_builder.dart';
-import '../builder/library_builder.dart';
-import '../builder/member_builder.dart';
-import '../builder/named_type_builder.dart';
-import '../builder/procedure_builder.dart';
-import '../builder/type_alias_builder.dart';
-import '../builder/type_builder.dart';
-import '../builder/type_declaration_builder.dart';
-
-import '../loader.dart' show Loader;
-
-import '../messages.dart'
+import '../../../base/common.dart';
+import '../../builder/builder.dart';
+import '../../builder/class_builder.dart';
+import '../../builder/field_builder.dart';
+import '../../builder/formal_parameter_builder.dart';
+import '../../builder/library_builder.dart';
+import '../../builder/member_builder.dart';
+import '../../builder/named_type_builder.dart';
+import '../../builder/procedure_builder.dart';
+import '../../builder/type_alias_builder.dart';
+import '../../builder/type_builder.dart';
+import '../../builder/type_declaration_builder.dart';
+import '../../messages.dart'
show
LocatedMessage,
- Message,
messageDeclaredMemberConflictsWithInheritedMember,
messageDeclaredMemberConflictsWithInheritedMemberCause,
messageDeclaredMemberConflictsWithOverriddenMembersCause,
@@ -52,748 +37,38 @@
templateCantInferTypesDueToNoCombinedSignature,
templateCantInferReturnTypeDueToNoCombinedSignature,
templateCantInferTypeDueToNoCombinedSignature,
- templateCombinedMemberSignatureFailed,
templateDuplicatedDeclaration,
templateDuplicatedDeclarationCause,
templateMissingImplementationCause,
templateMissingImplementationNotAbstract;
+import '../../names.dart' show noSuchMethodName;
+import '../../scope.dart' show Scope;
+import '../../source/source_class_builder.dart';
+import '../combined_member_signature.dart';
+import '../member_covariance.dart';
+import 'class_member.dart';
+import 'delayed.dart';
+import 'hierarchy_builder.dart';
+import 'hierarchy_node.dart';
+import 'members_builder.dart';
-import '../names.dart' show noSuchMethodName;
-
-import '../scope.dart' show Scope;
-
-import '../source/source_class_builder.dart';
-import '../source/source_library_builder.dart' show SourceLibraryBuilder;
-
-import '../source/source_loader.dart' show SourceLoader;
-
-import '../type_inference/standard_bounds.dart' show TypeSchemaStandardBounds;
-
-import '../type_inference/type_constraint_gatherer.dart'
- show TypeConstraintGatherer;
-
-import '../type_inference/type_inferrer.dart' show MixinInferrer;
-
-import '../type_inference/type_schema.dart' show UnknownType;
-
-import '../type_inference/type_schema_environment.dart' show TypeConstraint;
-
-import 'combined_member_signature.dart';
-
-import 'member_covariance.dart';
-
-import 'forwarding_node.dart' show ForwardingNode;
-
-const DebugLogger? debug =
- const bool.fromEnvironment("debug.hierarchy") ? const DebugLogger() : null;
-
-class DebugLogger {
- const DebugLogger();
- void log(Object message) => print(message);
-}
-
-int compareDeclarations(ClassMember a, ClassMember b) {
- if (a == b) return 0;
- return ClassHierarchy.compareNames(a.name, b.name);
-}
-
-int compareClassMembers(ClassMember a, ClassMember b) {
- if (a.forSetter == b.forSetter) {
- return compareDeclarations(a, b);
- } else if (a.forSetter) {
- return 1;
- } else {
- return -1;
- }
-}
-
-bool isNameVisibleIn(Name name, LibraryBuilder libraryBuilder) {
- return !name.isPrivate || name.library == libraryBuilder.library;
-}
-
-class Tuple {
- final Name name;
- ClassMember? _declaredMember;
- ClassMember? _declaredSetter;
- ClassMember? _mixedInMember;
- ClassMember? _mixedInSetter;
- ClassMember? _extendedMember;
- ClassMember? _extendedSetter;
- List<ClassMember>? _implementedMembers;
- List<ClassMember>? _implementedSetters;
-
- Tuple.declareMember(ClassMember declaredMember)
- : assert(!declaredMember.forSetter),
- this._declaredMember = declaredMember,
- this.name = declaredMember.name;
-
- Tuple.mixInMember(ClassMember mixedInMember)
- : assert(!mixedInMember.forSetter),
- this._mixedInMember = mixedInMember,
- this.name = mixedInMember.name;
-
- Tuple.extendMember(ClassMember extendedMember)
- : assert(!extendedMember.forSetter),
- this._extendedMember = extendedMember,
- this.name = extendedMember.name;
-
- Tuple.implementMember(ClassMember implementedMember)
- : assert(!implementedMember.forSetter),
- this.name = implementedMember.name,
- _implementedMembers = <ClassMember>[implementedMember];
-
- Tuple.declareSetter(ClassMember declaredSetter)
- : assert(declaredSetter.forSetter),
- this._declaredSetter = declaredSetter,
- this.name = declaredSetter.name;
-
- Tuple.mixInSetter(ClassMember mixedInSetter)
- : assert(mixedInSetter.forSetter),
- this._mixedInSetter = mixedInSetter,
- this.name = mixedInSetter.name;
-
- Tuple.extendSetter(ClassMember extendedSetter)
- : assert(extendedSetter.forSetter),
- this._extendedSetter = extendedSetter,
- this.name = extendedSetter.name;
-
- Tuple.implementSetter(ClassMember implementedSetter)
- : assert(implementedSetter.forSetter),
- this.name = implementedSetter.name,
- _implementedSetters = <ClassMember>[implementedSetter];
-
- ClassMember? get declaredMember => _declaredMember;
-
- void set declaredMember(ClassMember? value) {
- assert(!value!.forSetter);
- assert(
- _declaredMember == null,
- "Declared member already set to $_declaredMember, "
- "trying to set it to $value.");
- _declaredMember = value;
- }
-
- ClassMember? get declaredSetter => _declaredSetter;
-
- void set declaredSetter(ClassMember? value) {
- assert(value!.forSetter);
- assert(
- _declaredSetter == null,
- "Declared setter already set to $_declaredSetter, "
- "trying to set it to $value.");
- _declaredSetter = value;
- }
-
- ClassMember? get extendedMember => _extendedMember;
-
- void set extendedMember(ClassMember? value) {
- assert(!value!.forSetter);
- assert(
- _extendedMember == null,
- "Extended member already set to $_extendedMember, "
- "trying to set it to $value.");
- _extendedMember = value;
- }
-
- ClassMember? get extendedSetter => _extendedSetter;
-
- void set extendedSetter(ClassMember? value) {
- assert(value!.forSetter);
- assert(
- _extendedSetter == null,
- "Extended setter already set to $_extendedSetter, "
- "trying to set it to $value.");
- _extendedSetter = value;
- }
-
- ClassMember? get mixedInMember => _mixedInMember;
-
- void set mixedInMember(ClassMember? value) {
- assert(!value!.forSetter);
- assert(
- _mixedInMember == null,
- "Mixed in member already set to $_mixedInMember, "
- "trying to set it to $value.");
- _mixedInMember = value;
- }
-
- ClassMember? get mixedInSetter => _mixedInSetter;
-
- void set mixedInSetter(ClassMember? value) {
- assert(value!.forSetter);
- assert(
- _mixedInSetter == null,
- "Mixed in setter already set to $_mixedInSetter, "
- "trying to set it to $value.");
- _mixedInSetter = value;
- }
-
- List<ClassMember>? get implementedMembers => _implementedMembers;
-
- void addImplementedMember(ClassMember value) {
- assert(!value.forSetter);
- _implementedMembers ??= <ClassMember>[];
- _implementedMembers!.add(value);
- }
-
- List<ClassMember>? get implementedSetters => _implementedSetters;
-
- void addImplementedSetter(ClassMember value) {
- assert(value.forSetter);
- _implementedSetters ??= <ClassMember>[];
- _implementedSetters!.add(value);
- }
-
- @override
- String toString() {
- StringBuffer sb = new StringBuffer();
- String comma = '';
- sb.write('Tuple(');
- if (_declaredMember != null) {
- sb.write(comma);
- sb.write('declaredMember=');
- sb.write(_declaredMember);
- comma = ',';
- }
- if (_declaredSetter != null) {
- sb.write(comma);
- sb.write('declaredSetter=');
- sb.write(_declaredSetter);
- comma = ',';
- }
- if (_mixedInMember != null) {
- sb.write(comma);
- sb.write('mixedInMember=');
- sb.write(_mixedInMember);
- comma = ',';
- }
- if (_mixedInSetter != null) {
- sb.write(comma);
- sb.write('mixedInSetter=');
- sb.write(_mixedInSetter);
- comma = ',';
- }
- if (_extendedMember != null) {
- sb.write(comma);
- sb.write('extendedMember=');
- sb.write(_extendedMember);
- comma = ',';
- }
- if (_extendedSetter != null) {
- sb.write(comma);
- sb.write('extendedSetter=');
- sb.write(_extendedSetter);
- comma = ',';
- }
- if (_implementedMembers != null) {
- sb.write(comma);
- sb.write('implementedMembers=');
- sb.write(_implementedMembers);
- comma = ',';
- }
- if (_implementedSetters != null) {
- sb.write(comma);
- sb.write('implementedSetters=');
- sb.write(_implementedSetters);
- comma = ',';
- }
- sb.write(')');
- return sb.toString();
- }
-}
-
-abstract class ClassMember {
- Name get name;
- bool get isStatic;
- bool get isField;
- bool get isAssignable;
- bool get isSetter;
- bool get isGetter;
- bool get isFinal;
- bool get isConst;
- bool get forSetter;
-
- /// Returns `true` if this member corresponds to a declaration in the source
- /// code.
- bool get isSourceDeclaration;
-
- /// Returns `true` if this member is a field, getter or setter.
- bool get isProperty;
-
- /// Computes the [Member] node resulting from this class member.
- Member getMember(ClassHierarchyBuilder hierarchy);
-
- /// Returns the member [Covariance] for this class member.
- Covariance getCovariance(ClassHierarchyBuilder hierarchy);
-
- bool get isDuplicate;
- String get fullName;
- String get fullNameForErrors;
- ClassBuilder get classBuilder;
-
- /// Returns `true` if this class member is declared in Object from dart:core.
- bool isObjectMember(ClassBuilder objectClass);
- Uri get fileUri;
- int get charOffset;
-
- /// Returns `true` if this class member is an interface member.
- bool get isAbstract;
-
- /// Returns `true` if this member doesn't corresponds to a declaration in the
- /// source code.
- bool get isSynthesized;
-
- // If `true` this member is not part of the interface but only part of the
- // class members.
- //
- // This is `true` for instance for synthesized fields added for the late
- // lowering.
- bool get isInternalImplementation;
-
- /// Returns `true` if this member is composed from a list of class members
- /// accessible through [declarations].
- bool get hasDeclarations;
-
- /// If [hasDeclaration] is `true`, this returns the list of class members
- /// from which this class member is composed.
- ///
- /// This is used in [unfoldDeclarations] to retrieve all underlying member
- /// source declarations, and in [toSet] to retrieve all members used for
- /// this class member wrt. certain level of the hierarchy.
- /// TODO(johnniwinther): Can the use of [toSet] be replaced with a direct
- /// use of [declarations]?
- List<ClassMember> get declarations;
-
- /// The interface member corresponding to this member.
- ///
- /// If this member is declared on the source, the interface member is
- /// the member itself. For instance
- ///
- /// abstract class Class {
- /// void concreteMethod() {}
- /// void abstractMethod();
- /// }
- ///
- /// the interface members for `concreteMethod` and `abstractMethod` are the
- /// members themselves.
- ///
- /// If this member is a synthesized interface member, the
- /// interface member is the member itself. For instance
- ///
- /// abstract class Interface1 {
- /// void method() {}
- /// }
- /// abstract class Interface2 {
- /// void method() {}
- /// }
- /// abstract class Class implements Interface1, Interface2 {}
- ///
- /// the interface member for `method` in `Class` is the synthesized interface
- /// member created for the implemented members `Interface1.method` and
- /// `Interface2.method`.
- ///
- /// If this member is a concrete member that implements an interface member,
- /// the interface member is the implemented interface member. For instance
- ///
- /// class Super {
- /// void method() {}
- /// }
- /// class Interface {
- /// void method() {}
- /// }
- /// class Class extends Super implements Interface {}
- ///
- /// the interface member for `Super.method` implementing `method` in `Class`
- /// is the synthesized interface member created for the implemented members
- /// `Super.method` and `Interface.method`.
- ClassMember get interfaceMember;
-
- void inferType(ClassHierarchyBuilder hierarchy);
- void registerOverrideDependency(Set<ClassMember> overriddenMembers);
-
- /// Returns `true` if this has the same underlying declaration as [other].
- ///
- /// This is used for avoiding unnecessary checks and can this trivially
- /// return `false`.
- bool isSameDeclaration(ClassMember other);
-}
-
-bool hasSameSignature(FunctionNode a, FunctionNode b) {
- List<TypeParameter> aTypeParameters = a.typeParameters;
- List<TypeParameter> bTypeParameters = b.typeParameters;
- int typeParameterCount = aTypeParameters.length;
- if (typeParameterCount != bTypeParameters.length) {
- return false;
- }
- Substitution? substitution;
- if (typeParameterCount != 0) {
- List<DartType> types = new List<DartType>.generate(
- typeParameterCount,
- (int i) => new TypeParameterType.forAlphaRenaming(
- bTypeParameters[i], aTypeParameters[i]),
- growable: false);
- substitution = Substitution.fromPairs(bTypeParameters, types);
- for (int i = 0; i < typeParameterCount; i++) {
- DartType aBound = aTypeParameters[i].bound;
- DartType bBound = substitution.substituteType(bTypeParameters[i].bound);
- if (aBound != bBound) {
- return false;
- }
- }
- }
-
- if (a.requiredParameterCount != b.requiredParameterCount) {
- return false;
- }
- List<VariableDeclaration> aPositionalParameters = a.positionalParameters;
- List<VariableDeclaration> bPositionalParameters = b.positionalParameters;
- if (aPositionalParameters.length != bPositionalParameters.length) {
- return false;
- }
- for (int i = 0; i < aPositionalParameters.length; i++) {
- VariableDeclaration aParameter = aPositionalParameters[i];
- VariableDeclaration bParameter = bPositionalParameters[i];
- if (aParameter.isCovariantByDeclaration !=
- bParameter.isCovariantByDeclaration) {
- return false;
- }
- DartType aType = aParameter.type;
- DartType bType = bParameter.type;
- if (substitution != null) {
- bType = substitution.substituteType(bType);
- }
- if (aType != bType) return false;
- }
-
- List<VariableDeclaration> aNamedParameters = a.namedParameters;
- List<VariableDeclaration> bNamedParameters = b.namedParameters;
- if (aNamedParameters.length != bNamedParameters.length) {
- return false;
- }
- for (int i = 0; i < aNamedParameters.length; i++) {
- VariableDeclaration aParameter = aNamedParameters[i];
- VariableDeclaration bParameter = bNamedParameters[i];
- if (aParameter.isCovariantByDeclaration !=
- bParameter.isCovariantByDeclaration) {
- return false;
- }
- if (aParameter.name != bParameter.name) {
- return false;
- }
- DartType aType = aParameter.type;
- DartType bType = bParameter.type;
- if (substitution != null) {
- bType = substitution.substituteType(bType);
- }
- if (aType != bType) {
- return false;
- }
- }
-
- DartType aReturnType = a.returnType;
- DartType bReturnType = b.returnType;
- if (substitution != null) {
- bReturnType = substitution.substituteType(bReturnType);
- }
-
- return aReturnType == bReturnType;
-}
-
-class ClassHierarchyBuilder implements ClassHierarchyBase {
- final Map<Class, ClassHierarchyNode> nodes = <Class, ClassHierarchyNode>{};
-
- final Map<ClassBuilder, Map<Class, Substitution>> substitutions =
- <ClassBuilder, Map<Class, Substitution>>{};
-
- final ClassBuilder objectClassBuilder;
-
- final Loader loader;
-
- final Class objectClass;
-
- final Class futureClass;
-
- final Class functionClass;
-
- final List<DelayedTypeComputation> _delayedTypeComputations =
- <DelayedTypeComputation>[];
-
- final List<DelayedCheck> _delayedChecks = <DelayedCheck>[];
-
- final List<ClassMember> _delayedMemberComputations = <ClassMember>[];
-
- @override
- final CoreTypes coreTypes;
-
- late Types types;
-
- ClassHierarchyBuilder(this.objectClassBuilder, this.loader, this.coreTypes)
- : objectClass = objectClassBuilder.cls,
- futureClass = coreTypes.futureClass,
- functionClass = coreTypes.functionClass {
- types = new Types(this);
- }
-
- void clear() {
- nodes.clear();
- substitutions.clear();
- _delayedChecks.clear();
- _delayedTypeComputations.clear();
- _delayedMemberComputations.clear();
- }
-
- void registerDelayedTypeComputation(DelayedTypeComputation computation) {
- _delayedTypeComputations.add(computation);
- }
-
- void registerOverrideCheck(SourceClassBuilder classBuilder,
- ClassMember declaredMember, Set<ClassMember> overriddenMembers) {
- _delayedChecks.add(new DelayedOverrideCheck(
- classBuilder, declaredMember, overriddenMembers));
- }
-
- void registerGetterSetterCheck(
- SourceClassBuilder classBuilder, ClassMember getter, ClassMember setter) {
- _delayedChecks
- .add(new DelayedGetterSetterCheck(classBuilder, getter, setter));
- }
-
- void registerMemberComputation(ClassMember member) {
- _delayedMemberComputations.add(member);
- }
-
- List<DelayedTypeComputation> takeDelayedTypeComputations() {
- List<DelayedTypeComputation> list = _delayedTypeComputations.toList();
- _delayedTypeComputations.clear();
- return list;
- }
-
- List<DelayedCheck> takeDelayedChecks() {
- List<DelayedCheck> list = _delayedChecks.toList();
- _delayedChecks.clear();
- return list;
- }
-
- List<ClassMember> takeDelayedMemberComputations() {
- List<ClassMember> list = _delayedMemberComputations.toList();
- _delayedMemberComputations.clear();
- return list;
- }
-
- void inferFieldType(SourceFieldBuilder declaredMember,
- Iterable<ClassMember> overriddenMembers) {
- ClassHierarchyNodeBuilder.inferFieldType(
- this,
- declaredMember.classBuilder as SourceClassBuilder,
- declaredMember,
- overriddenMembers);
- }
-
- void inferGetterType(SourceProcedureBuilder declaredMember,
- Iterable<ClassMember> overriddenMembers) {
- ClassHierarchyNodeBuilder.inferGetterType(
- this,
- declaredMember.classBuilder as SourceClassBuilder,
- declaredMember,
- overriddenMembers);
- }
-
- void inferSetterType(SourceProcedureBuilder declaredMember,
- Iterable<ClassMember> overriddenMembers) {
- ClassHierarchyNodeBuilder.inferSetterType(
- this,
- declaredMember.classBuilder as SourceClassBuilder,
- declaredMember,
- overriddenMembers);
- }
-
- void inferMethodType(SourceProcedureBuilder declaredMember,
- Iterable<ClassMember> overriddenMembers) {
- ClassHierarchyNodeBuilder.inferMethodType(
- this,
- declaredMember.classBuilder as SourceClassBuilder,
- declaredMember,
- overriddenMembers);
- }
-
- ClassHierarchyNode getNodeFromClassBuilder(ClassBuilder classBuilder) {
- return nodes[classBuilder.cls] ??= new ClassHierarchyNodeBuilder(
- this, classBuilder, substitutions[classBuilder] ??= {})
- .build();
- }
-
- ClassHierarchyNode? getNodeFromTypeBuilder(TypeBuilder type) {
- ClassBuilder? cls = getClass(type);
- return cls == null ? null : getNodeFromClassBuilder(cls);
- }
-
- ClassHierarchyNode getNodeFromClass(Class cls) {
- return nodes[cls] ??
- getNodeFromClassBuilder(loader.computeClassBuilderFromTargetClass(cls));
- }
-
- Supertype? asSupertypeOf(InterfaceType subtype, Class supertype) {
- if (subtype.classNode == supertype) {
- return new Supertype(supertype, subtype.typeArguments);
- }
- ClassHierarchyNode clsNode = getNodeFromClass(subtype.classNode);
- ClassHierarchyNode supertypeNode = getNodeFromClass(supertype);
- List<Supertype> superclasses = clsNode.superclasses;
- int depth = supertypeNode.depth;
- if (depth < superclasses.length) {
- Supertype superclass = superclasses[depth];
- if (superclass.classNode == supertype) {
- return Substitution.fromInterfaceType(subtype)
- .substituteSupertype(superclass);
- }
- }
- List<Supertype> superinterfaces = clsNode.interfaces;
- for (int i = 0; i < superinterfaces.length; i++) {
- Supertype superinterface = superinterfaces[i];
- if (superinterface.classNode == supertype) {
- return Substitution.fromInterfaceType(subtype)
- .substituteSupertype(superinterface);
- }
- }
- return null;
- }
-
- @override
- InterfaceType getTypeAsInstanceOf(
- InterfaceType type, Class superclass, Library clientLibrary) {
- if (type.classNode == superclass) return type;
- return asSupertypeOf(type, superclass)!
- .asInterfaceType
- .withDeclaredNullability(type.nullability);
- }
-
- @override
- List<DartType>? getTypeArgumentsAsInstanceOf(
- InterfaceType type, Class superclass) {
- if (type.classNode == superclass) return type.typeArguments;
- return asSupertypeOf(type, superclass)?.typeArguments;
- }
-
- @override
- InterfaceType getLegacyLeastUpperBound(
- InterfaceType type1, InterfaceType type2, Library clientLibrary) {
- if (type1 == type2) return type1;
-
- // LLUB(Null, List<dynamic>*) works differently for opt-in and opt-out
- // libraries. In opt-out libraries the legacy behavior is preserved, so
- // LLUB(Null, List<dynamic>*) = List<dynamic>*. In opt-out libraries the
- // rules imply that LLUB(Null, List<dynamic>*) = List<dynamic>?.
- if (!clientLibrary.isNonNullableByDefault) {
- if (type1 is NullType) {
- return type2;
- }
- if (type2 is NullType) {
- return type1;
- }
- }
-
- ClassHierarchyNode node1 = getNodeFromClass(type1.classNode);
- ClassHierarchyNode node2 = getNodeFromClass(type2.classNode);
- Set<ClassHierarchyNode> nodes1 = node1.computeAllSuperNodes(this).toSet();
- List<ClassHierarchyNode> nodes2 = node2.computeAllSuperNodes(this);
- List<ClassHierarchyNode> common = <ClassHierarchyNode>[];
-
- for (int i = 0; i < nodes2.length; i++) {
- ClassHierarchyNode node = nodes2[i];
- // ignore: unnecessary_null_comparison
- if (node == null) continue;
- if (node.classBuilder.cls.isAnonymousMixin) {
- // Never find unnamed mixin application in least upper bound.
- continue;
- }
- if (nodes1.contains(node)) {
- DartType candidate1 =
- getTypeAsInstanceOf(type1, node.classBuilder.cls, clientLibrary);
- DartType candidate2 =
- getTypeAsInstanceOf(type2, node.classBuilder.cls, clientLibrary);
- if (candidate1 == candidate2) {
- common.add(node);
- }
- }
- }
-
- if (common.length == 1) {
- return coreTypes.objectRawType(
- uniteNullabilities(type1.nullability, type2.nullability));
- }
- common.sort(ClassHierarchyNode.compareMaxInheritancePath);
-
- for (int i = 0; i < common.length - 1; i++) {
- ClassHierarchyNode node = common[i];
- if (node.maxInheritancePath != common[i + 1].maxInheritancePath) {
- return getTypeAsInstanceOf(type1, node.classBuilder.cls, clientLibrary)
- .withDeclaredNullability(
- uniteNullabilities(type1.nullability, type2.nullability));
- } else {
- do {
- i++;
- } while (node.maxInheritancePath == common[i + 1].maxInheritancePath);
- }
- }
- return coreTypes.objectRawType(
- uniteNullabilities(type1.nullability, type2.nullability));
- }
-
- @override
- Member? getInterfaceMember(Class cls, Name name, {bool setter: false}) {
- return getNodeFromClass(cls)
- .getInterfaceMember(name, setter)
- ?.getMember(this);
- }
-
- ClassMember? getInterfaceClassMember(Class cls, Name name,
- {bool setter: false}) {
- return getNodeFromClass(cls).getInterfaceMember(name, setter);
- }
-
- static ClassHierarchyBuilder build(ClassBuilder objectClass,
- List<ClassBuilder> classes, SourceLoader loader, CoreTypes coreTypes) {
- ClassHierarchyBuilder hierarchy =
- new ClassHierarchyBuilder(objectClass, loader, coreTypes);
- for (int i = 0; i < classes.length; i++) {
- ClassBuilder classBuilder = classes[i];
- if (!classBuilder.isPatch) {
- hierarchy.nodes[classBuilder.cls] = new ClassHierarchyNodeBuilder(
- hierarchy,
- classBuilder,
- hierarchy.substitutions[classBuilder] ??= {})
- .build();
- } else {
- // TODO(ahe): Merge the injected members of patch into the hierarchy
- // node of `cls.origin`.
- }
- }
- return hierarchy;
- }
-
- void computeTypes() {
- List<DelayedTypeComputation> typeComputations =
- takeDelayedTypeComputations();
- for (int i = 0; i < typeComputations.length; i++) {
- typeComputations[i].compute(this);
- }
- }
-}
-
-class ClassHierarchyNodeBuilder {
- final ClassHierarchyBuilder hierarchy;
-
- final ClassBuilder classBuilder;
+class ClassMembersNodeBuilder {
+ final ClassHierarchyNode _hierarchyNode;
+ final ClassMembersBuilder _membersBuilder;
bool hasNoSuchMethod = false;
final Map<Class, Substitution> substitutions;
- ClassHierarchyNodeBuilder(
- this.hierarchy, this.classBuilder, this.substitutions);
+ ClassMembersNodeBuilder(
+ this._membersBuilder, this._hierarchyNode, this.substitutions);
+
+ ClassHierarchyBuilder get hierarchy => _membersBuilder.hierarchyBuilder;
ClassBuilder get objectClass => hierarchy.objectClassBuilder;
+ ClassBuilder get classBuilder => _hierarchyNode.classBuilder;
+
bool get shouldModifyKernel =>
classBuilder.library.loader == hierarchy.loader;
@@ -806,7 +81,8 @@
}
static void inferMethodType(
- ClassHierarchyBuilder hierarchy,
+ ClassHierarchyBuilder hierarchyBuilder,
+ ClassMembersBuilder membersBuilder,
SourceClassBuilder classBuilder,
SourceProcedureBuilder declaredMember,
Iterable<ClassMember> overriddenMembers) {
@@ -833,7 +109,7 @@
toSet(classBuilder, overriddenMembers);
CombinedClassMemberSignature combinedMemberSignature =
new CombinedClassMemberSignature(
- hierarchy, classBuilder, overriddenMemberSet.toList(),
+ membersBuilder, classBuilder, overriddenMemberSet.toList(),
forSetter: false);
FunctionType? combinedMemberSignatureType = combinedMemberSignature
.getCombinedSignatureTypeInContext(declaredTypeParameters)
@@ -901,14 +177,13 @@
if ((cantInferReturnType && cantInferParameterTypes != null) ||
(cantInferParameterTypes != null &&
cantInferParameterTypes.length > 1)) {
- reportCantInferTypes(
- classBuilder, declaredMember, hierarchy, overriddenMembers);
+ reportCantInferTypes(classBuilder, declaredMember, overriddenMembers);
} else if (cantInferReturnType) {
reportCantInferReturnType(
- classBuilder, declaredMember, hierarchy, overriddenMembers);
+ classBuilder, declaredMember, overriddenMembers);
} else if (cantInferParameterTypes != null) {
- reportCantInferParameterType(classBuilder,
- cantInferParameterTypes.single, hierarchy, overriddenMembers);
+ reportCantInferParameterType(
+ classBuilder, cantInferParameterTypes.single, overriddenMembers);
}
if (declaredMember.returnType == null) {
@@ -929,41 +204,43 @@
}
}
- void inferMethodSignature(ClassHierarchyBuilder hierarchy,
+ void inferMethodSignature(ClassMembersBuilder membersBuilder,
ClassMember declaredMember, Iterable<ClassMember> overriddenMembers) {
assert(!declaredMember.isGetter && !declaredMember.isSetter);
// Trigger computation of method type.
Procedure declaredProcedure =
- declaredMember.getMember(hierarchy) as Procedure;
+ declaredMember.getMember(membersBuilder) as Procedure;
for (ClassMember overriddenMember
in toSet(declaredMember.classBuilder, overriddenMembers)) {
- Covariance covariance = overriddenMember.getCovariance(hierarchy);
+ Covariance covariance = overriddenMember.getCovariance(membersBuilder);
covariance.applyCovariance(declaredProcedure);
}
}
- void inferGetterSignature(ClassHierarchyBuilder hierarchy,
+ void inferGetterSignature(ClassMembersBuilder membersBuilder,
ClassMember declaredMember, Iterable<ClassMember> overriddenMembers) {
assert(declaredMember.isGetter);
// Trigger computation of the getter type.
- declaredMember.getMember(hierarchy);
+ declaredMember.getMember(membersBuilder);
// Otherwise nothing to do. Getters have no variance.
}
- void inferSetterSignature(ClassHierarchyBuilder hierarchy,
+ void inferSetterSignature(ClassMembersBuilder membersBuilder,
ClassMember declaredMember, Iterable<ClassMember> overriddenMembers) {
assert(declaredMember.isSetter);
// Trigger computation of the getter type.
- Procedure declaredSetter = declaredMember.getMember(hierarchy) as Procedure;
+ Procedure declaredSetter =
+ declaredMember.getMember(membersBuilder) as Procedure;
for (ClassMember overriddenMember
in toSet(declaredMember.classBuilder, overriddenMembers)) {
- Covariance covariance = overriddenMember.getCovariance(hierarchy);
+ Covariance covariance = overriddenMember.getCovariance(membersBuilder);
covariance.applyCovariance(declaredSetter);
}
}
static void inferGetterType(
- ClassHierarchyBuilder hierarchy,
+ ClassHierarchyBuilder hierarchyBuilder,
+ ClassMembersBuilder membersBuilder,
SourceClassBuilder classBuilder,
SourceProcedureBuilder declaredMember,
Iterable<ClassMember> overriddenMembers) {
@@ -987,14 +264,14 @@
// ignore: unnecessary_null_comparison
assert(forSetter != null);
CombinedClassMemberSignature combinedMemberSignature =
- new CombinedClassMemberSignature(hierarchy, classBuilder, members,
+ new CombinedClassMemberSignature(
+ membersBuilder, classBuilder, members,
forSetter: forSetter);
DartType? combinedMemberSignatureType =
combinedMemberSignature.combinedMemberSignatureType;
if (combinedMemberSignatureType == null) {
inferredType = const InvalidType();
- reportCantInferReturnType(
- classBuilder, declaredMember, hierarchy, members);
+ reportCantInferReturnType(classBuilder, declaredMember, members);
} else {
inferredType = combinedMemberSignatureType;
}
@@ -1025,7 +302,8 @@
}
static void inferSetterType(
- ClassHierarchyBuilder hierarchy,
+ ClassHierarchyBuilder hierarchyBuilder,
+ ClassMembersBuilder membersBuilder,
SourceClassBuilder classBuilder,
SourceProcedureBuilder declaredMember,
Iterable<ClassMember> overriddenMembers) {
@@ -1050,14 +328,14 @@
// ignore: unnecessary_null_comparison
assert(forSetter != null);
CombinedClassMemberSignature combinedMemberSignature =
- new CombinedClassMemberSignature(hierarchy, classBuilder, members,
+ new CombinedClassMemberSignature(
+ membersBuilder, classBuilder, members,
forSetter: forSetter);
DartType? combinedMemberSignatureType =
combinedMemberSignature.combinedMemberSignatureType;
if (combinedMemberSignatureType == null) {
inferredType = const InvalidType();
- reportCantInferReturnType(
- classBuilder, declaredMember, hierarchy, members);
+ reportCantInferReturnType(classBuilder, declaredMember, members);
} else {
inferredType = combinedMemberSignatureType;
}
@@ -1126,7 +404,8 @@
/// Infers the field type of [fieldBuilder] based on [overriddenMembers].
static void inferFieldType(
- ClassHierarchyBuilder hierarchy,
+ ClassHierarchyBuilder hierarchyBuilder,
+ ClassMembersBuilder membersBuilder,
SourceClassBuilder classBuilder,
SourceFieldBuilder fieldBuilder,
Iterable<ClassMember> overriddenMembers) {
@@ -1150,7 +429,8 @@
// ignore: unnecessary_null_comparison
assert(forSetter != null);
CombinedClassMemberSignature combinedMemberSignature =
- new CombinedClassMemberSignature(hierarchy, classBuilder, members,
+ new CombinedClassMemberSignature(
+ membersBuilder, classBuilder, members,
forSetter: forSetter);
return combinedMemberSignature.combinedMemberSignatureType;
}
@@ -1205,12 +485,12 @@
/// Infers the field signature of [declaredMember] based on
/// [overriddenMembers].
- void inferFieldSignature(ClassHierarchyBuilder hierarchy,
+ void inferFieldSignature(ClassMembersBuilder membersBuilder,
ClassMember declaredMember, Iterable<ClassMember> overriddenMembers) {
- Field declaredField = declaredMember.getMember(hierarchy) as Field;
+ Field declaredField = declaredMember.getMember(membersBuilder) as Field;
for (ClassMember overriddenMember
in toSet(declaredMember.classBuilder, overriddenMembers)) {
- Covariance covariance = overriddenMember.getCovariance(hierarchy);
+ Covariance covariance = overriddenMember.getCovariance(membersBuilder);
covariance.applyCovariance(declaredField);
}
}
@@ -1285,18 +565,13 @@
}
}
- ClassHierarchyNode build() {
- assert(!classBuilder.isPatch);
- ClassHierarchyNode? supernode;
- if (objectClass != classBuilder.origin) {
- supernode =
- hierarchy.getNodeFromTypeBuilder(classBuilder.supertypeBuilder!);
- if (supernode == null) {
- supernode = hierarchy.getNodeFromClassBuilder(objectClass);
- }
- // ignore: unnecessary_null_comparison
- assert(supernode != null);
- }
+ ClassMembersNode build() {
+ ClassMembersNode? supernode = _hierarchyNode.supernode != null
+ ? _membersBuilder
+ .getNodeFromClassBuilder(_hierarchyNode.supernode!.classBuilder)
+ : null;
+ List<TypeBuilder>? directInterfaceBuilders =
+ _hierarchyNode.directInterfaceBuilders;
/// Set to `true` if the class needs interfaces, that is, if it has any
/// members where the interface member is different from its corresponding
@@ -1364,7 +639,6 @@
if (classBuilder.isMixinApplication) {
TypeBuilder mixedInTypeBuilder = classBuilder.mixedInTypeBuilder!;
TypeDeclarationBuilder mixin = mixedInTypeBuilder.declaration!;
- inferMixinApplication();
while (mixin.isNamedMixinApplication) {
ClassBuilder named = mixin as ClassBuilder;
mixedInTypeBuilder = named.mixedInTypeBuilder!;
@@ -1434,12 +708,6 @@
}
}
- List<Supertype> superclasses;
-
- List<Supertype> interfaces;
-
- int maxInheritancePath;
-
void extend(Map<Name, ClassMember>? superClassMembers) {
if (superClassMembers == null) return;
for (MapEntry<Name, ClassMember> entry in superClassMembers.entries) {
@@ -1488,52 +756,7 @@
if (supernode == null) {
// This should be Object.
- superclasses = new List<Supertype>.filled(0, dummySupertype);
- interfaces = new List<Supertype>.filled(0, dummySupertype);
- maxInheritancePath = 0;
} else {
- maxInheritancePath = supernode.maxInheritancePath + 1;
-
- superclasses = new List<Supertype>.filled(
- supernode.superclasses.length + 1, dummySupertype);
- Supertype? supertype = classBuilder.supertypeBuilder!.buildSupertype(
- classBuilder.library, classBuilder.charOffset, classBuilder.fileUri);
- if (supertype == null) {
- // If the superclass is not an interface type we use Object instead.
- // A similar normalization is performed on [supernode] above.
- supertype =
- new Supertype(hierarchy.coreTypes.objectClass, const <DartType>[]);
- }
- superclasses.setRange(0, superclasses.length - 1,
- substSupertypes(supertype, supernode.superclasses));
- superclasses[superclasses.length - 1] = supertype;
- if (!classBuilder.library.isNonNullableByDefault &&
- supernode.classBuilder.library.isNonNullableByDefault) {
- for (int i = 0; i < superclasses.length; i++) {
- superclasses[i] = legacyErasureSupertype(superclasses[i]);
- }
- }
-
- List<TypeBuilder>? directInterfaceBuilders =
- ignoreFunction(classBuilder.interfaceBuilders);
- if (classBuilder.isMixinApplication) {
- if (directInterfaceBuilders == null) {
- directInterfaceBuilders = <TypeBuilder>[
- classBuilder.mixedInTypeBuilder!
- ];
- } else {
- directInterfaceBuilders = <TypeBuilder>[
- classBuilder.mixedInTypeBuilder!
- ]..addAll(directInterfaceBuilders);
- }
- }
-
- List<Supertype> superclassInterfaces = supernode.interfaces;
- // ignore: unnecessary_null_comparison
- if (superclassInterfaces != null) {
- superclassInterfaces = substSupertypes(supertype, superclassInterfaces);
- }
-
extend(supernode.classMemberMap);
extend(supernode.classSetterMap);
@@ -1549,8 +772,8 @@
if (directInterfaceBuilders != null) {
for (int i = 0; i < directInterfaceBuilders.length; i++) {
- ClassHierarchyNode? interfaceNode =
- hierarchy.getNodeFromTypeBuilder(directInterfaceBuilders[i]);
+ ClassMembersNode? interfaceNode = _membersBuilder
+ .getNodeFromTypeBuilder(directInterfaceBuilders[i]);
if (interfaceNode != null) {
hasInterfaces = true;
@@ -1560,65 +783,6 @@
interfaceNode.classSetterMap);
}
}
-
- interfaces = <Supertype>[];
- // ignore: unnecessary_null_comparison
- if (superclassInterfaces != null) {
- for (int i = 0; i < superclassInterfaces.length; i++) {
- addInterface(interfaces, superclasses, superclassInterfaces[i]);
- }
- }
-
- for (int i = 0; i < directInterfaceBuilders.length; i++) {
- Supertype? directInterface = directInterfaceBuilders[i]
- .buildSupertype(classBuilder.library, classBuilder.charOffset,
- classBuilder.fileUri);
- if (directInterface != null) {
- addInterface(interfaces, superclasses, directInterface);
- ClassHierarchyNode interfaceNode =
- hierarchy.getNodeFromClass(directInterface.classNode);
- // ignore: unnecessary_null_comparison
- if (interfaceNode != null) {
- if (maxInheritancePath < interfaceNode.maxInheritancePath + 1) {
- maxInheritancePath = interfaceNode.maxInheritancePath + 1;
- }
-
- List<Supertype> types =
- substSupertypes(directInterface, interfaceNode.superclasses);
- for (int i = 0; i < types.length; i++) {
- addInterface(interfaces, superclasses, types[i]);
- }
- // ignore: unnecessary_null_comparison
- if (interfaceNode.interfaces != null) {
- List<Supertype> types =
- substSupertypes(directInterface, interfaceNode.interfaces);
- for (int i = 0; i < types.length; i++) {
- addInterface(interfaces, superclasses, types[i]);
- }
- }
- }
- }
- }
- // ignore: unnecessary_null_comparison
- } else if (superclassInterfaces != null &&
- !classBuilder.library.isNonNullableByDefault &&
- supernode.classBuilder.library.isNonNullableByDefault) {
- interfaces = <Supertype>[];
- for (int i = 0; i < superclassInterfaces.length; i++) {
- addInterface(interfaces, superclasses, superclassInterfaces[i]);
- }
- } else {
- interfaces = superclassInterfaces;
- }
- }
-
- for (Supertype superclass in superclasses) {
- recordSupertype(superclass);
- }
- // ignore: unnecessary_null_comparison
- if (interfaces != null) {
- for (Supertype superinterface in interfaces) {
- recordSupertype(superinterface);
}
}
@@ -2350,7 +1514,7 @@
isProperty: definingMember.isProperty,
forSetter: definingMember.forSetter,
shouldModifyKernel: shouldModifyKernel);
- hierarchy.registerMemberComputation(interfaceMember);
+ _membersBuilder.registerMemberComputation(interfaceMember);
if (extendedMember != null) {
/// class Super {
@@ -2384,7 +1548,7 @@
implementedInterfaceMember: interfaceMember,
forSetter: definingMember.forSetter,
isProperty: definingMember.isProperty);
- hierarchy.registerMemberComputation(classMember);
+ _membersBuilder.registerMemberComputation(classMember);
if (!classBuilder.isAbstract) {
registerInheritedImplements(extendedMember, {interfaceMember},
aliasForTesting: classMember);
@@ -2475,7 +1639,7 @@
isProperty: definingMember.isProperty,
forSetter: definingMember.forSetter,
shouldModifyKernel: shouldModifyKernel);
- hierarchy.registerMemberComputation(interfaceMember);
+ _membersBuilder.registerMemberComputation(interfaceMember);
/// The concrete mixed in member is the class member but will
/// be overwritten by a concrete mixin stub:
@@ -2494,7 +1658,7 @@
implementedInterfaceMember: interfaceMember,
forSetter: definingMember.forSetter,
isProperty: definingMember.isProperty);
- hierarchy.registerMemberComputation(classMember);
+ _membersBuilder.registerMemberComputation(classMember);
if (!classBuilder.isAbstract) {
/// class Interface {
@@ -2583,7 +1747,7 @@
isProperty: definingMember.isProperty,
forSetter: definingMember.forSetter,
shouldModifyKernel: shouldModifyKernel);
- hierarchy.registerMemberComputation(interfaceMember);
+ _membersBuilder.registerMemberComputation(interfaceMember);
}
if (extendedMember != null) {
@@ -2615,7 +1779,7 @@
implementedInterfaceMember: interfaceMember,
forSetter: definingMember.forSetter,
isProperty: definingMember.isProperty);
- hierarchy.registerMemberComputation(classMember);
+ _membersBuilder.registerMemberComputation(classMember);
if (!classBuilder.isAbstract) {
/// class Super {
@@ -2739,7 +1903,7 @@
isProperty: definingMember.isProperty,
forSetter: definingMember.forSetter,
shouldModifyKernel: shouldModifyKernel);
- hierarchy.registerMemberComputation(interfaceMember);
+ _membersBuilder.registerMemberComputation(interfaceMember);
}
if (interfaceMember == classMember) {
/// class Super {
@@ -2783,7 +1947,7 @@
implementedInterfaceMember: interfaceMember,
isProperty: definingMember.isProperty,
forSetter: definingMember.forSetter);
- hierarchy.registerMemberComputation(classMember);
+ _membersBuilder.registerMemberComputation(classMember);
if (!classBuilder.isAbstract) {
/// class Super {
/// method() {}
@@ -2809,7 +1973,7 @@
isProperty: definingMember.isProperty,
forSetter: definingMember.forSetter,
shouldModifyKernel: shouldModifyKernel);
- hierarchy.registerMemberComputation(interfaceMember);
+ _membersBuilder.registerMemberComputation(interfaceMember);
/// The concrete extended member is the class member and should
/// be able to be overwritten by a synthesized concrete member here,
@@ -2820,7 +1984,7 @@
implementedInterfaceMember: interfaceMember,
isProperty: definingMember.isProperty,
forSetter: definingMember.forSetter);
- hierarchy.registerMemberComputation(classMember);
+ _membersBuilder.registerMemberComputation(classMember);
}
} else if (implementedMembers != null) {
/// class Interface {
@@ -2865,7 +2029,7 @@
isProperty: definingMember.isProperty,
forSetter: definingMember.forSetter,
shouldModifyKernel: shouldModifyKernel);
- hierarchy.registerMemberComputation(interfaceMember);
+ _membersBuilder.registerMemberComputation(interfaceMember);
}
if (!classBuilder.isAbstract) {
/// class Interface {
@@ -2947,7 +2111,7 @@
/// not a valid getter/setter in `Class` because the type of the getter
/// `Super.property2` is _not_ a subtype of the setter
/// `Mixin.property1`.
- hierarchy.registerGetterSetterCheck(
+ _membersBuilder.registerGetterSetterCheck(
classBuilder as SourceClassBuilder,
interfaceGetable,
interfaceSetable);
@@ -3104,11 +2268,11 @@
/// computed before override checks are performed.
DelayedTypeComputation computation =
new DelayedTypeComputation(this, classMember, overriddenMembers);
- hierarchy.registerDelayedTypeComputation(computation);
+ _membersBuilder.registerDelayedTypeComputation(computation);
/// Declared members must be checked to validly override the
/// overridden members.
- hierarchy.registerOverrideCheck(
+ _membersBuilder.registerOverrideCheck(
classBuilder as SourceClassBuilder, classMember, overriddenMembers);
});
@@ -3116,7 +2280,7 @@
(ClassMember classMember, Set<ClassMember> overriddenMembers) {
/// Declared mixed in members must be checked to validly override the
/// overridden members.
- hierarchy.registerOverrideCheck(
+ _membersBuilder.registerOverrideCheck(
classBuilder as SourceClassBuilder, classMember, overriddenMembers);
});
@@ -3124,7 +2288,7 @@
(ClassMember classMember, Set<ClassMember> overriddenMembers) {
/// Concrete members must be checked to validly override the overridden
/// members in concrete classes.
- hierarchy.registerOverrideCheck(
+ _membersBuilder.registerOverrideCheck(
classBuilder as SourceClassBuilder, classMember, overriddenMembers);
});
}
@@ -3163,131 +2327,16 @@
}
}
- return new ClassHierarchyNode(
+ return new ClassMembersNode(
classBuilder,
classMemberMap,
classSetterMap,
interfaceMemberMap,
interfaceSetterMap,
- superclasses,
- interfaces,
- maxInheritancePath,
hasNoSuchMethod,
dataForTesting);
}
- Supertype recordSupertype(Supertype supertype) {
- debug?.log("In ${this.classBuilder.fullNameForErrors} "
- "recordSupertype(${supertype})");
- Class cls = supertype.classNode;
- List<TypeParameter> supertypeTypeParameters = cls.typeParameters;
- if (supertypeTypeParameters.isEmpty) {
- substitutions[cls] = Substitution.empty;
- } else {
- List<DartType> arguments = supertype.typeArguments;
- List<DartType> typeArguments =
- new List<DartType>.filled(arguments.length, dummyDartType);
- List<TypeParameter> typeParameters =
- new List<TypeParameter>.filled(arguments.length, dummyTypeParameter);
- for (int i = 0; i < arguments.length; i++) {
- typeParameters[i] = supertypeTypeParameters[i];
- typeArguments[i] = arguments[i];
- }
- substitutions[cls] =
- Substitution.fromPairs(typeParameters, typeArguments);
- }
- return supertype;
- }
-
- List<Supertype> substSupertypes(
- Supertype supertype, List<Supertype> supertypes) {
- List<TypeParameter> typeVariables = supertype.classNode.typeParameters;
- if (typeVariables.isEmpty) {
- debug?.log("In ${this.classBuilder.fullNameForErrors} "
- "$supertypes aren't substed");
- return supertypes;
- }
- Map<TypeParameter, DartType> map = <TypeParameter, DartType>{};
- List<DartType> arguments = supertype.typeArguments;
- for (int i = 0; i < typeVariables.length; i++) {
- map[typeVariables[i]] = arguments[i];
- }
- Substitution substitution = Substitution.fromMap(map);
- List<Supertype>? result;
- for (int i = 0; i < supertypes.length; i++) {
- Supertype supertype = supertypes[i];
- Supertype substituted = substitution.substituteSupertype(supertype);
- if (supertype != substituted) {
- debug?.log("In ${this.classBuilder.fullNameForErrors} $supertype"
- " -> $substituted");
- result ??= supertypes.toList();
- result[i] = substituted;
- } else {
- debug?.log("In ${this.classBuilder.fullNameForErrors} "
- "$supertype isn't substed");
- }
- }
- return result ?? supertypes;
- }
-
- void addInterface(List<Supertype> interfaces, List<Supertype> superclasses,
- Supertype type) {
- // ignore: unnecessary_null_comparison
- if (type == null) return null;
- if (!classBuilder.library.isNonNullableByDefault) {
- type = legacyErasureSupertype(type);
- }
- ClassHierarchyNode node = hierarchy.getNodeFromClass(type.classNode);
- // ignore: unnecessary_null_comparison
- if (node == null) return null;
- int depth = node.depth;
- int myDepth = superclasses.length;
- Supertype? superclass = depth < myDepth ? superclasses[depth] : null;
- if (superclass != null && superclass.classNode == type.classNode) {
- // This is a potential conflict.
- if (classBuilder.library.isNonNullableByDefault) {
- superclass = nnbdTopMergeSupertype(
- hierarchy.coreTypes,
- normSupertype(hierarchy.coreTypes, superclass),
- normSupertype(hierarchy.coreTypes, type));
- if (superclass == null) {
- // This is a conflict.
- // TODO(johnniwinther): Report errors here instead of through
- // the computation of the [ClassHierarchy].
- superclass = superclasses[depth];
- } else {
- superclasses[depth] = superclass;
- }
- }
- return;
- } else {
- for (int i = 0; i < interfaces.length; i++) {
- // This is a quadratic algorithm, but normally, the number of
- // interfaces is really small.
- Supertype? interface = interfaces[i];
- if (interface.classNode == type.classNode) {
- // This is a potential conflict.
- if (classBuilder.library.isNonNullableByDefault) {
- interface = nnbdTopMergeSupertype(
- hierarchy.coreTypes,
- normSupertype(hierarchy.coreTypes, interface),
- normSupertype(hierarchy.coreTypes, type));
- if (interface == null) {
- // This is a conflict.
- // TODO(johnniwinther): Report errors here instead of through
- // the computation of the [ClassHierarchy].
- interface = interfaces[i];
- } else {
- interfaces[i] = interface;
- }
- }
- return;
- }
- }
- }
- interfaces.add(type);
- }
-
void reportMissingMembers(List<ClassMember> abstractMembers) {
Map<String, LocatedMessage> contextMap = <String, LocatedMessage>{};
for (ClassMember declaration in unfoldDeclarations(abstractMembers)) {
@@ -3319,50 +2368,9 @@
void installNsmHandlers() {
// TODO(ahe): Implement this.
}
-
- void inferMixinApplication() {
- Class cls = classBuilder.cls;
- Supertype? mixedInType = cls.mixedInType;
- if (mixedInType == null) return;
- List<DartType> typeArguments = mixedInType.typeArguments;
- if (typeArguments.isEmpty || typeArguments.first is! UnknownType) return;
- new BuilderMixinInferrer(
- classBuilder,
- hierarchy.coreTypes,
- new TypeBuilderConstraintGatherer(hierarchy,
- mixedInType.classNode.typeParameters, cls.enclosingLibrary))
- .infer(cls);
- List<TypeBuilder> inferredArguments = new List<TypeBuilder>.generate(
- typeArguments.length,
- (int i) => hierarchy.loader.computeTypeBuilder(typeArguments[i]),
- growable: false);
- NamedTypeBuilder mixedInTypeBuilder =
- classBuilder.mixedInTypeBuilder as NamedTypeBuilder;
- mixedInTypeBuilder.arguments = inferredArguments;
- }
-
- /// The class Function from dart:core is supposed to be ignored when used as
- /// an interface.
- List<TypeBuilder>? ignoreFunction(List<TypeBuilder>? interfaces) {
- if (interfaces == null) return null;
- for (int i = 0; i < interfaces!.length; i++) {
- ClassBuilder? classBuilder = getClass(interfaces[i]);
- if (classBuilder != null && classBuilder.cls == hierarchy.functionClass) {
- if (interfaces.length == 1) {
- return null;
- } else {
- interfaces = interfaces.toList();
- interfaces.removeAt(i);
- return ignoreFunction(interfaces);
- }
- }
- }
- return interfaces;
- }
}
-class ClassHierarchyNode {
- /// The class corresponding to this hierarchy node.
+class ClassMembersNode {
final ClassBuilder classBuilder;
/// All the members of this class including [classMembers] of its
@@ -3386,83 +2394,25 @@
/// This may be null, in which case [classSetters] is the interface setters.
final Map<Name, ClassMember>? interfaceSetterMap;
- /// All superclasses of [classBuilder] excluding itself. The classes are
- /// sorted by depth from the root (Object) in ascending order.
- final List<Supertype> superclasses;
-
- /// The list of all classes implemented by [classBuilder] and its supertypes
- /// excluding any classes from [superclasses].
- final List<Supertype> interfaces;
-
- /// The longest inheritance path from [classBuilder] to `Object`.
- final int maxInheritancePath;
-
- int get depth => superclasses.length;
-
final bool hasNoSuchMethod;
final ClassHierarchyNodeDataForTesting? dataForTesting;
- ClassHierarchyNode(
+ ClassMembersNode(
this.classBuilder,
this.classMemberMap,
this.classSetterMap,
this.interfaceMemberMap,
this.interfaceSetterMap,
- this.superclasses,
- this.interfaces,
- this.maxInheritancePath,
this.hasNoSuchMethod,
this.dataForTesting);
- /// Returns a list of all supertypes of [classBuilder], including this node.
- List<ClassHierarchyNode> computeAllSuperNodes(
- ClassHierarchyBuilder hierarchy) {
- List<ClassHierarchyNode> result = [];
- for (int i = 0; i < superclasses.length; i++) {
- Supertype type = superclasses[i];
- result.add(hierarchy.getNodeFromClass(type.classNode));
- }
- for (int i = 0; i < interfaces.length; i++) {
- Supertype type = interfaces[i];
- result.add(hierarchy.getNodeFromClass(type.classNode));
- }
- result.add(this);
- return result;
- }
-
@override
String toString() {
StringBuffer sb = new StringBuffer();
sb
..write(classBuilder.fullNameForErrors)
..writeln(":");
- if (maxInheritancePath != this.depth) {
- sb
- ..write(" Longest path to Object: ")
- ..writeln(maxInheritancePath);
- }
- sb..writeln(" superclasses:");
- int depth = 0;
- for (Supertype superclass in superclasses) {
- sb.write(" " * (depth + 2));
- if (depth != 0) sb.write("-> ");
- sb.write(typeToText(superclass.asInterfaceType));
- sb.writeln();
- depth++;
- }
- // ignore: unnecessary_null_comparison
- if (interfaces != null) {
- sb.write(" interfaces:");
- bool first = true;
- for (Supertype i in interfaces) {
- if (!first) sb.write(",");
- sb.write(" ");
- sb.write(typeToText(i.asInterfaceType));
- first = false;
- }
- sb.writeln();
- }
printMemberMap(classMemberMap, sb, "classMembers");
printMemberMap(classSetterMap, sb, "classSetters");
if (interfaceMemberMap != null) {
@@ -3529,11 +2479,6 @@
ClassMember? getDispatchTarget(Name name, bool isSetter) {
return isSetter ? classSetterMap[name] : classMemberMap[name];
}
-
- static int compareMaxInheritancePath(
- ClassHierarchyNode a, ClassHierarchyNode b) {
- return b.maxInheritancePath.compareTo(a.maxInheritancePath);
- }
}
class ClassHierarchyNodeDataForTesting {
@@ -3547,229 +2492,217 @@
this.mixinApplicationOverrides, this.inheritedImplements);
}
-List<LocatedMessage> _inheritedConflictContext(ClassMember a, ClassMember b) {
- int length = a.fullNameForErrors.length;
- // TODO(ahe): Delete this method when it isn't used by [InterfaceResolver].
- int compare = "${a.fileUri}".compareTo("${b.fileUri}");
- if (compare == 0) {
- compare = a.charOffset.compareTo(b.charOffset);
+class Tuple {
+ final Name name;
+ ClassMember? _declaredMember;
+ ClassMember? _declaredSetter;
+ ClassMember? _mixedInMember;
+ ClassMember? _mixedInSetter;
+ ClassMember? _extendedMember;
+ ClassMember? _extendedSetter;
+ List<ClassMember>? _implementedMembers;
+ List<ClassMember>? _implementedSetters;
+
+ Tuple.declareMember(ClassMember declaredMember)
+ : assert(!declaredMember.forSetter),
+ this._declaredMember = declaredMember,
+ this.name = declaredMember.name;
+
+ Tuple.mixInMember(ClassMember mixedInMember)
+ : assert(!mixedInMember.forSetter),
+ this._mixedInMember = mixedInMember,
+ this.name = mixedInMember.name;
+
+ Tuple.extendMember(ClassMember extendedMember)
+ : assert(!extendedMember.forSetter),
+ this._extendedMember = extendedMember,
+ this.name = extendedMember.name;
+
+ Tuple.implementMember(ClassMember implementedMember)
+ : assert(!implementedMember.forSetter),
+ this.name = implementedMember.name,
+ _implementedMembers = <ClassMember>[implementedMember];
+
+ Tuple.declareSetter(ClassMember declaredSetter)
+ : assert(declaredSetter.forSetter),
+ this._declaredSetter = declaredSetter,
+ this.name = declaredSetter.name;
+
+ Tuple.mixInSetter(ClassMember mixedInSetter)
+ : assert(mixedInSetter.forSetter),
+ this._mixedInSetter = mixedInSetter,
+ this.name = mixedInSetter.name;
+
+ Tuple.extendSetter(ClassMember extendedSetter)
+ : assert(extendedSetter.forSetter),
+ this._extendedSetter = extendedSetter,
+ this.name = extendedSetter.name;
+
+ Tuple.implementSetter(ClassMember implementedSetter)
+ : assert(implementedSetter.forSetter),
+ this.name = implementedSetter.name,
+ _implementedSetters = <ClassMember>[implementedSetter];
+
+ ClassMember? get declaredMember => _declaredMember;
+
+ void set declaredMember(ClassMember? value) {
+ assert(!value!.forSetter);
+ assert(
+ _declaredMember == null,
+ "Declared member already set to $_declaredMember, "
+ "trying to set it to $value.");
+ _declaredMember = value;
}
- ClassMember first;
- ClassMember second;
- if (compare < 0) {
- first = a;
- second = b;
- } else {
- first = b;
- second = a;
+
+ ClassMember? get declaredSetter => _declaredSetter;
+
+ void set declaredSetter(ClassMember? value) {
+ assert(value!.forSetter);
+ assert(
+ _declaredSetter == null,
+ "Declared setter already set to $_declaredSetter, "
+ "trying to set it to $value.");
+ _declaredSetter = value;
}
- return <LocatedMessage>[
- messageInheritedMembersConflictCause1.withLocation(
- first.fileUri, first.charOffset, length),
- messageInheritedMembersConflictCause2.withLocation(
- second.fileUri, second.charOffset, length),
- ];
-}
-class BuilderMixinInferrer extends MixinInferrer {
- final ClassBuilder cls;
+ ClassMember? get extendedMember => _extendedMember;
- BuilderMixinInferrer(
- this.cls, CoreTypes coreTypes, TypeBuilderConstraintGatherer gatherer)
- : super(coreTypes, gatherer);
+ void set extendedMember(ClassMember? value) {
+ assert(!value!.forSetter);
+ assert(
+ _extendedMember == null,
+ "Extended member already set to $_extendedMember, "
+ "trying to set it to $value.");
+ _extendedMember = value;
+ }
- @override
- Supertype? asInstantiationOf(Supertype type, Class superclass) {
- List<DartType>? arguments =
- gatherer.getTypeArgumentsAsInstanceOf(type.asInterfaceType, superclass);
- if (arguments == null) return null;
- return new Supertype(superclass, arguments);
+ ClassMember? get extendedSetter => _extendedSetter;
+
+ void set extendedSetter(ClassMember? value) {
+ assert(value!.forSetter);
+ assert(
+ _extendedSetter == null,
+ "Extended setter already set to $_extendedSetter, "
+ "trying to set it to $value.");
+ _extendedSetter = value;
+ }
+
+ ClassMember? get mixedInMember => _mixedInMember;
+
+ void set mixedInMember(ClassMember? value) {
+ assert(!value!.forSetter);
+ assert(
+ _mixedInMember == null,
+ "Mixed in member already set to $_mixedInMember, "
+ "trying to set it to $value.");
+ _mixedInMember = value;
+ }
+
+ ClassMember? get mixedInSetter => _mixedInSetter;
+
+ void set mixedInSetter(ClassMember? value) {
+ assert(value!.forSetter);
+ assert(
+ _mixedInSetter == null,
+ "Mixed in setter already set to $_mixedInSetter, "
+ "trying to set it to $value.");
+ _mixedInSetter = value;
+ }
+
+ List<ClassMember>? get implementedMembers => _implementedMembers;
+
+ void addImplementedMember(ClassMember value) {
+ assert(!value.forSetter);
+ _implementedMembers ??= <ClassMember>[];
+ _implementedMembers!.add(value);
+ }
+
+ List<ClassMember>? get implementedSetters => _implementedSetters;
+
+ void addImplementedSetter(ClassMember value) {
+ assert(value.forSetter);
+ _implementedSetters ??= <ClassMember>[];
+ _implementedSetters!.add(value);
}
@override
- void reportProblem(Message message, Class kernelClass) {
- int length = cls.isMixinApplication ? 1 : cls.fullNameForErrors.length;
- cls.addProblem(message, cls.charOffset, length);
- }
-}
-
-class TypeBuilderConstraintGatherer extends TypeConstraintGatherer
- with StandardBounds, TypeSchemaStandardBounds {
- @override
- final ClassHierarchyBuilder hierarchy;
-
- TypeBuilderConstraintGatherer(this.hierarchy,
- Iterable<TypeParameter> typeParameters, Library currentLibrary)
- : super.subclassing(typeParameters, currentLibrary);
-
- @override
- CoreTypes get coreTypes => hierarchy.coreTypes;
-
- @override
- void addLowerBound(
- TypeConstraint constraint, DartType lower, Library clientLibrary) {
- constraint.lower =
- getStandardUpperBound(constraint.lower, lower, clientLibrary);
- }
-
- @override
- void addUpperBound(
- TypeConstraint constraint, DartType upper, Library clientLibrary) {
- constraint.upper =
- getStandardLowerBound(constraint.upper, upper, clientLibrary);
- }
-
- @override
- Member? getInterfaceMember(Class class_, Name name, {bool setter: false}) {
- return null;
- }
-
- @override
- InterfaceType getTypeAsInstanceOf(InterfaceType type, Class superclass,
- Library clientLibrary, CoreTypes coreTypes) {
- return hierarchy.getTypeAsInstanceOf(type, superclass, clientLibrary);
- }
-
- @override
- List<DartType>? getTypeArgumentsAsInstanceOf(
- InterfaceType type, Class superclass) {
- return hierarchy.getTypeArgumentsAsInstanceOf(type, superclass);
- }
-
- @override
- InterfaceType futureType(DartType type, Nullability nullability) {
- return new InterfaceType(
- hierarchy.futureClass, nullability, <DartType>[type]);
- }
-
- @override
- bool isSubtypeOf(
- DartType subtype, DartType supertype, SubtypeCheckMode mode) {
- return hierarchy.types.isSubtypeOf(subtype, supertype, mode);
- }
-
- @override
- bool areMutualSubtypes(DartType s, DartType t, SubtypeCheckMode mode) {
- return isSubtypeOf(s, t, mode) && isSubtypeOf(t, s, mode);
- }
-}
-
-abstract class DelayedCheck {
- void check(ClassHierarchyBuilder hierarchy);
-}
-
-class DelayedOverrideCheck implements DelayedCheck {
- final SourceClassBuilder _classBuilder;
- final ClassMember _declaredMember;
- final Set<ClassMember> _overriddenMembers;
-
- DelayedOverrideCheck(
- this._classBuilder, this._declaredMember, this._overriddenMembers);
-
- @override
- void check(ClassHierarchyBuilder hierarchy) {
- Member declaredMember = _declaredMember.getMember(hierarchy);
-
- /// If [_declaredMember] is a class member that is declared in an opt-in
- /// library but inherited to [_classBuilder] through an opt-out class then
- /// we need to apply legacy erasure to the declared type to get the
- /// inherited type.
- ///
- /// For interface members this is handled by member signatures but since
- /// these are abstract they will never be the inherited class member.
- ///
- /// For instance:
- ///
- /// // Opt in:
- /// class Super {
- /// int extendedMethod(int i, {required int j}) => i;
- /// }
- /// class Mixin {
- /// int mixedInMethod(int i, {required int j}) => i;
- /// }
- /// // Opt out:
- /// class Legacy extends Super with Mixin {}
- /// // Opt in:
- /// class Class extends Legacy {
- /// // Valid overrides since the type of `Legacy.extendedMethod` is
- /// // `int* Function(int*, {int* j})`.
- /// int? extendedMethod(int? i, {int? j}) => i;
- /// // Valid overrides since the type of `Legacy.mixedInMethod` is
- /// // `int* Function(int*, {int* j})`.
- /// int? mixedInMethod(int? i, {int? j}) => i;
- /// }
- ///
- bool declaredNeedsLegacyErasure =
- needsLegacyErasure(_classBuilder.cls, declaredMember.enclosingClass!);
- void callback(Member interfaceMember, bool isSetter) {
- _classBuilder.checkOverride(
- hierarchy.types, declaredMember, interfaceMember, isSetter, callback,
- isInterfaceCheck: !_classBuilder.isMixinApplication,
- declaredNeedsLegacyErasure: declaredNeedsLegacyErasure);
+ String toString() {
+ StringBuffer sb = new StringBuffer();
+ String comma = '';
+ sb.write('Tuple(');
+ if (_declaredMember != null) {
+ sb.write(comma);
+ sb.write('declaredMember=');
+ sb.write(_declaredMember);
+ comma = ',';
}
-
- for (ClassMember overriddenMember in _overriddenMembers) {
- callback(overriddenMember.getMember(hierarchy), _declaredMember.isSetter);
+ if (_declaredSetter != null) {
+ sb.write(comma);
+ sb.write('declaredSetter=');
+ sb.write(_declaredSetter);
+ comma = ',';
}
+ if (_mixedInMember != null) {
+ sb.write(comma);
+ sb.write('mixedInMember=');
+ sb.write(_mixedInMember);
+ comma = ',';
+ }
+ if (_mixedInSetter != null) {
+ sb.write(comma);
+ sb.write('mixedInSetter=');
+ sb.write(_mixedInSetter);
+ comma = ',';
+ }
+ if (_extendedMember != null) {
+ sb.write(comma);
+ sb.write('extendedMember=');
+ sb.write(_extendedMember);
+ comma = ',';
+ }
+ if (_extendedSetter != null) {
+ sb.write(comma);
+ sb.write('extendedSetter=');
+ sb.write(_extendedSetter);
+ comma = ',';
+ }
+ if (_implementedMembers != null) {
+ sb.write(comma);
+ sb.write('implementedMembers=');
+ sb.write(_implementedMembers);
+ comma = ',';
+ }
+ if (_implementedSetters != null) {
+ sb.write(comma);
+ sb.write('implementedSetters=');
+ sb.write(_implementedSetters);
+ comma = ',';
+ }
+ sb.write(')');
+ return sb.toString();
}
}
-class DelayedGetterSetterCheck implements DelayedCheck {
- final SourceClassBuilder classBuilder;
- final ClassMember getter;
- final ClassMember setter;
-
- const DelayedGetterSetterCheck(this.classBuilder, this.getter, this.setter);
-
- @override
- void check(ClassHierarchyBuilder hierarchy) {
- classBuilder.checkGetterSetter(hierarchy.types, getter.getMember(hierarchy),
- setter.getMember(hierarchy));
- }
+Set<ClassMember> toSet(
+ ClassBuilder classBuilder, Iterable<ClassMember> members) {
+ Set<ClassMember> result = <ClassMember>{};
+ _toSet(classBuilder, members, result);
+ return result;
}
-class DelayedTypeComputation {
- final ClassHierarchyNodeBuilder builder;
- final ClassMember declaredMember;
- final Set<ClassMember> overriddenMembers;
- bool _computed = false;
-
- DelayedTypeComputation(
- this.builder, this.declaredMember, this.overriddenMembers)
- : assert(declaredMember.isSourceDeclaration);
-
- void compute(ClassHierarchyBuilder hierarchy) {
- if (_computed) return;
- declaredMember.inferType(hierarchy);
- _computed = true;
- if (declaredMember.isField) {
- builder.inferFieldSignature(hierarchy, declaredMember, overriddenMembers);
- } else if (declaredMember.isGetter) {
- builder.inferGetterSignature(
- hierarchy, declaredMember, overriddenMembers);
- } else if (declaredMember.isSetter) {
- builder.inferSetterSignature(
- hierarchy, declaredMember, overriddenMembers);
+void _toSet(ClassBuilder classBuilder, Iterable<ClassMember> members,
+ Set<ClassMember> result) {
+ for (ClassMember member in members) {
+ if (member.hasDeclarations && classBuilder == member.classBuilder) {
+ _toSet(classBuilder, member.declarations, result);
} else {
- builder.inferMethodSignature(
- hierarchy, declaredMember, overriddenMembers);
+ result.add(member);
}
}
-
- @override
- String toString() => 'DelayedTypeComputation('
- '${builder.classBuilder.name},$declaredMember,$overriddenMembers)';
}
-int compareNamedParameters(VariableDeclaration a, VariableDeclaration b) {
- return a.name!.compareTo(b.name!);
-}
-
-void reportCantInferParameterType(
- ClassBuilder cls,
- FormalParameterBuilder parameter,
- ClassHierarchyBuilder hierarchy,
- Iterable<ClassMember> overriddenMembers) {
+void reportCantInferParameterType(ClassBuilder cls,
+ FormalParameterBuilder parameter, Iterable<ClassMember> overriddenMembers) {
String name = parameter.name;
List<LocatedMessage> context = overriddenMembers
.map((ClassMember overriddenMember) {
@@ -3790,7 +2723,7 @@
}
void reportCantInferTypes(ClassBuilder cls, SourceProcedureBuilder member,
- ClassHierarchyBuilder hierarchy, Iterable<ClassMember> overriddenMembers) {
+ Iterable<ClassMember> overriddenMembers) {
String name = member.fullNameForErrors;
List<LocatedMessage> context = overriddenMembers
.map((ClassMember overriddenMember) {
@@ -3811,7 +2744,7 @@
}
void reportCantInferReturnType(ClassBuilder cls, SourceProcedureBuilder member,
- ClassHierarchyBuilder hierarchy, Iterable<ClassMember> overriddenMembers) {
+ Iterable<ClassMember> overriddenMembers) {
String name = member.fullNameForErrors;
List<LocatedMessage> context = overriddenMembers
.map((ClassMember overriddenMember) {
@@ -3899,32 +2832,37 @@
context: context);
}
-ClassBuilder? getClass(TypeBuilder type) {
- Builder? declaration = type.declaration;
- if (declaration is TypeAliasBuilder) {
- TypeAliasBuilder aliasBuilder = declaration;
- NamedTypeBuilder namedBuilder = type as NamedTypeBuilder;
- declaration = aliasBuilder.unaliasDeclaration(namedBuilder.arguments);
+List<LocatedMessage> _inheritedConflictContext(ClassMember a, ClassMember b) {
+ int length = a.fullNameForErrors.length;
+ // TODO(ahe): Delete this method when it isn't used by [InterfaceResolver].
+ int compare = "${a.fileUri}".compareTo("${b.fileUri}");
+ if (compare == 0) {
+ compare = a.charOffset.compareTo(b.charOffset);
}
- return declaration is ClassBuilder ? declaration : null;
+ ClassMember first;
+ ClassMember second;
+ if (compare < 0) {
+ first = a;
+ second = b;
+ } else {
+ first = b;
+ second = a;
+ }
+ return <LocatedMessage>[
+ messageInheritedMembersConflictCause1.withLocation(
+ first.fileUri, first.charOffset, length),
+ messageInheritedMembersConflictCause2.withLocation(
+ second.fileUri, second.charOffset, length),
+ ];
}
-Set<ClassMember> toSet(
- ClassBuilder classBuilder, Iterable<ClassMember> members) {
- Set<ClassMember> result = <ClassMember>{};
- _toSet(classBuilder, members, result);
- return result;
+bool isNameVisibleIn(Name name, LibraryBuilder libraryBuilder) {
+ return !name.isPrivate || name.library == libraryBuilder.library;
}
-void _toSet(ClassBuilder classBuilder, Iterable<ClassMember> members,
- Set<ClassMember> result) {
- for (ClassMember member in members) {
- if (member.hasDeclarations && classBuilder == member.classBuilder) {
- _toSet(classBuilder, member.declarations, result);
- } else {
- result.add(member);
- }
- }
+int compareDeclarations(ClassMember a, ClassMember b) {
+ if (a == b) return 0;
+ return ClassHierarchy.compareNames(a.name, b.name);
}
Set<ClassMember> unfoldDeclarations(Iterable<ClassMember> members) {
@@ -3943,474 +2881,3 @@
}
}
}
-
-abstract class SynthesizedMember extends ClassMember {
- @override
- final ClassBuilder classBuilder;
-
- @override
- final Name name;
-
- @override
- final bool forSetter;
-
- @override
- final bool isProperty;
-
- SynthesizedMember(this.classBuilder, this.name,
- {required this.forSetter, required this.isProperty})
- // ignore: unnecessary_null_comparison
- : assert(forSetter != null),
- // ignore: unnecessary_null_comparison
- assert(isProperty != null);
-
- @override
- List<ClassMember> get declarations => throw new UnimplementedError();
-
- @override
- void inferType(ClassHierarchyBuilder hierarchy) {}
-
- @override
- bool get isAssignable => throw new UnimplementedError();
-
- @override
- bool get isConst => throw new UnimplementedError();
-
- @override
- bool get isDuplicate => false;
-
- @override
- bool get isField => throw new UnimplementedError();
-
- @override
- bool get isFinal => throw new UnimplementedError();
-
- @override
- bool get isGetter => throw new UnimplementedError();
-
- @override
- bool get isInternalImplementation => false;
-
- @override
- bool get isSetter => forSetter;
-
- @override
- bool get isSourceDeclaration => false;
-
- @override
- bool get isStatic => false;
-
- @override
- bool get isSynthesized => true;
-
- @override
- void registerOverrideDependency(Set<ClassMember> overriddenMembers) {}
-}
-
-/// Class member for a set of interface members.
-///
-/// This is used to compute combined member signature of a set of interface
-/// members inherited into the same class, and to insert forwarding stubs,
-/// mixin stubs, and member signatures where needed.
-class SynthesizedInterfaceMember extends SynthesizedMember {
- @override
- final List<ClassMember> declarations;
-
- /// The concrete member in the super class overridden by [declarations], if
- /// any.
- ///
- /// This is used to as the target when creating concrete forwarding and mixin
- /// stub. For instance:
- ///
- /// class Super {
- /// method(int i) {}
- /// }
- /// class Interface {
- /// method(covariant int i) {}
- /// }
- /// class Class extends Super implements Interface {
- /// // Concrete forwarding stub calling [_superClassMember]:
- /// method(covariant int i) => super.method(i);
- ///
- final ClassMember? _superClassMember;
-
- /// The canonical member of the combined member signature if it is known by
- /// construction. The canonical member defines the type of combined member
- /// signature.
- ///
- /// This is used when a declared member is part of a set of implemented
- /// members. For instance
- ///
- /// class Super {
- /// method(int i) {}
- /// }
- /// class Interface {
- /// method(covariant num i) {}
- /// }
- /// class Class implements Interface {
- /// // This member is updated to be a concrete forwarding stub with an
- /// // covariant parameter but with its declared parameter type:
- /// // method(covariant int i) => super.method(i);
- /// method(int i);
- /// }
- final ClassMember? _canonicalMember;
-
- /// The member in [declarations] that is mixed in, if any.
- ///
- /// This is used to create mixin stubs. If the mixed in member is abstract,
- /// an abstract mixin stub is created:
- ///
- /// class Super {
- /// void method() {}
- /// }
- /// class Mixin {
- /// void method();
- /// }
- /// // Abstract mixin stub with `Mixin.method` as target inserted:
- /// // void method();
- /// class Class = Super with Mixin;
- ///
- /// If the mixed in member is concrete, a concrete mixin member is created:
- ///
- /// class Super {
- /// void method() {}
- /// }
- /// class Mixin {
- /// void method() {}
- /// }
- /// // Concrete mixin stub with `Mixin.method` as target inserted:
- /// // void method() => super.method();
- /// class Class = Super with Mixin;
- ///
- /// If a forwarding stub is needed, the created stub will be a possibly
- /// concrete forwarding stub:
- ///
- /// class Super {
- /// void method(int i) {}
- /// }
- /// class Interface {
- /// void method(covariant num i) {}
- /// }
- /// class Mixin {
- /// void method(int i);
- /// }
- /// // Concrete forwarding stub with `Super.method` as target inserted:
- /// // void method(covariant int i) => super.method(i);
- /// class Class = Super with Mixin implements Interface;
- ///
- final ClassMember? _mixedInMember;
-
- /// If `true`, a stub should be inserted, if needed.
- final bool _shouldModifyKernel;
-
- Member? _member;
- Covariance? _covariance;
-
- SynthesizedInterfaceMember(
- ClassBuilder classBuilder, Name name, this.declarations,
- {ClassMember? superClassMember,
- ClassMember? canonicalMember,
- ClassMember? mixedInMember,
- required bool isProperty,
- required bool forSetter,
- required bool shouldModifyKernel})
- : this._superClassMember = superClassMember,
- this._canonicalMember = canonicalMember,
- this._mixedInMember = mixedInMember,
- this._shouldModifyKernel = shouldModifyKernel,
- super(classBuilder, name, isProperty: isProperty, forSetter: forSetter);
-
- @override
- bool get hasDeclarations => true;
-
- void _ensureMemberAndCovariance(ClassHierarchyBuilder hierarchy) {
- if (_member != null) {
- return;
- }
- if (classBuilder.library is! SourceLibraryBuilder) {
- if (_canonicalMember != null) {
- _member = _canonicalMember!.getMember(hierarchy);
- _covariance = _canonicalMember!.getCovariance(hierarchy);
- } else {
- _member = declarations.first.getMember(hierarchy);
- _covariance = declarations.first.getCovariance(hierarchy);
- }
- return;
- }
- CombinedClassMemberSignature combinedMemberSignature;
- if (_canonicalMember != null) {
- combinedMemberSignature = new CombinedClassMemberSignature.internal(
- hierarchy,
- classBuilder as SourceClassBuilder,
- declarations.indexOf(_canonicalMember!),
- declarations,
- forSetter: isSetter);
- } else {
- combinedMemberSignature = new CombinedClassMemberSignature(
- hierarchy, classBuilder as SourceClassBuilder, declarations,
- forSetter: isSetter);
-
- if (combinedMemberSignature.canonicalMember == null) {
- String name = classBuilder.fullNameForErrors;
- int length = classBuilder.isAnonymousMixinApplication ? 1 : name.length;
- List<LocatedMessage> context = declarations.map((ClassMember d) {
- return messageDeclaredMemberConflictsWithOverriddenMembersCause
- .withLocation(
- d.fileUri, d.charOffset, d.fullNameForErrors.length);
- }).toList();
-
- classBuilder.addProblem(
- templateCombinedMemberSignatureFailed.withArguments(
- classBuilder.fullNameForErrors,
- declarations.first.fullNameForErrors),
- classBuilder.charOffset,
- length,
- context: context);
- // TODO(johnniwinther): Maybe we should have an invalid marker to avoid
- // cascading errors.
- _member = declarations.first.getMember(hierarchy);
- _covariance = declarations.first.getCovariance(hierarchy);
- return;
- }
- }
-
- if (_shouldModifyKernel) {
- ProcedureKind kind = ProcedureKind.Method;
- Member canonicalMember =
- combinedMemberSignature.canonicalMember!.getMember(hierarchy);
- if (combinedMemberSignature.canonicalMember!.isProperty) {
- kind = isSetter ? ProcedureKind.Setter : ProcedureKind.Getter;
- } else if (canonicalMember is Procedure &&
- canonicalMember.kind == ProcedureKind.Operator) {
- kind = ProcedureKind.Operator;
- }
-
- Procedure? stub = new ForwardingNode(
- combinedMemberSignature, kind, _superClassMember, _mixedInMember)
- .finalize();
- if (stub != null) {
- assert(classBuilder.cls == stub.enclosingClass);
- assert(stub != canonicalMember);
- classBuilder.cls.addProcedure(stub);
- SourceLibraryBuilder library =
- classBuilder.library as SourceLibraryBuilder;
- if (canonicalMember is Procedure) {
- library.forwardersOrigins
- ..add(stub)
- ..add(canonicalMember);
- }
- _member = stub;
- _covariance = combinedMemberSignature.combinedMemberSignatureCovariance;
- assert(
- _covariance ==
- new Covariance.fromMember(_member!, forSetter: forSetter),
- "Unexpected covariance for combined members signature "
- "$_member. Found $_covariance, expected "
- "${new Covariance.fromMember(_member!, forSetter: forSetter)}.");
- return;
- }
- }
-
- _member = combinedMemberSignature.canonicalMember!.getMember(hierarchy);
- _covariance = combinedMemberSignature.combinedMemberSignatureCovariance;
- }
-
- @override
- Member getMember(ClassHierarchyBuilder hierarchy) {
- _ensureMemberAndCovariance(hierarchy);
- return _member!;
- }
-
- @override
- Covariance getCovariance(ClassHierarchyBuilder hierarchy) {
- _ensureMemberAndCovariance(hierarchy);
- return _covariance!;
- }
-
- @override
- ClassMember get interfaceMember => this;
-
- @override
- bool isObjectMember(ClassBuilder objectClass) {
- return false;
- }
-
- @override
- bool isSameDeclaration(ClassMember other) {
- // TODO(johnniwinther): Optimize this.
- return false;
- }
-
- @override
- int get charOffset => declarations.first.charOffset;
-
- @override
- Uri get fileUri => declarations.first.fileUri;
-
- @override
- bool get isAbstract => true;
-
- @override
- String get fullNameForErrors =>
- declarations.map((ClassMember m) => m.fullName).join("%");
-
- @override
- String get fullName {
- String suffix = isSetter ? "=" : "";
- return "${fullNameForErrors}$suffix";
- }
-
- @override
- String toString() => 'SynthesizedInterfaceMember($classBuilder,$name,'
- '$declarations,forSetter=$forSetter)';
-}
-
-/// Class member for an inherited concrete member that implements an interface
-/// member.
-///
-/// This is used to ensure that both the inherited concrete member and the
-/// interface member is taken into account when computing the resulting [Member]
-/// node.
-///
-/// This is needed because an interface member, though initially abstract, can
-/// result in a concrete stub that overrides the concrete member. For instance
-///
-/// class Super {
-/// method(int i) {}
-/// }
-/// class Interface {
-/// method(covariant int i) {}
-/// }
-/// class Class extends Super implements Interface {
-/// // A concrete forwarding stub is inserted:
-/// method(covariant int i) => super.method(i);
-/// }
-/// class Sub extends Class implements Interface {
-/// // No forwarding stub should be inserted since `Class.method` is
-/// // adequate.
-/// }
-///
-///
-/// Here the create stub `Class.method` overrides `Super.method` and should
-/// be used to determine whether to insert a forwarding stub in subclasses.
-class InheritedClassMemberImplementsInterface extends SynthesizedMember {
- final ClassMember inheritedClassMember;
- final ClassMember implementedInterfaceMember;
-
- Member? _member;
- Covariance? _covariance;
-
- InheritedClassMemberImplementsInterface(ClassBuilder classBuilder, Name name,
- {required this.inheritedClassMember,
- required this.implementedInterfaceMember,
- required bool isProperty,
- required bool forSetter})
- // ignore: unnecessary_null_comparison
- : assert(inheritedClassMember != null),
- // ignore: unnecessary_null_comparison
- assert(implementedInterfaceMember != null),
- super(classBuilder, name, isProperty: isProperty, forSetter: forSetter);
-
- void _ensureMemberAndCovariance(ClassHierarchyBuilder hierarchy) {
- if (_member == null) {
- Member classMember = inheritedClassMember.getMember(hierarchy);
- Member interfaceMember = implementedInterfaceMember.getMember(hierarchy);
- if (!interfaceMember.isAbstract &&
- interfaceMember.enclosingClass == classBuilder.cls) {
- /// The interface member resulted in a concrete stub being inserted.
- /// For instance for `method1` but _not_ for `method2` here:
- ///
- /// class Super {
- /// method1(int i) {}
- /// method2(covariant int i) {}
- /// }
- /// class Interface {
- /// method1(covariant int i) {}
- /// method2(int i) {}
- /// }
- /// class Class extends Super implements Interface {
- /// // A concrete forwarding stub is inserted for `method1` since
- /// // the parameter on `Super.method1` is _not_ marked as
- /// // covariant:
- /// method1(covariant int i) => super.method(i);
- /// // No concrete forwarding stub is inserted for `method2` since
- /// // the parameter on `Super.method2` is already marked as
- /// // covariant.
- /// }
- ///
- /// The inserted stub should be used as the resulting member.
- _member = interfaceMember;
- _covariance = implementedInterfaceMember.getCovariance(hierarchy);
- } else {
- /// The interface member did not result in an inserted stub or the
- /// inserted stub was abstract. For instance:
- ///
- /// // Opt-in:
- /// class Super {
- /// method(int? i) {}
- /// }
- /// // Opt-out:
- /// class Class extends Super {
- /// // An abstract member signature stub is inserted:
- /// method(int* i);
- /// }
- ///
- /// The inserted stub should _not_ be used as the resulting member
- /// since it is abstract and therefore not a class member.
- _member = classMember;
- _covariance = inheritedClassMember.getCovariance(hierarchy);
- }
- }
- }
-
- @override
- Member getMember(ClassHierarchyBuilder hierarchy) {
- _ensureMemberAndCovariance(hierarchy);
- return _member!;
- }
-
- @override
- Covariance getCovariance(ClassHierarchyBuilder hierarchy) {
- _ensureMemberAndCovariance(hierarchy);
- return _covariance!;
- }
-
- @override
- ClassMember get interfaceMember => implementedInterfaceMember;
-
- @override
- bool isObjectMember(ClassBuilder objectClass) {
- return inheritedClassMember.isObjectMember(objectClass);
- }
-
- @override
- bool isSameDeclaration(ClassMember other) {
- // TODO(johnniwinther): Optimize this.
- return false;
- }
-
- @override
- int get charOffset => inheritedClassMember.charOffset;
-
- @override
- Uri get fileUri => inheritedClassMember.fileUri;
-
- @override
- bool get hasDeclarations => false;
-
- @override
- bool get isAbstract => false;
-
- @override
- String get fullNameForErrors => inheritedClassMember.fullNameForErrors;
-
- @override
- String get fullName => inheritedClassMember.fullName;
-
- @override
- String toString() =>
- 'InheritedClassMemberImplementsInterface($classBuilder,$name,'
- 'inheritedClassMember=$inheritedClassMember,'
- 'implementedInterfaceMember=$implementedInterfaceMember,'
- 'forSetter=$forSetter)';
-}
diff --git a/pkg/front_end/lib/src/fasta/kernel/hierarchy/mixin_inferrer.dart b/pkg/front_end/lib/src/fasta/kernel/hierarchy/mixin_inferrer.dart
new file mode 100644
index 0000000..f8974cc
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/kernel/hierarchy/mixin_inferrer.dart
@@ -0,0 +1,103 @@
+// 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.
+
+library fasta.class_hierarchy_builder;
+
+import 'package:kernel/ast.dart';
+import 'package:kernel/core_types.dart' show CoreTypes;
+import 'package:kernel/src/standard_bounds.dart';
+import 'package:kernel/type_environment.dart';
+
+import '../../builder/class_builder.dart';
+import '../../messages.dart' show Message;
+import '../../type_inference/standard_bounds.dart'
+ show TypeSchemaStandardBounds;
+import '../../type_inference/type_constraint_gatherer.dart'
+ show TypeConstraintGatherer;
+import '../../type_inference/type_inferrer.dart' show MixinInferrer;
+import '../../type_inference/type_schema_environment.dart' show TypeConstraint;
+import 'hierarchy_builder.dart';
+
+class BuilderMixinInferrer extends MixinInferrer {
+ final ClassBuilder cls;
+
+ BuilderMixinInferrer(
+ this.cls, CoreTypes coreTypes, TypeBuilderConstraintGatherer gatherer)
+ : super(coreTypes, gatherer);
+
+ @override
+ Supertype? asInstantiationOf(Supertype type, Class superclass) {
+ List<DartType>? arguments =
+ gatherer.getTypeArgumentsAsInstanceOf(type.asInterfaceType, superclass);
+ if (arguments == null) return null;
+ return new Supertype(superclass, arguments);
+ }
+
+ @override
+ void reportProblem(Message message, Class kernelClass) {
+ int length = cls.isMixinApplication ? 1 : cls.fullNameForErrors.length;
+ cls.addProblem(message, cls.charOffset, length);
+ }
+}
+
+class TypeBuilderConstraintGatherer extends TypeConstraintGatherer
+ with StandardBounds, TypeSchemaStandardBounds {
+ @override
+ final ClassHierarchyBuilder hierarchy;
+
+ TypeBuilderConstraintGatherer(this.hierarchy,
+ Iterable<TypeParameter> typeParameters, Library currentLibrary)
+ : super.subclassing(typeParameters, currentLibrary);
+
+ @override
+ CoreTypes get coreTypes => hierarchy.coreTypes;
+
+ @override
+ void addLowerBound(
+ TypeConstraint constraint, DartType lower, Library clientLibrary) {
+ constraint.lower =
+ getStandardUpperBound(constraint.lower, lower, clientLibrary);
+ }
+
+ @override
+ void addUpperBound(
+ TypeConstraint constraint, DartType upper, Library clientLibrary) {
+ constraint.upper =
+ getStandardLowerBound(constraint.upper, upper, clientLibrary);
+ }
+
+ @override
+ Member? getInterfaceMember(Class class_, Name name, {bool setter: false}) {
+ return null;
+ }
+
+ @override
+ InterfaceType getTypeAsInstanceOf(InterfaceType type, Class superclass,
+ Library clientLibrary, CoreTypes coreTypes) {
+ return hierarchy.getTypeAsInstanceOf(type, superclass, clientLibrary);
+ }
+
+ @override
+ List<DartType>? getTypeArgumentsAsInstanceOf(
+ InterfaceType type, Class superclass) {
+ return hierarchy.getTypeArgumentsAsInstanceOf(type, superclass);
+ }
+
+ @override
+ InterfaceType futureType(DartType type, Nullability nullability) {
+ return new InterfaceType(
+ hierarchy.futureClass, nullability, <DartType>[type]);
+ }
+
+ @override
+ bool isSubtypeOf(
+ DartType subtype, DartType supertype, SubtypeCheckMode mode) {
+ return hierarchy.types.isSubtypeOf(subtype, supertype, mode);
+ }
+
+ @override
+ bool areMutualSubtypes(DartType s, DartType t, SubtypeCheckMode mode) {
+ return isSubtypeOf(s, t, mode) && isSubtypeOf(t, s, mode);
+ }
+}
diff --git a/pkg/front_end/lib/src/fasta/scope.dart b/pkg/front_end/lib/src/fasta/scope.dart
index db65cb2..f69cc83 100644
--- a/pkg/front_end/lib/src/fasta/scope.dart
+++ b/pkg/front_end/lib/src/fasta/scope.dart
@@ -14,7 +14,7 @@
import 'builder/name_iterator.dart';
import 'builder/type_variable_builder.dart';
import 'kernel/body_builder.dart' show JumpTarget;
-import 'kernel/class_hierarchy_builder.dart' show ClassMember;
+import 'kernel/hierarchy/class_member.dart' show ClassMember;
import 'kernel/kernel_helper.dart';
import 'util/helpers.dart' show DelayedActionPerformer;
diff --git a/pkg/front_end/lib/src/fasta/source/source_class_builder.dart b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
index a7d6ce8..8873c4e 100644
--- a/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
@@ -5,7 +5,8 @@
library fasta.source_class_builder;
import 'package:kernel/ast.dart';
-import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
+import 'package:kernel/class_hierarchy.dart'
+ show ClassHierarchy, ClassHierarchyMembers;
import 'package:kernel/reference_from_index.dart' show IndexedClass;
import 'package:kernel/src/bounds_checks.dart';
import 'package:kernel/src/legacy_erasure.dart';
@@ -1002,8 +1003,13 @@
return count;
}
- void checkOverride(Types types, Member declaredMember, Member interfaceMember,
- bool isSetter, callback(Member interfaceMember, bool isSetter),
+ void checkOverride(
+ Types types,
+ ClassHierarchyMembers memberHierarchy,
+ Member declaredMember,
+ Member interfaceMember,
+ bool isSetter,
+ callback(Member interfaceMember, bool isSetter),
{required bool isInterfaceCheck,
required bool declaredNeedsLegacyErasure}) {
// ignore: unnecessary_null_comparison
@@ -1031,7 +1037,8 @@
isInterfaceCheck,
declaredNeedsLegacyErasure);
if (seenCovariant) {
- handleSeenCovariant(types, interfaceMember, isSetter, callback);
+ handleSeenCovariant(
+ memberHierarchy, interfaceMember, isSetter, callback);
}
} else if (declaredMember.kind == ProcedureKind.Getter) {
checkGetterOverride(
@@ -1050,7 +1057,8 @@
isInterfaceCheck,
declaredNeedsLegacyErasure);
if (seenCovariant) {
- handleSeenCovariant(types, interfaceMember, isSetter, callback);
+ handleSeenCovariant(
+ memberHierarchy, interfaceMember, isSetter, callback);
}
} else {
assert(
@@ -1090,7 +1098,8 @@
isInterfaceCheck,
declaredNeedsLegacyErasure);
if (seenCovariant) {
- handleSeenCovariant(types, interfaceMember, isSetter, callback);
+ handleSeenCovariant(
+ memberHierarchy, interfaceMember, isSetter, callback);
}
}
}
diff --git a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
index cf7b0ba..3689325 100644
--- a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
@@ -80,7 +80,7 @@
import '../import.dart' show Import;
-import '../kernel/class_hierarchy_builder.dart';
+import '../kernel/hierarchy/members_builder.dart';
import '../kernel/constructor_tearoff_lowering.dart';
import '../kernel/implicit_field_type.dart';
import '../kernel/internal_ast.dart';
@@ -4294,7 +4294,7 @@
checkUncheckedTypedefTypes(typeEnvironment);
}
- void computeShowHideElements(ClassHierarchyBuilder hierarchy) {
+ void computeShowHideElements(ClassMembersBuilder membersBuilder) {
assert(currentTypeParameterScopeBuilder.kind ==
TypeParameterScopeKind.library);
for (SourceExtensionBuilder extensionBuilder
@@ -4306,8 +4306,9 @@
new ExtensionTypeShowHideClause();
// TODO(dmitryas): Handle private names.
- List<Supertype> supertypes =
- hierarchy.getNodeFromClass(onType.classNode).superclasses;
+ List<Supertype> supertypes = membersBuilder.hierarchyBuilder
+ .getNodeFromClass(onType.classNode)
+ .superclasses;
Map<String, Supertype> supertypesByName = <String, Supertype>{};
for (Supertype supertype in supertypes) {
// TODO(dmitryas): Should only non-generic supertypes be allowed?
@@ -4317,7 +4318,7 @@
// Handling elements of the 'show' clause.
for (String memberOrTypeName in extensionBuilder
.extensionTypeShowHideClauseBuilder.shownMembersOrTypes) {
- Member? getableMember = hierarchy.getInterfaceMember(
+ Member? getableMember = membersBuilder.getInterfaceMember(
onType.classNode, new Name(memberOrTypeName));
if (getableMember != null) {
if (getableMember is Field) {
@@ -4330,7 +4331,7 @@
getableMember.kind == ProcedureKind.Method) {
showHideClause.shownMethods.add(getableMember.reference);
}
- Member? setableMember = hierarchy.getInterfaceMember(
+ Member? setableMember = membersBuilder.getInterfaceMember(
onType.classNode, new Name(memberOrTypeName),
setter: true);
if (setableMember != null) {
@@ -4357,7 +4358,7 @@
}
for (String getterName in extensionBuilder
.extensionTypeShowHideClauseBuilder.shownGetters) {
- Member? member = hierarchy.getInterfaceMember(
+ Member? member = membersBuilder.getInterfaceMember(
onType.classNode, new Name(getterName));
if (member != null) {
if (member is Field) {
@@ -4373,7 +4374,7 @@
}
for (String setterName in extensionBuilder
.extensionTypeShowHideClauseBuilder.shownSetters) {
- Member? member = hierarchy.getInterfaceMember(
+ Member? member = membersBuilder.getInterfaceMember(
onType.classNode, new Name(setterName),
setter: true);
if (member != null) {
@@ -4394,7 +4395,7 @@
}
for (Operator operator in extensionBuilder
.extensionTypeShowHideClauseBuilder.shownOperators) {
- Member? member = hierarchy.getInterfaceMember(
+ Member? member = membersBuilder.getInterfaceMember(
onType.classNode, new Name(operatorToString(operator)));
if (member != null) {
showHideClause.shownOperators.add(member.reference);
@@ -4409,7 +4410,7 @@
// Handling elements of the 'hide' clause.
for (String memberOrTypeName in extensionBuilder
.extensionTypeShowHideClauseBuilder.hiddenMembersOrTypes) {
- Member? getableMember = hierarchy.getInterfaceMember(
+ Member? getableMember = membersBuilder.getInterfaceMember(
onType.classNode, new Name(memberOrTypeName));
if (getableMember != null) {
if (getableMember is Field) {
@@ -4422,7 +4423,7 @@
getableMember.kind == ProcedureKind.Method) {
showHideClause.hiddenMethods.add(getableMember.reference);
}
- Member? setableMember = hierarchy.getInterfaceMember(
+ Member? setableMember = membersBuilder.getInterfaceMember(
onType.classNode, new Name(memberOrTypeName),
setter: true);
if (setableMember != null) {
@@ -4450,7 +4451,7 @@
}
for (String getterName in extensionBuilder
.extensionTypeShowHideClauseBuilder.hiddenGetters) {
- Member? member = hierarchy.getInterfaceMember(
+ Member? member = membersBuilder.getInterfaceMember(
onType.classNode, new Name(getterName));
if (member != null) {
if (member is Field) {
@@ -4466,7 +4467,7 @@
}
for (String setterName in extensionBuilder
.extensionTypeShowHideClauseBuilder.hiddenSetters) {
- Member? member = hierarchy.getInterfaceMember(
+ Member? member = membersBuilder.getInterfaceMember(
onType.classNode, new Name(setterName),
setter: true);
if (member != null) {
@@ -4487,7 +4488,7 @@
}
for (Operator operator in extensionBuilder
.extensionTypeShowHideClauseBuilder.hiddenOperators) {
- Member? member = hierarchy.getInterfaceMember(
+ Member? member = membersBuilder.getInterfaceMember(
onType.classNode, new Name(operatorToString(operator)));
if (member != null) {
showHideClause.hiddenOperators.add(member.reference);
diff --git a/pkg/front_end/lib/src/fasta/source/source_loader.dart b/pkg/front_end/lib/src/fasta/source/source_loader.dart
index 4043a0a4..5568bb4 100644
--- a/pkg/front_end/lib/src/fasta/source/source_loader.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_loader.dart
@@ -63,7 +63,10 @@
import '../export.dart' show Export;
import '../fasta_codes.dart';
import '../kernel/body_builder.dart' show BodyBuilder;
-import '../kernel/class_hierarchy_builder.dart';
+import '../kernel/hierarchy/class_member.dart';
+import '../kernel/hierarchy/delayed.dart';
+import '../kernel/hierarchy/hierarchy_builder.dart';
+import '../kernel/hierarchy/members_builder.dart';
import '../kernel/kernel_helper.dart'
show SynthesizedFunctionNode, TypeDependency;
import '../kernel/kernel_target.dart' show KernelTarget;
@@ -101,7 +104,9 @@
final Map<Uri, List<int>> sourceBytes = <Uri, List<int>>{};
- ClassHierarchyBuilder? _builderHierarchy;
+ ClassHierarchyBuilder? _hierarchyBuilder;
+
+ ClassMembersBuilder? _membersBuilder;
ReferenceFromIndex? referenceFromIndex;
@@ -676,7 +681,9 @@
TypeInferenceEngineImpl get typeInferenceEngine => _typeInferenceEngine!;
- ClassHierarchyBuilder get builderHierarchy => _builderHierarchy!;
+ ClassHierarchyBuilder get hierarchyBuilder => _hierarchyBuilder!;
+
+ ClassMembersBuilder get membersBuilder => _membersBuilder!;
Template<SummaryTemplate> get outlineSummaryTemplate =>
templateSourceOutlineSummary;
@@ -1724,7 +1731,7 @@
for (LibraryBuilder libraryBuilder in libraryBuilders) {
if (libraryBuilder.loader == this &&
libraryBuilder is SourceLibraryBuilder) {
- libraryBuilder.computeShowHideElements(_builderHierarchy!);
+ libraryBuilder.computeShowHideElements(membersBuilder);
}
}
ticker.logMs("Computed show and hide elements");
@@ -1781,9 +1788,9 @@
}
void checkOverrides(List<SourceClassBuilder> sourceClasses) {
- List<DelayedCheck> overrideChecks = builderHierarchy.takeDelayedChecks();
+ List<DelayedCheck> overrideChecks = membersBuilder.takeDelayedChecks();
for (int i = 0; i < overrideChecks.length; i++) {
- overrideChecks[i].check(builderHierarchy);
+ overrideChecks[i].check(membersBuilder);
}
ticker.logMs("Checked ${overrideChecks.length} overrides");
@@ -1793,10 +1800,10 @@
void checkAbstractMembers(List<SourceClassBuilder> sourceClasses) {
List<ClassMember> delayedMemberChecks =
- builderHierarchy.takeDelayedMemberComputations();
+ membersBuilder.takeDelayedMemberComputations();
Set<Class> changedClasses = new Set<Class>();
for (int i = 0; i < delayedMemberChecks.length; i++) {
- delayedMemberChecks[i].getMember(builderHierarchy);
+ delayedMemberChecks[i].getMember(membersBuilder);
changedClasses.add(delayedMemberChecks[i].classBuilder.cls);
}
ticker.logMs(
@@ -1888,9 +1895,13 @@
void buildClassHierarchy(
List<SourceClassBuilder> sourceClasses, ClassBuilder objectClass) {
- _builderHierarchy = ClassHierarchyBuilder.build(
- objectClass, sourceClasses, this, coreTypes);
- typeInferenceEngine.hierarchyBuilder = builderHierarchy;
+ ClassHierarchyBuilder hierarchyBuilder = _hierarchyBuilder =
+ ClassHierarchyBuilder.build(
+ objectClass, sourceClasses, this, coreTypes);
+ ClassMembersBuilder membersBuilder = _membersBuilder =
+ ClassMembersBuilder.build(hierarchyBuilder, sourceClasses);
+ typeInferenceEngine.hierarchyBuilder = hierarchyBuilder;
+ typeInferenceEngine.membersBuilder = membersBuilder;
ticker.logMs("Built class hierarchy");
}
@@ -1904,7 +1915,7 @@
/// might be subject to type inference, and records dependencies between
/// them.
typeInferenceEngine.prepareTopLevel(coreTypes, hierarchy);
- builderHierarchy.computeTypes();
+ membersBuilder.computeTypes();
List<FieldBuilder> allImplicitlyTypedFields = <FieldBuilder>[];
for (LibraryBuilder library in libraryBuilders) {
@@ -2130,7 +2141,8 @@
void releaseAncillaryResources() {
hierarchy = null;
- _builderHierarchy = null;
+ _hierarchyBuilder = null;
+ _membersBuilder = null;
_typeInferenceEngine = null;
_builders.clear();
libraries.clear();
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart
index 2194bf5..b14927c 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart
@@ -19,7 +19,8 @@
import '../kernel/forest.dart';
import '../kernel/implicit_field_type.dart';
import '../kernel/internal_ast.dart';
-import '../kernel/class_hierarchy_builder.dart' show ClassHierarchyBuilder;
+import '../kernel/hierarchy/hierarchy_builder.dart' show ClassHierarchyBuilder;
+import '../kernel/hierarchy/members_builder.dart' show ClassMembersBuilder;
import '../kernel/kernel_helper.dart';
import '../source/source_library_builder.dart' show SourceLibraryBuilder;
@@ -103,6 +104,8 @@
late ClassHierarchyBuilder hierarchyBuilder;
+ late ClassMembersBuilder membersBuilder;
+
late CoreTypes coreTypes;
// TODO(johnniwinther): Shared this with the BodyBuilder.
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
index 93e1544..5dc515a 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
@@ -35,7 +35,7 @@
import '../fasta_codes.dart';
-import '../kernel/class_hierarchy_builder.dart' show ClassMember;
+import '../kernel/hierarchy/class_member.dart' show ClassMember;
import '../kernel/constructor_tearoff_lowering.dart';
import '../kernel/kernel_helper.dart';
import '../kernel/inference_visitor.dart';
@@ -4250,7 +4250,7 @@
Member? _getInterfaceMember(
Class class_, Name name, bool setter, int charOffset) {
- ClassMember? classMember = engine.hierarchyBuilder
+ ClassMember? classMember = engine.membersBuilder
.getInterfaceClassMember(class_, name, setter: setter);
if (classMember != null) {
if (classMember.isStatic) {
@@ -4266,7 +4266,7 @@
classMember = null;
}
}
- Member? member = classMember?.getMember(engine.hierarchyBuilder);
+ Member? member = classMember?.getMember(engine.membersBuilder);
if (member == null && library.isPatch) {
// TODO(johnniwinther): Injected members are currently not included
// in the class hierarchy builder.
diff --git a/pkg/front_end/test/class_hierarchy/class_hierarchy_test.dart b/pkg/front_end/test/class_hierarchy/class_hierarchy_test.dart
index 4acaf78..76f3281 100644
--- a/pkg/front_end/test/class_hierarchy/class_hierarchy_test.dart
+++ b/pkg/front_end/test/class_hierarchy/class_hierarchy_test.dart
@@ -8,7 +8,11 @@
import 'package:_fe_analyzer_shared/src/testing/id_testing.dart';
import 'package:front_end/src/testing/id_testing_helper.dart';
import 'package:front_end/src/testing/id_testing_utils.dart';
-import 'package:front_end/src/fasta/kernel/class_hierarchy_builder.dart';
+import 'package:front_end/src/fasta/kernel/hierarchy/class_member.dart';
+import 'package:front_end/src/fasta/kernel/hierarchy/hierarchy_builder.dart';
+import 'package:front_end/src/fasta/kernel/hierarchy/hierarchy_node.dart';
+import 'package:front_end/src/fasta/kernel/hierarchy/members_builder.dart';
+import 'package:front_end/src/fasta/kernel/hierarchy/members_node.dart';
import 'package:front_end/src/testing/id_extractor.dart';
import 'package:kernel/ast.dart';
import 'package:kernel/core_types.dart';
@@ -99,17 +103,20 @@
CoreTypes get _coreTypes => _compilerResult.coreTypes!;
ClassHierarchyBuilder get _classHierarchyBuilder =>
- _compilerResult.kernelTargetForTesting!.loader.builderHierarchy;
+ _compilerResult.kernelTargetForTesting!.loader.hierarchyBuilder;
+
+ ClassMembersBuilder get _classMembersBuilder =>
+ _compilerResult.kernelTargetForTesting!.loader.membersBuilder;
@override
void computeForClass(Class node) {
super.computeForClass(node);
- ClassHierarchyNode classHierarchyNode =
- _classHierarchyBuilder.getNodeFromClass(node);
- ClassHierarchyNodeDataForTesting data = classHierarchyNode.dataForTesting!;
+ ClassMembersNode classMembersNode =
+ _classMembersBuilder.getNodeFromClass(node);
+ ClassHierarchyNodeDataForTesting data = classMembersNode.dataForTesting!;
void addMember(ClassMember classMember,
{required bool isSetter, required bool isClassMember}) {
- Member member = classMember.getMember(_classHierarchyBuilder);
+ Member member = classMember.getMember(_classMembersBuilder);
Member memberOrigin = member.memberSignatureOrigin ?? member;
if (memberOrigin.enclosingClass == _coreTypes.objectClass) {
return;
@@ -179,13 +186,13 @@
features.add(Tag.abstractForwardingStub);
features[Tag.type] = procedureType(member);
features[Tag.covariance] =
- classMember.getCovariance(_classHierarchyBuilder).toString();
+ classMember.getCovariance(_classMembersBuilder).toString();
break;
case ProcedureStubKind.ConcreteForwardingStub:
features.add(Tag.concreteForwardingStub);
features[Tag.type] = procedureType(member);
features[Tag.covariance] =
- classMember.getCovariance(_classHierarchyBuilder).toString();
+ classMember.getCovariance(_classMembersBuilder).toString();
features[Tag.stubTarget] = memberQualifiedName(member.stubTarget!);
break;
case ProcedureStubKind.NoSuchMethodForwarder:
@@ -195,7 +202,7 @@
features.add(Tag.memberSignature);
features[Tag.type] = procedureType(member);
features[Tag.covariance] =
- classMember.getCovariance(_classHierarchyBuilder).toString();
+ classMember.getCovariance(_classMembersBuilder).toString();
break;
case ProcedureStubKind.AbstractMixinStub:
features.add(Tag.abstractMixinStub);
@@ -211,23 +218,23 @@
id, features, member);
}
- classHierarchyNode.classMemberMap
+ classMembersNode.classMemberMap
.forEach((Name name, ClassMember classMember) {
addMember(classMember, isSetter: false, isClassMember: true);
});
- classHierarchyNode.classSetterMap
+ classMembersNode.classSetterMap
.forEach((Name name, ClassMember classMember) {
addMember(classMember, isSetter: true, isClassMember: true);
});
- classHierarchyNode.interfaceMemberMap
+ classMembersNode.interfaceMemberMap
?.forEach((Name name, ClassMember classMember) {
- if (!identical(classMember, classHierarchyNode.classMemberMap[name])) {
+ if (!identical(classMember, classMembersNode.classMemberMap[name])) {
addMember(classMember, isSetter: false, isClassMember: false);
}
});
- classHierarchyNode.interfaceSetterMap
+ classMembersNode.interfaceSetterMap
?.forEach((Name name, ClassMember classMember) {
- if (!identical(classMember, classHierarchyNode.classSetterMap[name])) {
+ if (!identical(classMember, classMembersNode.classSetterMap[name])) {
addMember(classMember, isSetter: true, isClassMember: false);
}
});
@@ -238,7 +245,9 @@
Features features = new Features();
ClassHierarchyNode classHierarchyNode =
_classHierarchyBuilder.getNodeFromClass(node);
- ClassHierarchyNodeDataForTesting data = classHierarchyNode.dataForTesting!;
+ ClassMembersNode classMembersNode =
+ _classMembersBuilder.getNodeFromClass(node);
+ ClassHierarchyNodeDataForTesting data = classMembersNode.dataForTesting!;
classHierarchyNode.superclasses.forEach((Supertype supertype) {
features.addElement(Tag.superclasses, supertypeToText(supertype));
});
@@ -253,7 +262,7 @@
}
features[Tag.maxInheritancePath] =
'${classHierarchyNode.maxInheritancePath}';
- if (classHierarchyNode.hasNoSuchMethod) {
+ if (classMembersNode.hasNoSuchMethod) {
features.add(Tag.hasNoSuchMethod);
}
return features;
diff --git a/pkg/front_end/test/fasta/testing/suite.dart b/pkg/front_end/test/fasta/testing/suite.dart
index 3bbed42..5121e9a 100644
--- a/pkg/front_end/test/fasta/testing/suite.dart
+++ b/pkg/front_end/test/fasta/testing/suite.dart
@@ -66,12 +66,12 @@
import 'package:front_end/src/fasta/incremental_compiler.dart'
show IncrementalCompiler;
-import 'package:front_end/src/fasta/kernel/class_hierarchy_builder.dart'
- show ClassHierarchyNode;
-
-import 'package:front_end/src/fasta/kernel/class_hierarchy_builder.dart'
+import 'package:front_end/src/fasta/kernel/hierarchy/hierarchy_builder.dart'
show ClassHierarchyBuilder;
+import 'package:front_end/src/fasta/kernel/hierarchy/hierarchy_node.dart'
+ show ClassHierarchyNode;
+
import 'package:front_end/src/fasta/kernel/kernel_target.dart'
show KernelTarget;
@@ -2148,7 +2148,7 @@
Uri uri =
component.uriToSource.keys.firstWhere((uri) => uri.scheme == "file");
KernelTarget target = result.sourceTarget;
- ClassHierarchyBuilder hierarchy = target.loader.builderHierarchy;
+ ClassHierarchyBuilder hierarchy = target.loader.hierarchyBuilder;
StringBuffer sb = new StringBuffer();
for (ClassHierarchyNode node in hierarchy.nodes.values) {
sb.writeln(node);
diff --git a/pkg/front_end/test/fasta/types/dill_hierachy_test.dart b/pkg/front_end/test/fasta/types/dill_hierarchy_test.dart
similarity index 86%
rename from pkg/front_end/test/fasta/types/dill_hierachy_test.dart
rename to pkg/front_end/test/fasta/types/dill_hierarchy_test.dart
index cf2e491..55076d6 100644
--- a/pkg/front_end/test/fasta/types/dill_hierachy_test.dart
+++ b/pkg/front_end/test/fasta/types/dill_hierarchy_test.dart
@@ -29,7 +29,7 @@
import "package:front_end/src/fasta/dill/dill_target.dart" show DillTarget;
-import "package:front_end/src/fasta/kernel/class_hierarchy_builder.dart"
+import "package:front_end/src/fasta/kernel/hierarchy/hierarchy_builder.dart"
show ClassHierarchyBuilder;
import "package:front_end/src/fasta/ticker.dart" show Ticker;
@@ -38,65 +38,41 @@
Object:
superclasses:
interfaces:
- classMembers:
- classSetters:
A:
superclasses:
Object
interfaces:
- classMembers:
- classSetters:
B:
Longest path to Object: 2
superclasses:
Object
interfaces: A
- classMembers:
- classSetters:
- interfaceMembers:
- interfaceSetters:
C:
Longest path to Object: 2
superclasses:
Object
interfaces: A
- classMembers:
- classSetters:
- interfaceMembers:
- interfaceSetters:
D:
Longest path to Object: 3
superclasses:
Object
interfaces: B<T>, A, C<U>
- classMembers:
- classSetters:
- interfaceMembers:
- interfaceSetters:
E:
Longest path to Object: 4
superclasses:
Object
interfaces: D<int,double>, B<int>, A, C<double>
- classMembers:
- classSetters:
- interfaceMembers:
- interfaceSetters:
F:
Longest path to Object: 4
superclasses:
Object
interfaces: D<int,bool>, B<int>, A, C<bool>
- classMembers:
- classSetters:
- interfaceMembers:
- interfaceSetters:
""";
void main() {
diff --git a/pkg/front_end/test/fasta/types/fasta_legacy_upper_bound_test.dart b/pkg/front_end/test/fasta/types/fasta_legacy_upper_bound_test.dart
index cc4493a..618c014 100644
--- a/pkg/front_end/test/fasta/types/fasta_legacy_upper_bound_test.dart
+++ b/pkg/front_end/test/fasta/types/fasta_legacy_upper_bound_test.dart
@@ -20,7 +20,7 @@
import "package:front_end/src/fasta/dill/dill_target.dart" show DillTarget;
-import "package:front_end/src/fasta/kernel/class_hierarchy_builder.dart"
+import "package:front_end/src/fasta/kernel/hierarchy/hierarchy_builder.dart"
show ClassHierarchyBuilder;
import "package:front_end/src/fasta/ticker.dart" show Ticker;
diff --git a/pkg/front_end/test/fasta/types/fasta_types_test.dart b/pkg/front_end/test/fasta/types/fasta_types_test.dart
index ecff945..55095c7 100644
--- a/pkg/front_end/test/fasta/types/fasta_types_test.dart
+++ b/pkg/front_end/test/fasta/types/fasta_types_test.dart
@@ -29,7 +29,7 @@
import "package:front_end/src/fasta/dill/dill_target.dart" show DillTarget;
-import "package:front_end/src/fasta/kernel/class_hierarchy_builder.dart"
+import "package:front_end/src/fasta/kernel/hierarchy/hierarchy_builder.dart"
show ClassHierarchyBuilder;
import "package:front_end/src/fasta/ticker.dart" show Ticker;
diff --git a/pkg/front_end/test/fasta/types/subtypes_benchmark.dart b/pkg/front_end/test/fasta/types/subtypes_benchmark.dart
index d3c0a09..165313e 100644
--- a/pkg/front_end/test/fasta/types/subtypes_benchmark.dart
+++ b/pkg/front_end/test/fasta/types/subtypes_benchmark.dart
@@ -34,7 +34,7 @@
import "package:front_end/src/fasta/dill/dill_target.dart" show DillTarget;
-import "package:front_end/src/fasta/kernel/class_hierarchy_builder.dart"
+import "package:front_end/src/fasta/kernel/hierarchy/hierarchy_builder.dart"
show ClassHierarchyBuilder;
import "package:front_end/src/fasta/ticker.dart" show Ticker;
diff --git a/pkg/front_end/test/id_tests/inheritance_test.dart b/pkg/front_end/test/id_tests/inheritance_test.dart
index 11dc8bc..78f9bf5 100644
--- a/pkg/front_end/test/id_tests/inheritance_test.dart
+++ b/pkg/front_end/test/id_tests/inheritance_test.dart
@@ -7,7 +7,8 @@
import 'package:_fe_analyzer_shared/src/testing/id.dart';
import 'package:_fe_analyzer_shared/src/testing/id_testing.dart';
import 'package:front_end/src/api_prototype/experimental_flags.dart';
-import 'package:front_end/src/fasta/kernel/class_hierarchy_builder.dart';
+import 'package:front_end/src/fasta/kernel/hierarchy/hierarchy_builder.dart';
+import 'package:front_end/src/fasta/kernel/hierarchy/hierarchy_node.dart';
import 'package:front_end/src/testing/id_extractor.dart';
import 'package:front_end/src/testing/id_testing_helper.dart';
import 'package:front_end/src/testing/id_testing_utils.dart';
@@ -95,7 +96,7 @@
CoreTypes get _coreTypes => _compilerResult.coreTypes!;
ClassHierarchyBuilder get _classHierarchyBuilder =>
- _compilerResult.kernelTargetForTesting!.loader.builderHierarchy;
+ _compilerResult.kernelTargetForTesting!.loader.hierarchyBuilder;
@override
String computeLibraryValue(Id id, Library node) {
diff --git a/pkg/kernel/lib/class_hierarchy.dart b/pkg/kernel/lib/class_hierarchy.dart
index 43368ec..e231e8f 100644
--- a/pkg/kernel/lib/class_hierarchy.dart
+++ b/pkg/kernel/lib/class_hierarchy.dart
@@ -38,17 +38,6 @@
List<DartType>? getTypeArgumentsAsInstanceOf(
InterfaceType type, Class superclass);
- /// Returns the possibly abstract interface member of [class_] with the given
- /// [name].
- ///
- /// If [setter] is `false`, only fields, methods, and getters with that name
- /// will be found. If [setter] is `true`, only non-final fields and setters
- /// will be found.
- ///
- /// If multiple members with that name are inherited and not overridden, the
- /// member from the first declared supertype is returned.
- Member? getInterfaceMember(Class class_, Name name, {bool setter: false});
-
/// Returns the least upper bound of two interface types, as defined by Dart
/// 1.0.
///
@@ -68,8 +57,22 @@
InterfaceType type1, InterfaceType type2, Library clientLibrary);
}
+abstract class ClassHierarchyMembers {
+ /// Returns the possibly abstract interface member of [class_] with the given
+ /// [name].
+ ///
+ /// If [setter] is `false`, only fields, methods, and getters with that name
+ /// will be found. If [setter] is `true`, only non-final fields and setters
+ /// will be found.
+ ///
+ /// If multiple members with that name are inherited and not overridden, the
+ /// member from the first declared supertype is returned.
+ Member? getInterfaceMember(Class class_, Name name, {bool setter: false});
+}
+
/// Interface for answering various subclassing queries.
-abstract class ClassHierarchy implements ClassHierarchyBase {
+abstract class ClassHierarchy
+ implements ClassHierarchyBase, ClassHierarchyMembers {
factory ClassHierarchy(Component component, CoreTypes coreTypes,
{HandleAmbiguousSupertypes? onAmbiguousSupertypes,
MixinInferrer? mixinInferrer}) {
diff --git a/pkg/kernel/lib/src/hierarchy_based_type_environment.dart b/pkg/kernel/lib/src/hierarchy_based_type_environment.dart
index 65894ac..15812bf 100644
--- a/pkg/kernel/lib/src/hierarchy_based_type_environment.dart
+++ b/pkg/kernel/lib/src/hierarchy_based_type_environment.dart
@@ -6,7 +6,7 @@
import '../ast.dart' show Class, DartType, InterfaceType, Library, Member, Name;
-import '../class_hierarchy.dart' show ClassHierarchyBase;
+import '../class_hierarchy.dart' show ClassHierarchy;
import '../core_types.dart' show CoreTypes;
@@ -14,7 +14,7 @@
class HierarchyBasedTypeEnvironment extends TypeEnvironment {
@override
- final ClassHierarchyBase hierarchy;
+ final ClassHierarchy hierarchy;
HierarchyBasedTypeEnvironment(CoreTypes coreTypes, this.hierarchy)
: super.fromSubclass(coreTypes, hierarchy);
diff --git a/pkg/kernel/lib/type_environment.dart b/pkg/kernel/lib/type_environment.dart
index 5320daf..a67f7ea 100644
--- a/pkg/kernel/lib/type_environment.dart
+++ b/pkg/kernel/lib/type_environment.dart
@@ -26,6 +26,9 @@
return new HierarchyBasedTypeEnvironment(coreTypes, hierarchy);
}
+ @override
+ ClassHierarchy get hierarchy;
+
Class get intClass => coreTypes.intClass;
Class get numClass => coreTypes.numClass;
Class get functionClass => coreTypes.functionClass;
diff --git a/pkg/vm/lib/transformations/type_flow/transformer.dart b/pkg/vm/lib/transformations/type_flow/transformer.dart
index 1868a4d..aa9af8f 100644
--- a/pkg/vm/lib/transformations/type_flow/transformer.dart
+++ b/pkg/vm/lib/transformations/type_flow/transformer.dart
@@ -315,13 +315,7 @@
Constant? constantValue;
bool isInt = false;
- // Note: the explicit type `bool` is needed because the checked-in version
- // of the CFE that we use for bootstrapping doesn't yet have constructor
- // tearoffs enabled, and the fix for bug
- // https://github.com/dart-lang/language/issues/1785 only takes effect when
- // constructor tearoffs are enabled. TODO(paulberry): remove the type after
- // the bootstrap CFE enables constructor tearoffs.
- final bool nullable = type is NullableType;
+ final nullable = type is NullableType;
if (nullable) {
type = type.baseType;
}
diff --git a/pkg/vm/pubspec.yaml b/pkg/vm/pubspec.yaml
index 3ae9534..4086172 100644
--- a/pkg/vm/pubspec.yaml
+++ b/pkg/vm/pubspec.yaml
@@ -4,7 +4,7 @@
publish_to: none
environment:
- sdk: '>=2.12.0 <3.0.0'
+ sdk: '>=2.15.0 <3.0.0'
dependencies:
args: ^2.0.0
diff --git a/sdk/lib/collection/collections.dart b/sdk/lib/collection/collections.dart
index 9b43996..1137f52 100644
--- a/sdk/lib/collection/collections.dart
+++ b/sdk/lib/collection/collections.dart
@@ -8,6 +8,17 @@
///
/// The source of the elements may be a [List] or any [Iterable] with
/// efficient [Iterable.length] and [Iterable.elementAt].
+///
+/// ```dart
+/// final numbers = <int>[10, 20, 30];
+/// final unmodifiableListView = UnmodifiableListView(numbers);
+///
+/// // Insert new elements into the original list.
+/// numbers.addAll([40, 50]);
+/// print(unmodifiableListView); // [10, 20, 30, 40, 50]
+///
+/// unmodifiableListView.remove(20); // Throws.
+/// ```
class UnmodifiableListView<E> extends UnmodifiableListBase<E> {
final Iterable<E> _source;
diff --git a/sdk/lib/collection/maps.dart b/sdk/lib/collection/maps.dart
index b0ab270..b8673b1 100644
--- a/sdk/lib/collection/maps.dart
+++ b/sdk/lib/collection/maps.dart
@@ -200,7 +200,7 @@
/// Basic implementation of an unmodifiable [Map].
///
/// This class has a basic implementation of all but two of the members of
-/// an umodifiable [Map].
+/// an unmodifiable [Map].
/// A simple unmodifiable `Map` class can be implemented by extending this
/// class and implementing `keys` and `operator[]`.
///
@@ -376,6 +376,17 @@
/// A wrapper around a `Map` that forwards all members to the map provided in
/// the constructor, except for operations that modify the map.
/// Modifying operations throw instead.
+///
+/// ```dart
+/// final baseMap = <int, String>{1: 'Mars', 2: 'Mercury', 3: 'Venus'};
+/// final unmodifiableMapView = UnmodifiableMapView(baseMap);
+///
+/// // Remove an entry from the original map.
+/// baseMap.remove(3);
+/// print(unmodifiableMapView); // {1: Mars, 2: Mercury}
+///
+/// unmodifiableMapView.remove(1); // Throws.
+/// ```
class UnmodifiableMapView<K, V> extends MapView<K, V>
with _UnmodifiableMapMixin<K, V> {
UnmodifiableMapView(Map<K, V> map) : super(map);
diff --git a/sdk/lib/collection/set.dart b/sdk/lib/collection/set.dart
index 81ca0a8..f59b56d 100644
--- a/sdk/lib/collection/set.dart
+++ b/sdk/lib/collection/set.dart
@@ -400,6 +400,17 @@
///
/// Methods that could change the set, such as [add] and [remove],
/// must not be called.
+///
+/// ```dart
+/// final baseSet = <String>{'Mars', 'Mercury', 'Earth', 'Venus'};
+/// final unmodifiableSetView = UnmodifiableSetView(baseSet);
+///
+/// // Remove an element from the original set.
+/// baseSet.remove('Venus');
+/// print(unmodifiableSetView); // {Mars, Mercury, Earth}
+///
+/// unmodifiableSetView.remove('Earth'); // Throws.
+/// ```
@Since("2.12")
class UnmodifiableSetView<E> extends SetBase<E> with _UnmodifiableSetMixin<E> {
final Set<E> _source;
diff --git a/sdk/lib/core/date_time.dart b/sdk/lib/core/date_time.dart
index 2281fd8..0bd6884 100644
--- a/sdk/lib/core/date_time.dart
+++ b/sdk/lib/core/date_time.dart
@@ -9,94 +9,111 @@
/// DateTimes can represent time values that are at a distance of at most
/// 100,000,000 days from epoch (1970-01-01 UTC): -271821-04-20 to 275760-09-13.
///
-/// Create a DateTime object by using one of the constructors
+/// Create a `DateTime` object by using one of the constructors
/// or by parsing a correctly formatted string,
/// which complies with a subset of ISO 8601.
-/// Note that hours are specified between 0 and 23,
+/// **Note:** hours are specified between 0 and 23,
/// as in a 24-hour clock.
-/// For example:
///
+/// For example:
/// ```dart
-/// var now = DateTime.now();
-/// var berlinWallFell = DateTime.utc(1989, 11, 9);
-/// var moonLanding = DateTime.parse("1969-07-20 20:18:04Z"); // 8:18pm
+/// final now = DateTime.now();
+/// final berlinWallFell = DateTime.utc(1989, 11, 9);
+/// final moonLanding = DateTime.parse('1969-07-20 20:18:04Z'); // 8:18pm
/// ```
///
-/// A DateTime object is anchored either in the UTC time zone
+/// A `DateTime` object is anchored either in the UTC time zone
/// or in the local time zone of the current computer
/// when the object is created.
///
/// Once created, neither the value nor the time zone
-/// of a DateTime object may be changed.
+/// of a `DateTime` object may be changed.
///
/// You can use properties to get
-/// the individual units of a DateTime object.
-///
-/// ```dart
-/// assert(berlinWallFell.month == 11);
-/// assert(moonLanding.hour == 20);
+/// the individual units of a `DateTime` object.
/// ```
-///
+/// print(berlinWallFell.year); // 1989
+/// print(berlinWallFell.month); // 11
+/// print(berlinWallFell.day); // 9
+/// print(moonLanding.hour); // 20
+/// print(moonLanding.minute); // 18
+/// ```
/// For convenience and readability,
-/// the DateTime class provides a constant for each day and month
+/// the `DateTime` class provides a constant for each `day` and `month`
/// name - for example, [august] and [friday].
/// You can use these constants to improve code readability:
-///
/// ```dart
-/// var berlinWallFell = DateTime.utc(1989, DateTime.november, 9);
+/// final berlinWallFell = DateTime.utc(1989, DateTime.november, 9);
+/// print(DateTime.november); // 11
+/// assert(berlinWallFell.month == DateTime.november);
/// assert(berlinWallFell.weekday == DateTime.thursday);
/// ```
///
-/// Day and month values begin at 1, and the week starts on Monday.
+/// `Day` and `month` values begin at 1, and the week starts on `Monday`.
/// That is, the constants [january] and [monday] are both 1.
///
/// ## Working with UTC and local time
///
-/// A DateTime object is in the local time zone
+/// A `DateTime` object is in the local time zone
/// unless explicitly created in the UTC time zone.
+/// Use [isUtc] to determine whether a `DateTime` object is based in UTC.
///
/// ```dart
-/// var dDay = DateTime.utc(1944, 6, 6);
-/// ```
+/// final dDay = DateTime.utc(1944, 6, 6);
+/// print(dDay.isUtc); // true
///
-/// Use [isUtc] to determine whether a DateTime object is based in UTC.
+/// final dDayLocal = DateTime(1944, 6, 6);
+/// print(dDayLocal.isUtc); // false
+/// ```
/// Use the methods [toLocal] and [toUtc]
/// to get the equivalent date/time value specified in the other time zone.
+/// ```
+/// final localDay = dDay.toLocal(); // e.g. 1944-06-06 02:00:00.000
+/// print(localDay.isUtc); // false
+///
+/// final utcFromLocal = localDay.toUtc(); // 1944-06-06 00:00:00.000Z
+/// print(utcFromLocal.isUtc); // true
+/// ```
/// Use [timeZoneName] to get an abbreviated name of the time zone
-/// for the DateTime object.
+/// for the `DateTime` object.
+/// ```
+/// print(dDay.timeZoneName); // UTC
+/// print(localDay.timeZoneName); // e.g. EET
+/// ```
/// To find the difference
-/// between UTC and the time zone of a DateTime object
+/// between UTC and the time zone of a `DateTime` object
/// call [timeZoneOffset].
+/// ```
+/// print(dDay.timeZoneOffset); // 0:00:00.000000
+/// print(localDay.timeZoneOffset); // e.g. 2:00:00.000000
+/// ```
///
/// ## Comparing DateTime objects
///
-/// The DateTime class contains several handy methods,
-/// such as [isAfter], [isBefore], and [isAtSameMomentAs],
-/// for comparing DateTime objects.
-///
-/// ```dart
-/// assert(berlinWallFell.isAfter(moonLanding) == true);
-/// assert(berlinWallFell.isBefore(moonLanding) == false);
+/// The `DateTime` class contains methods for comparing `DateTime`s
+/// chronologically, such as [isAfter], [isBefore], and [isAtSameMomentAs].
+/// ```
+/// print(berlinWallFell.isAfter(moonLanding)); // true
+/// print(berlinWallFell.isBefore(moonLanding)); // false
+/// print(dDay.isAtSameMomentAs(localDay)); // true
/// ```
///
/// ## Using DateTime with Duration
///
/// Use the [add] and [subtract] methods with a [Duration] object
-/// to create a DateTime object based on another.
-/// For example, to find the date that is sixty days (24 * 60 hours) after today,
-/// write:
-///
+/// to create a `DateTime` object based on another.
+/// For example, to find the point in time that is 36 hours after now,
+/// you can write:
/// ```dart
-/// var now = DateTime.now();
-/// var sixtyDaysFromNow = now.add(const Duration(days: 60));
+/// final now = DateTime.now();
+/// final later = now.add(const Duration(hours: 36));
/// ```
///
-/// To find out how much time is between two DateTime objects use
+/// To find out how much time is between two `DateTime` objects use
/// [difference], which returns a [Duration] object:
-///
-/// ```dart
-/// var difference = berlinWallFell.difference(moonLanding);
-/// assert(difference.inDays == 7416);
+/// ```
+/// final difference = berlinWallFell.difference(moonLanding);
+/// print(difference.inDays); // 7416
/// ```
///
/// The difference between two dates in different time zones
@@ -111,13 +128,11 @@
///
/// ## Other resources
///
-/// See [Duration] to represent a span of time.
-/// See [Stopwatch] to measure timespans.
-///
-/// The DateTime class does not provide internationalization.
-/// To internationalize your code, use
-/// the [intl](https://pub.dev/packages/intl) package.
-///
+/// * See [Duration] to represent a span of time.
+/// * See [Stopwatch] to measure timespans.
+/// * The `DateTime` class does not provide internationalization.
+/// To internationalize your code, use
+/// the [intl](https://pub.dev/packages/intl) package.
class DateTime implements Comparable<DateTime> {
// Weekday constants that are returned by [weekday] method:
static const int monday = 1;
@@ -154,20 +169,22 @@
/// True if this [DateTime] is set to UTC time.
///
/// ```dart
- /// var dDay = DateTime.utc(1944, 6, 6);
- /// assert(dDay.isUtc);
- /// ```
+ /// final dDay = DateTime.utc(1944, 6, 6);
+ /// print(dDay.isUtc); // true
///
+ /// final local = DateTime(1944, 6, 6);
+ /// print(local.isUtc); // false
+ /// ```
final bool isUtc;
/// Constructs a [DateTime] instance specified in the local time zone.
///
/// For example,
- /// to create a DateTime object representing the 7th of September 2017,
+ /// to create a `DateTime` object representing the 7th of September 2017,
/// 5:30pm
///
/// ```dart
- /// var dentistAppointment = DateTime(2017, 9, 7, 17, 30);
+ /// final dentistAppointment = DateTime(2017, 9, 7, 17, 30);
/// ```
DateTime(int year,
[int month = 1,
@@ -183,10 +200,10 @@
/// Constructs a [DateTime] instance specified in the UTC time zone.
///
/// ```dart
- /// var moonLanding = DateTime.utc(1969, 7, 20, 20, 18, 04);
+ /// final moonLanding = DateTime.utc(1969, 7, 20, 20, 18, 04);
/// ```
///
- /// When dealing with dates or historic events prefer to use UTC DateTimes,
+ /// When dealing with dates or historic events, preferably use UTC DateTimes,
/// since they are unaffected by daylight-saving changes and are unaffected
/// by the local timezone.
DateTime.utc(int year,
@@ -204,7 +221,7 @@
/// local time zone.
///
/// ```dart
- /// var thisInstant = DateTime.now();
+ /// final now = DateTime.now();
/// ```
DateTime.now() : this._now();
@@ -212,7 +229,7 @@
///
/// Throws a [FormatException] if the input string cannot be parsed.
///
- /// The function parses a subset of ISO 8601
+ /// The function parses a subset of ISO 8601,
/// which includes the subset accepted by RFC 3339.
///
/// The accepted inputs are currently:
@@ -233,7 +250,7 @@
/// possibly separated from the previous by a space.
/// The time zone is either 'z' or 'Z', or it is a signed two digit hour
/// part and an optional two digit minute part. The sign must be either
- /// "+" or "-", and can not be omitted.
+ /// "+" or "-", and cannot be omitted.
/// The minutes may be separated from the hours by a ':'.
/// Examples: "Z", "-10", "+01:30", "+1130".
///
@@ -354,23 +371,33 @@
/// The constructed [DateTime] represents
/// 1970-01-01T00:00:00Z + [millisecondsSinceEpoch] ms in the given
/// time zone (local or UTC).
+ /// ```dart
+ /// final newYearsDay =
+ /// DateTime.fromMillisecondsSinceEpoch(1640979000000, isUtc:true);
+ /// print(newYearsDay); // 2022-01-01 10:00:00.000Z
+ /// ```
external DateTime.fromMillisecondsSinceEpoch(int millisecondsSinceEpoch,
{bool isUtc = false});
/// Constructs a new [DateTime] instance
/// with the given [microsecondsSinceEpoch].
///
- /// If [isUtc] is false then the date is in the local time zone.
+ /// If [isUtc] is false, then the date is in the local time zone.
///
/// The constructed [DateTime] represents
/// 1970-01-01T00:00:00Z + [microsecondsSinceEpoch] us in the given
/// time zone (local or UTC).
+ /// ```dart
+ /// final newYearsEve =
+ /// DateTime.fromMicrosecondsSinceEpoch(1640901600000000, isUtc:true);
+ /// print(newYearsEve); // 2021-12-31 19:30:00.000Z
+ /// ```
external DateTime.fromMicrosecondsSinceEpoch(int microsecondsSinceEpoch,
{bool isUtc = false});
/// Constructs a new [DateTime] instance with the given value.
///
- /// If [isUtc] is false then the date is in the local time zone.
+ /// If [isUtc] is false, then the date is in the local time zone.
DateTime._withValue(this._value, {required this.isUtc}) {
if (millisecondsSinceEpoch.abs() > _maxMillisecondsSinceEpoch ||
(millisecondsSinceEpoch.abs() == _maxMillisecondsSinceEpoch &&
@@ -386,11 +413,12 @@
/// same time zone (UTC or local).
///
/// ```dart
- /// var dDayUtc = DateTime.utc(1944, 6, 6);
- /// var dDayLocal = dDayUtc.toLocal();
+ /// final dDayUtc = DateTime.utc(1944, 6, 6);
+ /// final dDayLocal = dDayUtc.toLocal();
///
/// // These two dates are at the same moment, but are in different zones.
/// assert(dDayUtc != dDayLocal);
+ /// print(dDayUtc != dDayLocal); // true
/// ```
///
/// See [isAtSameMomentAs] for a comparison that compares moments in time
@@ -403,17 +431,17 @@
/// of whether the time is in UTC or in the local time zone.
///
/// ```dart
- /// var now = DateTime.now();
- /// var earlier = now.subtract(const Duration(seconds: 5));
- /// assert(earlier.isBefore(now));
- /// assert(!now.isBefore(now));
+ /// final now = DateTime.now();
+ /// final earlier = now.subtract(const Duration(seconds: 5));
+ /// print(earlier.isBefore(now)); // true
+ /// print(!now.isBefore(now)); // true
///
/// // This relation stays the same, even when changing timezones.
- /// assert(earlier.isBefore(now.toUtc()));
- /// assert(earlier.toUtc().isBefore(now));
+ /// print(earlier.isBefore(now.toUtc())); // true
+ /// print(earlier.toUtc().isBefore(now)); // true
///
- /// assert(!now.toUtc().isBefore(now));
- /// assert(!now.isBefore(now.toUtc()));
+ /// print(!now.toUtc().isBefore(now)); // true
+ /// print(!now.isBefore(now.toUtc())); // true
/// ```
external bool isBefore(DateTime other);
@@ -423,17 +451,17 @@
/// of whether the time is in UTC or in the local time zone.
///
/// ```dart
- /// var now = DateTime.now();
- /// var later = now.add(const Duration(seconds: 5));
- /// assert(later.isAfter(now));
- /// assert(!now.isBefore(now));
+ /// final now = DateTime.now();
+ /// final later = now.add(const Duration(seconds: 5));
+ /// print(later.isAfter(now)); // true
+ /// print(!now.isBefore(now)); // true
///
/// // This relation stays the same, even when changing timezones.
- /// assert(later.isAfter(now.toUtc()));
- /// assert(later.toUtc().isAfter(now));
+ /// print(later.isAfter(now.toUtc())); // true
+ /// print(later.toUtc().isAfter(now)); // true
///
- /// assert(!now.toUtc().isAfter(now));
- /// assert(!now.isAfter(now.toUtc()));
+ /// print(!now.toUtc().isAfter(now)); // true
+ /// print(!now.isAfter(now.toUtc())); // true
/// ```
external bool isAfter(DateTime other);
@@ -443,26 +471,38 @@
/// time zone.
///
/// ```dart
- /// var now = DateTime.now();
- /// var later = now.add(const Duration(seconds: 5));
- /// assert(!later.isAtSameMomentAs(now));
- /// assert(now.isAtSameMomentAs(now));
+ /// final now = DateTime.now();
+ /// final later = now.add(const Duration(seconds: 5));
+ /// print(!later.isAtSameMomentAs(now)); // true
+ /// print(now.isAtSameMomentAs(now)); // true
///
/// // This relation stays the same, even when changing timezones.
- /// assert(!later.isAtSameMomentAs(now.toUtc()));
- /// assert(!later.toUtc().isAtSameMomentAs(now));
+ /// print(!later.isAtSameMomentAs(now.toUtc())); // true
+ /// print(!later.toUtc().isAtSameMomentAs(now)); // true
///
- /// assert(now.toUtc().isAtSameMomentAs(now));
- /// assert(now.isAtSameMomentAs(now.toUtc()));
+ /// print(now.toUtc().isAtSameMomentAs(now)); // true
+ /// print(now.isAtSameMomentAs(now.toUtc())); // true
/// ```
external bool isAtSameMomentAs(DateTime other);
/// Compares this DateTime object to [other],
/// returning zero if the values are equal.
///
- /// Returns a negative value if this DateTime [isBefore] [other]. It returns 0
- /// if it [isAtSameMomentAs] [other], and returns a positive value otherwise
- /// (when this [isAfter] [other]).
+ /// A [compareTo] function returns:
+ /// * a negative value if this DateTime [isBefore] [other].
+ /// * `0` if this DateTime [isAtSameMomentAs] [other], and
+ /// * a positive value otherwise (when this DateTime [isAfter] [other]).
+ ///
+ /// ```dart
+ /// final now = DateTime.now();
+ /// final future = now.add(const Duration(days: 2));
+ /// final past = now.subtract(const Duration(days: 2));
+ /// final newDate = now.toUtc();
+ ///
+ /// print(now.compareTo(future)); // -1
+ /// print(now.compareTo(past)); // 1
+ /// print(now.compareTo(newDate)); // 0
+ /// ```
external int compareTo(DateTime other);
int get hashCode => (_value ^ (_value >> 30)) & 0x3FFFFFFF;
@@ -569,6 +609,11 @@
/// 0, then this part is omitted.
///
/// The resulting string can be parsed back using [parse].
+ /// ```dart
+ /// final moonLanding = DateTime.utc(1969, 7, 20, 20, 18, 04);
+ /// final isoDate = moonLanding.toIso8601String();
+ /// print(isoDate); // 1969-07-20T20:18:04.000Z
+ /// ```
String toIso8601String() {
String y =
(year >= -9999 && year <= 9999) ? _fourDigits(year) : _sixDigits(year);
@@ -589,8 +634,8 @@
/// Returns a new [DateTime] instance with [duration] added to [this].
///
/// ```dart
- /// var today = DateTime.now();
- /// var fiftyDaysFromNow = today.add(const Duration(days: 50));
+ /// final today = DateTime.now();
+ /// final fiftyDaysFromNow = today.add(const Duration(days: 50));
/// ```
///
/// Notice that the duration being added is actually 50 * 24 * 60 * 60
@@ -604,8 +649,8 @@
/// Returns a new [DateTime] instance with [duration] subtracted from [this].
///
/// ```dart
- /// DateTime today = DateTime.now();
- /// DateTime fiftyDaysAgo = today.subtract(const Duration(days: 50));
+ /// final today = DateTime.now();
+ /// final fiftyDaysAgo = today.subtract(const Duration(days: 50));
/// ```
///
/// Notice that the duration being subtracted is actually 50 * 24 * 60 * 60
@@ -622,11 +667,11 @@
/// The returned [Duration] will be negative if [other] occurs after [this].
///
/// ```dart
- /// var berlinWallFell = DateTime.utc(1989, DateTime.november, 9);
- /// var dDay = DateTime.utc(1944, DateTime.june, 6);
+ /// final berlinWallFell = DateTime.utc(1989, DateTime.november, 9);
+ /// final dDay = DateTime.utc(1944, DateTime.june, 6);
///
- /// Duration difference = berlinWallFell.difference(dDay);
- /// assert(difference.inDays == 16592);
+ /// final difference = berlinWallFell.difference(dDay);
+ /// print(difference.inDays); // 16592
/// ```
///
/// The difference is measured in seconds and fractions of seconds.
@@ -639,9 +684,10 @@
/// For example, in Australia, similar code using local time instead of UTC:
///
/// ```dart
- /// var berlinWallFell = DateTime(1989, DateTime.november, 9);
- /// var dDay = DateTime(1944, DateTime.june, 6);
- /// Duration difference = berlinWallFell.difference(dDay);
+ /// final berlinWallFell = DateTime(1989, DateTime.november, 9);
+ /// final dDay = DateTime(1944, DateTime.june, 6);
+ /// final difference = berlinWallFell.difference(dDay);
+ /// print(difference.inDays); // 16591
/// assert(difference.inDays == 16592);
/// ```
/// will fail because the difference is actually 16591 days and 23 hours, and
@@ -707,21 +753,39 @@
/// Note, that JavaScript, Python and C return the difference between UTC and
/// local time. Java, C# and Ruby return the difference between local time and
/// UTC.
+ ///
+ /// For example, using local time in San Francisco, United States:
+ /// ```dart
+ /// final dateUS = DateTime.parse('2021-11-01 20:18:04Z').toLocal();
+ /// print(dateUS); // 2021-11-01 13:18:04.000
+ /// print(dateUS.timeZoneName); // PDT ( Pacific Daylight Time )
+ /// print(dateUS.timeZoneOffset.inHours); // -7
+ /// print(dateUS.timeZoneOffset.inMinutes); // -420
+ /// ```
+ ///
+ /// For example, using local time in Canberra, Australia:
+ /// ```dart
+ /// final dateAus = DateTime.parse('2021-11-01 20:18:04Z').toLocal();
+ /// print(dateAus); // 2021-11-02 07:18:04.000
+ /// print(dateAus.timeZoneName); // AEDT ( Australian Eastern Daylight Time )
+ /// print(dateAus.timeZoneOffset.inHours); // 11
+ /// print(dateAus.timeZoneOffset.inMinutes); // 660
+ /// ```
external Duration get timeZoneOffset;
/// The year.
///
/// ```dart
- /// var moonLanding = DateTime.parse("1969-07-20 20:18:04Z");
- /// assert(moonLanding.year == 1969);
+ /// final moonLanding = DateTime.parse('1969-07-20 20:18:04Z');
+ /// print(moonLanding.year); // 1969
/// ```
external int get year;
/// The month `[1..12]`.
///
/// ```dart
- /// var moonLanding = DateTime.parse("1969-07-20 20:18:04Z");
- /// assert(moonLanding.month == 7);
+ /// final moonLanding = DateTime.parse('1969-07-20 20:18:04Z');
+ /// print(moonLanding.month); // 7
/// assert(moonLanding.month == DateTime.july);
/// ```
external int get month;
@@ -729,48 +793,48 @@
/// The day of the month `[1..31]`.
///
/// ```dart
- /// var moonLanding = DateTime.parse("1969-07-20 20:18:04Z");
- /// assert(moonLanding.day == 20);
+ /// final moonLanding = DateTime.parse('1969-07-20 20:18:04Z');
+ /// print(moonLanding.day); // 20
/// ```
external int get day;
/// The hour of the day, expressed as in a 24-hour clock `[0..23]`.
///
/// ```dart
- /// var moonLanding = DateTime.parse("1969-07-20 20:18:04Z");
- /// assert(moonLanding.hour == 20);
+ /// final moonLanding = DateTime.parse('1969-07-20 20:18:04Z');
+ /// print(moonLanding.hour); // 20
/// ```
external int get hour;
/// The minute `[0...59]`.
///
/// ```dart
- /// var moonLanding = DateTime.parse("1969-07-20 20:18:04Z");
- /// assert(moonLanding.minute == 18);
+ /// final moonLanding = DateTime.parse('1969-07-20 20:18:04Z');
+ /// print(moonLanding.minute); // 18
/// ```
external int get minute;
/// The second `[0...59]`.
///
/// ```dart
- /// var moonLanding = DateTime.parse("1969-07-20 20:18:04Z");
- /// assert(moonLanding.second == 4);
+ /// final moonLanding = DateTime.parse('1969-07-20 20:18:04Z');
+ /// print(moonLanding.second); // 4
/// ```
external int get second;
/// The millisecond `[0...999]`.
///
/// ```dart
- /// var moonLanding = DateTime.parse("1969-07-20 20:18:04Z");
- /// assert(moonLanding.millisecond == 0);
+ /// final date = DateTime.parse('1970-01-01 05:01:01.234567Z');
+ /// print(date.millisecond); // 234
/// ```
external int get millisecond;
/// The microsecond `[0...999]`.
///
/// ```dart
- /// var moonLanding = DateTime.parse("1969-07-20 20:18:04Z");
- /// assert(moonLanding.microsecond == 0);
+ /// final date = DateTime.parse('1970-01-01 05:01:01.234567Z');
+ /// print(date.microsecond); // 567
/// ```
external int get microsecond;
@@ -780,8 +844,8 @@
/// a week starts with Monday, which has the value 1.
///
/// ```dart
- /// var moonLanding = DateTime.parse("1969-07-20 20:18:04Z");
- /// assert(moonLanding.weekday == 7);
+ /// final moonLanding = DateTime.parse('1969-07-20 20:18:04Z');
+ /// print(moonLanding.weekday); // 7
/// assert(moonLanding.weekday == DateTime.sunday);
/// ```
external int get weekday;
diff --git a/sdk/lib/core/map.dart b/sdk/lib/core/map.dart
index 164b6f2..f6c6caf 100644
--- a/sdk/lib/core/map.dart
+++ b/sdk/lib/core/map.dart
@@ -51,6 +51,11 @@
/// A `LinkedHashMap` requires the keys to implement compatible
/// `operator==` and `hashCode`.
/// It iterates in key insertion order.
+ /// ```dart
+ /// final planets = <num, String>{1: 'Mercury', 2: 'Venus', 3: 'Earth', 4: 'Mars'};
+ /// final mapFrom = Map<int, String>.from(planets);
+ /// print(mapFrom); // {1: Mercury, 2: Venus, 3: Earth, 4: Mars}
+ /// ```
factory Map.from(Map other) = LinkedHashMap<K, V>.from;
/// Creates a [LinkedHashMap] with the same keys and values as [other].
@@ -58,6 +63,11 @@
/// A `LinkedHashMap` requires the keys to implement compatible
/// `operator==` and `hashCode`, and it allows `null` as a key.
/// It iterates in key insertion order.
+ /// ```dart
+ /// final planets = <int, String>{1: 'Mercury', 2: 'Venus', 3: 'Earth'};
+ /// final mapOf = Map<num, String>.of(planets);
+ /// print(mapOf); // {1: Mercury, 2: Venus, 3: Earth}
+ /// ```
factory Map.of(Map<K, V> other) = LinkedHashMap<K, V>.of;
/// Creates an unmodifiable hash-based map containing the entries of [other].
@@ -72,6 +82,11 @@
///
/// The resulting map behaves like the result of [Map.from],
/// except that the map returned by this constructor is not modifiable.
+ /// ```dart
+ /// final planets = <int, String>{1: 'Mercury', 2: 'Venus', 3: 'Earth'};
+ /// final unmodifiableMap = Map.unmodifiable(planets);
+ /// unmodifiableMap[4] = 'Mars'; // Throws
+ /// ```
external factory Map.unmodifiable(Map<dynamic, dynamic> other);
/// Creates an identity map with the default implementation, [LinkedHashMap].
@@ -100,11 +115,11 @@
/// The keys of `map` are the `list` values converted to strings,
/// and the values of the `map` are the squares of the `list` values:
/// ```dart
- /// List<int> list = [1, 2, 3];
- /// var map = Map<String, int>.fromIterable(list,
+ /// final numbers = <int>[1, 2, 3];
+ /// final map = Map<String, int>.fromIterable(numbers,
/// key: (item) => item.toString(),
/// value: (item) => item * item);
- /// // map is {"1": 1, "2": 4, "3": 9}
+ /// print(map); // {1: 1, 2: 4, 3: 9}
/// ```
/// If no values are specified for [key] and [value],
/// the default is the identity function.
@@ -114,8 +129,9 @@
/// In the following example, the keys and corresponding values of `map`
/// are the `list` values directly:
/// ```dart
- /// var map = Map<int, int>.fromIterable(list);
- /// // map is {1: 1, 2: 2, 3: 3}
+ /// final numbers = <int>[1, 2, 3];
+ /// final map = Map.fromIterable(numbers);
+ /// print(map); // {1: 1, 2: 2, 3: 3}
/// ```
/// The keys computed by the source [iterable] do not need to be unique.
/// The last occurrence of a key will overwrite
@@ -134,10 +150,10 @@
/// The map construction iterates over [keys] and [values] simultaneously,
/// and adds an entry to the map for each pair of key and value.
/// ```dart
- /// List<String> letters = ['b', 'c'];
- /// List<String> words = ['bad', 'cat'];
- /// var map = Map.fromIterables(letters, words);
- /// // map is {"b": "bad", "c": "cat"}
+ /// final rings = <bool>[false, false, true, true];
+ /// final planets = <String>{'Earth', 'Mars', 'Jupiter', 'Saturn'};
+ /// final map = Map<String, bool>.fromIterables(planets, rings);
+ /// print(map); // {Earth: false, Mars: false, Jupiter: true, Saturn: true}
/// ```
/// If [keys] contains the same object multiple times,
/// the value of the last occurrence overwrites any previous value.
@@ -183,6 +199,12 @@
/// ```dart
/// <K, V>{for (var e in entries) e.key: e.value}
/// ```
+ /// Example:
+ /// ```dart
+ /// final moonCount = <String, int>{'Mercury': 0, 'Venus': 0, 'Earth': 1,
+ /// 'Mars': 2, 'Jupiter': 79, 'Saturn': 82, 'Uranus': 27, 'Neptune': 14};
+ /// final map = Map.fromEntries(moonCount.entries);
+ /// ```
factory Map.fromEntries(Iterable<MapEntry<K, V>> entries) =>
<K, V>{}..addEntries(entries);
@@ -211,12 +233,24 @@
///
/// Returns true if any of the values in the map are equal to `value`
/// according to the `==` operator.
+ /// ```dart
+ /// final moonCount = <String, int>{'Mercury': 0, 'Venus': 0, 'Earth': 1,
+ /// 'Mars': 2, 'Jupiter': 79, 'Saturn': 82, 'Uranus': 27, 'Neptune': 14 };
+ /// final moons3 = moonCount.containsValue(3); // false
+ /// final moons82 = moonCount.containsValue(82); // true
+ /// ```
bool containsValue(Object? value);
/// Whether this map contains the given [key].
///
/// Returns true if any of the keys in the map are equal to `key`
/// according to the equality used by the map.
+ /// ```dart
+ /// final moonCount = <String, int>{'Mercury': 0, 'Venus': 0, 'Earth': 1,
+ /// 'Mars': 2, 'Jupiter': 79, 'Saturn': 82, 'Uranus': 27, 'Neptune': 14 };
+ /// final containsUranus = moonCount.containsKey('Uranus'); // true
+ /// final containsPluto = moonCount.containsKey('Pluto'); // false
+ /// ```
bool containsKey(Object? key);
/// The value for the given [key], or `null` if [key] is not in the map.
@@ -248,6 +282,17 @@
///
/// The operation is equivalent to doing `this[entry.key] = entry.value`
/// for each [MapEntry] of the iterable.
+ /// ```dart
+ /// final planets = <int, String>{1: 'Mercury', 2: 'Venus',
+ /// 3: 'Earth', 4: 'Mars'};
+ /// final gasGiants = <int, String>{5: 'Jupiter', 6: 'Saturn'};
+ /// final iceGiants = <int, String>{7: 'Uranus', 8: 'Neptune'};
+ /// planets.addEntries(gasGiants.entries);
+ /// planets.addEntries(iceGiants.entries);
+ /// print(planets);
+ /// // {1: Mercury, 2: Venus, 3: Earth, 4: Mars, 5: Jupiter, 6: Saturn,
+ /// // 7: Uranus, 8: Neptune}
+ /// ```
void addEntries(Iterable<MapEntry<K, V>> newEntries);
/// Updates the value for the provided [key].
@@ -261,15 +306,38 @@
/// and adds the key with the returned value to the map.
///
/// If the key is not present, [ifAbsent] must be provided.
+ /// ```dart
+ /// final planetsFromSun = <int, String>{1: 'Mercury', 2: 'unknown',
+ /// 3: 'Earth'};
+ /// // Update value for known key value 2.
+ /// planetsFromSun.update(2, (value) => 'Venus');
+ /// print(planetsFromSun); // {1: Mercury, 2: Venus, 3: Earth}
+ ///
+ /// final largestPlanets = <int, String>{1: 'Jupiter', 2: 'Saturn',
+ /// 3: 'Neptune'};
+ /// // Key value 8 is missing from list, add it using [ifAbsent].
+ /// largestPlanets.update(8, (value) => 'New', ifAbsent: () => 'Mercury');
+ /// print(largestPlanets); // {1: Jupiter, 2: Saturn, 3: Neptune, 8: Mercury}
+ /// ```
V update(K key, V update(V value), {V ifAbsent()?});
/// Updates all values.
///
/// Iterates over all entries in the map and updates them with the result
/// of invoking [update].
+ /// ```dart
+ /// final terrestrial = <int, String>{1: 'Mercury', 2: 'Venus', 3: 'Earth'};
+ /// terrestrial.updateAll((key, value) => value.toUpperCase());
+ /// print(terrestrial); // {1: MERCURY, 2: VENUS, 3: EARTH}
+ /// ```
void updateAll(V update(K key, V value));
/// Removes all entries of this map that satisfy the given [test].
+ /// ```dart
+ /// final terrestrial = <int, String>{1: 'Mercury', 2: 'Venus', 3: 'Earth'};
+ /// terrestrial.removeWhere((key, value) => value.startsWith('E'));
+ /// print(terrestrial); // {1: Mercury, 2: Venus}
+ /// ```
void removeWhere(bool test(K key, V value));
/// Look up the value of [key], or add a new entry if it isn't there.
@@ -278,13 +346,18 @@
/// Otherwise calls [ifAbsent] to get a new value, associates [key] to
/// that value, and then returns the new value.
/// ```dart
- /// Map<String, int> scores = {'Bob': 36};
- /// for (var key in ['Bob', 'Rohan', 'Sophena']) {
- /// scores.putIfAbsent(key, () => key.length);
+ /// final diameters = <num, String>{1.0: 'Earth'};
+ /// final otherDiameters = <double, String>{0.383: 'Mercury', 0.949: 'Venus'};
+ ///
+ /// for (final item in otherDiameters.entries) {
+ /// diameters.putIfAbsent(item.key, () => item.value);
/// }
- /// scores['Bob']; // 36
- /// scores['Rohan']; // 5
- /// scores['Sophena']; // 7
+ /// print(diameters); // {1.0: Earth, 0.383: Mercury, 0.949: Venus}
+ ///
+ /// // If the key already exists, the current value is returned.
+ /// final result = diameters.putIfAbsent(0.383, () => 'Random');
+ /// print(result); // Mercury
+ /// print(diameters); // {1.0: Earth, 0.383: Mercury, 0.949: Venus}
/// ```
/// Calling [ifAbsent] must not add or remove keys from the map.
V putIfAbsent(K key, V ifAbsent());
@@ -296,6 +369,11 @@
/// The operation is equivalent to doing `this[key] = value` for each key
/// and associated value in other. It iterates over [other], which must
/// therefore not change during the iteration.
+ /// ```dart
+ /// final planets = <int, String>{1: 'Mercury', 2: 'Earth'};
+ /// planets.addAll({5: 'Jupiter', 6: 'Saturn'});
+ /// print(planets); // {1: Mercury, 2: Earth, 5: Jupiter, 6: Saturn}
+ /// ```
void addAll(Map<K, V> other);
/// Removes [key] and its associated value, if present, from the map.
@@ -305,16 +383,37 @@
///
/// Note that some maps allow `null` as a value,
/// so a returned `null` value doesn't always mean that the key was absent.
+ /// ```dart
+ /// final terrestrial = <int, String>{1: 'Mercury', 2: 'Venus', 3: 'Earth'};
+ /// final removedValue = terrestrial.remove(2); // Venus
+ /// print(terrestrial); // {1: Mercury, 3: Earth}
+ /// ```
V? remove(Object? key);
/// Removes all entries from the map.
///
/// After this, the map is empty.
+ /// ```dart
+ /// final planets = <int, String>{1: 'Mercury', 2: 'Venus', 3: 'Earth'};
+ /// planets.clear(); // {}
+ /// ```
void clear();
/// Applies [action] to each key/value pair of the map.
///
/// Calling `action` must not add or remove keys from the map.
+ /// ```dart
+ /// final planetsByMass = <num, String>{0.81: 'Venus', 1: 'Earth',
+ /// 0.11: 'Mars', 17.15: 'Neptune'};
+ ///
+ /// planetsByMass.forEach((key, value) {
+ /// print('$key: $value');
+ /// // 0.81: Venus
+ /// // 1: Earth
+ /// // 0.11: Mars
+ /// // 17.15: Neptune
+ /// });
+ /// ```
void forEach(void action(K key, V value));
/// The keys of [this].
diff --git a/tools/VERSION b/tools/VERSION
index f386dba..0d79263 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 16
PATCH 0
-PRERELEASE 93
+PRERELEASE 94
PRERELEASE_PATCH 0
\ No newline at end of file