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&lt;<a href="#type_ServerService">ServerService</a>&gt;</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