blob: 2adb063b1557d3ddb8ac1109c9ae791a14cdffa8 [file] [log] [blame]
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:_fe_analyzer_shared/src/util/dependency_walker.dart' as graph;
import 'package:analyzer/src/dart/ast/ast.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/summary2/link.dart';
/// Clears interfaces for declarations that have cycles.
void breakInterfaceCycles(Linker linker, List<AstNode> declarations) {
var walker = _ImplementsWalker();
var elements = <InterfaceElementImpl>[];
for (var declaration in declarations) {
if (declaration is DeclarationImpl) {
var element = declaration.declaredFragment!.element;
if (element is InterfaceElementImpl) {
elements.add(element);
}
}
}
for (var element in elements) {
var node = walker.getNode(element);
walker.walk(node);
}
}
class _ImplementsNode extends graph.Node<_ImplementsNode> {
final _ImplementsWalker walker;
final InterfaceElementImpl element;
@override
bool isEvaluated = false;
_ImplementsNode(this.walker, this.element);
@override
List<_ImplementsNode> computeDependencies() {
return [
element.supertype,
...element.mixins,
...element.interfaces,
if (element case MixinElementImpl element)
...element.superclassConstraints,
].nonNulls
.map((interface) => interface.element)
.map(walker.getNode)
.toList();
}
void _evaluate() {
isEvaluated = true;
}
void _markCircular(List<InterfaceElementImpl> elements) {
isEvaluated = true;
element.interfaceCycle = elements;
var typeProvider = element.library.typeProvider;
var typeSystem = element.library.typeSystem;
switch (element) {
case ClassElementImpl element:
element.supertype = typeProvider.objectType;
element.mixins = [];
element.interfaces = [];
case EnumElementImpl element:
element.mixins = [];
element.interfaces = [];
case ExtensionTypeElementImpl element:
element.hasImplementsSelfReference = true;
var representationType = element.representation.type;
var superInterface = typeSystem.isNonNullable(representationType)
? typeSystem.objectNone
: typeSystem.objectQuestion;
element.interfaces = [superInterface];
case MixinElementImpl element:
element.superclassConstraints = [typeProvider.objectType];
element.interfaces = [];
default:
throw UnimplementedError('${element.runtimeType}');
}
}
}
class _ImplementsWalker extends graph.DependencyWalker<_ImplementsNode> {
final Map<InterfaceElementImpl, _ImplementsNode> nodeMap = Map.identity();
@override
void evaluate(_ImplementsNode v) {
v._evaluate();
}
@override
void evaluateScc(List<_ImplementsNode> scc) {
var elements = scc.map((node) => node.element).toList();
for (var node in scc) {
node._markCircular(elements);
}
}
_ImplementsNode getNode(InterfaceElementImpl element) {
return nodeMap[element] ??= _ImplementsNode(this, element);
}
}