// 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 declarations) { var walker = _ImplementsWalker(); var elements = []; 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 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 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); } }