mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 12:24:24 +00:00
[cfe] Fix sound mode failures
Closes #46704 Change-Id: I39b05b8432a8c316c4bca8679531d663e46817a9 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/208084 Reviewed-by: Dmitry Stefantsov <dmitryas@google.com> Commit-Queue: Johnni Winther <johnniwinther@google.com>
This commit is contained in:
parent
db90fd784b
commit
eb1a2166cd
13 changed files with 92 additions and 61 deletions
|
@ -51,6 +51,8 @@ import 'variable_builder.dart';
|
|||
/// constructor.
|
||||
class FormalParameterBuilder extends ModifierBuilderImpl
|
||||
implements VariableBuilder {
|
||||
static const String noNameSentinel = 'no name sentinel';
|
||||
|
||||
/// List of metadata builders for the metadata declared on this parameter.
|
||||
final List<MetadataBuilder>? metadata;
|
||||
|
||||
|
@ -130,7 +132,8 @@ class FormalParameterBuilder extends ModifierBuilderImpl
|
|||
if (!library.isNonNullableByDefault && builtType != null) {
|
||||
builtType = legacyErasure(builtType);
|
||||
}
|
||||
variable = new VariableDeclarationImpl(name, functionNestingLevel,
|
||||
variable = new VariableDeclarationImpl(
|
||||
name == noNameSentinel ? null : name, functionNestingLevel,
|
||||
type: builtType,
|
||||
isFinal: isFinal,
|
||||
isConst: isConst,
|
||||
|
|
|
@ -1256,12 +1256,16 @@ class BodyBuilder extends ScopeListener<JumpTarget>
|
|||
} else {
|
||||
Substitution substitution = Substitution.fromPairs(
|
||||
initialTarget.function.typeParameters, arguments.types);
|
||||
arguments.types.clear();
|
||||
arguments.types.length = redirectionTarget!.typeArguments.length;
|
||||
for (int i = 0; i < arguments.types.length; i++) {
|
||||
arguments.types[i] =
|
||||
for (int i = 0; i < redirectionTarget!.typeArguments.length; i++) {
|
||||
DartType typeArgument =
|
||||
substitution.substituteType(redirectionTarget.typeArguments[i]);
|
||||
if (i < arguments.types.length) {
|
||||
arguments.types[i] = typeArgument;
|
||||
} else {
|
||||
arguments.types.add(typeArgument);
|
||||
}
|
||||
}
|
||||
arguments.types.length = redirectionTarget.typeArguments.length;
|
||||
|
||||
replacementNode = buildStaticInvocation(
|
||||
resolvedTarget,
|
||||
|
@ -2679,7 +2683,7 @@ class BodyBuilder extends ScopeListener<JumpTarget>
|
|||
if (!libraryBuilder.isNonNullableByDefault) {
|
||||
reportNonNullableModifierError(lateToken);
|
||||
}
|
||||
UnresolvedType type = pop() as UnresolvedType;
|
||||
UnresolvedType? type = pop() as UnresolvedType?;
|
||||
int modifiers = (lateToken != null ? lateMask : 0) |
|
||||
Modifier.validateVarFinalOrConst(varFinalOrConst?.lexeme);
|
||||
_enterLocalState(inLateLocalInitializer: lateToken != null);
|
||||
|
@ -4954,7 +4958,8 @@ class BodyBuilder extends ScopeListener<JumpTarget>
|
|||
@override
|
||||
void endTypeArguments(int count, Token beginToken, Token endToken) {
|
||||
debugEvent("TypeArguments");
|
||||
push(const FixedNullableList<UnresolvedType>().pop(stack, count) ??
|
||||
push(const FixedNullableList<UnresolvedType>()
|
||||
.popNonNullable(stack, count, dummyUnresolvedType) ??
|
||||
NullValue.TypeArguments);
|
||||
}
|
||||
|
||||
|
|
|
@ -943,7 +943,7 @@ class ConstantEvaluator implements ExpressionVisitor<Constant> {
|
|||
: numberSemantics = backend.numberSemantics,
|
||||
coreTypes = typeEnvironment.coreTypes,
|
||||
canonicalizationCache = <Constant, Constant>{},
|
||||
nodeCache = <Node, Constant>{},
|
||||
nodeCache = <Node, Constant?>{},
|
||||
env = new EvaluationEnvironment() {
|
||||
if (environmentDefines == null && !backend.supportsUnevaluatedConstants) {
|
||||
throw new ArgumentError(
|
||||
|
|
|
@ -2078,7 +2078,7 @@ class InferenceVisitor
|
|||
DartType inferredKeyType,
|
||||
DartType inferredValueType,
|
||||
DartType spreadContext,
|
||||
List<DartType?> actualTypes,
|
||||
List<DartType> actualTypes,
|
||||
List<DartType> actualTypesForSet,
|
||||
Map<TreeNode, DartType> inferredSpreadTypes,
|
||||
Map<Expression, DartType> inferredConditionTypes,
|
||||
|
@ -2096,8 +2096,8 @@ class InferenceVisitor
|
|||
DartType spreadType = spreadResult.inferredType;
|
||||
inferredSpreadTypes[entry.expression] = spreadType;
|
||||
int length = actualTypes.length;
|
||||
actualTypes.add(null);
|
||||
actualTypes.add(null);
|
||||
actualTypes.add(noInferredType);
|
||||
actualTypes.add(noInferredType);
|
||||
storeSpreadMapEntryElementTypes(
|
||||
spreadType, entry.isNullAware, actualTypes, length);
|
||||
DartType? actualKeyType = actualTypes[length];
|
||||
|
@ -2108,7 +2108,7 @@ class InferenceVisitor
|
|||
|
||||
MapLiteralEntry replacement = entry;
|
||||
if (typeChecksNeeded) {
|
||||
if (actualKeyType == null) {
|
||||
if (actualKeyType == noInferredType) {
|
||||
if (inferrer.coreTypes.isNull(spreadTypeBound) &&
|
||||
!entry.isNullAware) {
|
||||
replacement = new MapLiteralEntry(
|
||||
|
@ -2204,7 +2204,7 @@ class InferenceVisitor
|
|||
1);
|
||||
}
|
||||
}
|
||||
if (!inferrer.isAssignable(inferredValueType, actualValueType!)) {
|
||||
if (!inferrer.isAssignable(inferredValueType, actualValueType)) {
|
||||
if (inferrer.isNonNullableByDefault) {
|
||||
IsSubtypeOf subtypeCheckResult = inferrer.typeSchemaEnvironment
|
||||
.performNullabilityAwareSubtypeCheck(
|
||||
|
@ -2273,7 +2273,7 @@ class InferenceVisitor
|
|||
}
|
||||
|
||||
// Use 'dynamic' for error recovery.
|
||||
if (actualKeyType == null) {
|
||||
if (actualKeyType == noInferredType) {
|
||||
actualKeyType = actualTypes[length] = const DynamicType();
|
||||
actualValueType = actualTypes[length + 1] = const DynamicType();
|
||||
}
|
||||
|
@ -2287,7 +2287,7 @@ class InferenceVisitor
|
|||
entry.entryType = new InterfaceType(
|
||||
mapEntryClass!,
|
||||
inferrer.library.nonNullable,
|
||||
<DartType>[actualKeyType, actualValueType!]);
|
||||
<DartType>[actualKeyType, actualValueType]);
|
||||
|
||||
bool isMap = inferrer.typeSchemaEnvironment.isSubtypeOf(
|
||||
spreadType,
|
||||
|
@ -2354,10 +2354,10 @@ class InferenceVisitor
|
|||
typeChecksNeeded);
|
||||
int length = actualTypes.length;
|
||||
actualTypes[length - 2] = inferrer.typeSchemaEnvironment
|
||||
.getStandardUpperBound(actualKeyType!, actualTypes[length - 2]!,
|
||||
.getStandardUpperBound(actualKeyType, actualTypes[length - 2],
|
||||
inferrer.library.library);
|
||||
actualTypes[length - 1] = inferrer.typeSchemaEnvironment
|
||||
.getStandardUpperBound(actualValueType!, actualTypes[length - 1]!,
|
||||
.getStandardUpperBound(actualValueType, actualTypes[length - 1],
|
||||
inferrer.library.library);
|
||||
int lengthForSet = actualTypesForSet.length;
|
||||
actualTypesForSet[lengthForSet - 1] = inferrer.typeSchemaEnvironment
|
||||
|
@ -2622,7 +2622,7 @@ class InferenceVisitor
|
|||
inferredConditionTypes = new Map<Expression, DartType>.identity();
|
||||
}
|
||||
if (inferenceNeeded) {
|
||||
inferredTypes = [const UnknownType(), const UnknownType()];
|
||||
inferredTypes = [noInferredType, noInferredType];
|
||||
inferrer.typeSchemaEnvironment.inferGenericFunctionOrType(
|
||||
mapType,
|
||||
mapClass.typeParameters,
|
||||
|
@ -2701,7 +2701,7 @@ class InferenceVisitor
|
|||
formalTypesForSet.add(setType.typeArguments[0]);
|
||||
}
|
||||
|
||||
List<DartType> inferredTypesForSet = <DartType>[const UnknownType()];
|
||||
List<DartType> inferredTypesForSet = <DartType>[noInferredType];
|
||||
inferrer.typeSchemaEnvironment.inferGenericFunctionOrType(
|
||||
setType,
|
||||
inferrer.coreTypes.setClass.typeParameters,
|
||||
|
|
|
@ -179,12 +179,11 @@ class RedirectionTarget {
|
|||
}
|
||||
|
||||
RedirectionTarget? getRedirectionTarget(Procedure member, EnsureLoaded helper) {
|
||||
List<DartType> typeArguments = <DartType>[]..length =
|
||||
member.function.typeParameters.length;
|
||||
for (int i = 0; i < typeArguments.length; i++) {
|
||||
typeArguments[i] = new TypeParameterType.withDefaultNullabilityForLibrary(
|
||||
List<DartType> typeArguments = new List<DartType>.generate(
|
||||
member.function.typeParameters.length, (int i) {
|
||||
return new TypeParameterType.withDefaultNullabilityForLibrary(
|
||||
member.function.typeParameters[i], member.enclosingLibrary);
|
||||
}
|
||||
}, growable: true);
|
||||
|
||||
// We use the [tortoise and hare algorithm]
|
||||
// (https://en.wikipedia.org/wiki/Cycle_detection#Tortoise_and_hare) to
|
||||
|
@ -201,15 +200,15 @@ RedirectionTarget? getRedirectionTarget(Procedure member, EnsureLoaded helper) {
|
|||
Member nextTortoise = tortoiseBody!.target!;
|
||||
helper.ensureLoaded(nextTortoise);
|
||||
List<DartType>? nextTypeArguments = tortoiseBody.typeArguments;
|
||||
if (nextTypeArguments == null) {
|
||||
nextTypeArguments = <DartType>[];
|
||||
}
|
||||
|
||||
Substitution sub = Substitution.fromPairs(
|
||||
tortoise.function!.typeParameters, typeArguments);
|
||||
typeArguments = <DartType>[]..length = nextTypeArguments.length;
|
||||
for (int i = 0; i < typeArguments.length; i++) {
|
||||
typeArguments[i] = sub.substituteType(nextTypeArguments[i]);
|
||||
if (nextTypeArguments != null) {
|
||||
Substitution sub = Substitution.fromPairs(
|
||||
tortoise.function!.typeParameters, typeArguments);
|
||||
typeArguments =
|
||||
new List<DartType>.generate(nextTypeArguments.length, (int i) {
|
||||
return sub.substituteType(nextTypeArguments[i]);
|
||||
}, growable: true);
|
||||
} else {
|
||||
typeArguments = <DartType>[];
|
||||
}
|
||||
|
||||
tortoise = nextTortoise;
|
||||
|
|
|
@ -32,9 +32,12 @@ import 'package:kernel/text/ast_to_text.dart' show Printer;
|
|||
|
||||
import '../builder/fixed_type_builder.dart';
|
||||
import '../builder/formal_parameter_builder.dart';
|
||||
import '../builder/metadata_builder.dart';
|
||||
import '../builder/type_builder.dart';
|
||||
import '../builder/type_variable_builder.dart';
|
||||
import '../builder/unresolved_type.dart';
|
||||
import '../combinator.dart';
|
||||
import '../configuration.dart';
|
||||
import '../identifiers.dart';
|
||||
import '../source/source_library_builder.dart';
|
||||
import 'body_builder.dart';
|
||||
|
@ -159,6 +162,7 @@ class ByteSink implements Sink<List<int>> {
|
|||
final Token dummyToken = new SyntheticToken(TokenType.AT, -1);
|
||||
final Identifier dummyIdentifier = new Identifier(dummyToken);
|
||||
final Combinator dummyCombinator = new Combinator(false, {}, -1, dummyUri);
|
||||
final MetadataBuilder dummyMetadataBuilder = new MetadataBuilder(dummyToken);
|
||||
final TypeBuilder dummyTypeBuilder =
|
||||
new FixedTypeBuilder(dummyDartType, dummyUri, -1);
|
||||
final FormalParameterBuilder dummyFormalParameterBuilder =
|
||||
|
@ -167,3 +171,6 @@ final TypeVariableBuilder dummyTypeVariableBuilder =
|
|||
new TypeVariableBuilder(TypeVariableBuilder.noNameSentinel, null, -1, null);
|
||||
final Label dummyLabel = new Label('', -1);
|
||||
final FieldInfo dummyFieldInfo = new FieldInfo('', -1, null, dummyToken, -1);
|
||||
final Configuration dummyConfiguration = new Configuration(-1, '', '', '');
|
||||
final UnresolvedType dummyUnresolvedType =
|
||||
new UnresolvedType(dummyTypeBuilder, -1, dummyUri);
|
||||
|
|
|
@ -339,7 +339,7 @@ class DietListener extends StackListenerImpl {
|
|||
debugEvent("TopLevelMethod");
|
||||
Token bodyToken = pop() as Token;
|
||||
Object? name = pop();
|
||||
Token metadata = pop() as Token;
|
||||
Token? metadata = pop() as Token?;
|
||||
checkEmpty(beginToken.charOffset);
|
||||
if (name is ParserRecovery) return;
|
||||
|
||||
|
@ -509,7 +509,7 @@ class DietListener extends StackListenerImpl {
|
|||
debugEvent("Import");
|
||||
Object? name = pop(NullValue.Prefix);
|
||||
|
||||
Token metadata = pop() as Token;
|
||||
Token? metadata = pop() as Token?;
|
||||
checkEmpty(importKeyword.charOffset);
|
||||
if (name is ParserRecovery) return;
|
||||
|
||||
|
@ -535,7 +535,7 @@ class DietListener extends StackListenerImpl {
|
|||
void endExport(Token exportKeyword, Token semicolon) {
|
||||
debugEvent("Export");
|
||||
|
||||
Token metadata = pop() as Token;
|
||||
Token? metadata = pop() as Token?;
|
||||
Library libraryNode = libraryBuilder.library;
|
||||
LibraryDependency dependency =
|
||||
libraryNode.dependencies[importExportDirectiveIndex++];
|
||||
|
@ -546,7 +546,7 @@ class DietListener extends StackListenerImpl {
|
|||
void endPart(Token partKeyword, Token semicolon) {
|
||||
debugEvent("Part");
|
||||
|
||||
Token metadata = pop() as Token;
|
||||
Token? metadata = pop() as Token?;
|
||||
Library libraryNode = libraryBuilder.library;
|
||||
if (libraryNode.parts.length > partDirectiveIndex) {
|
||||
// If partDirectiveIndex >= libraryNode.parts.length we are in a case of
|
||||
|
@ -588,7 +588,7 @@ class DietListener extends StackListenerImpl {
|
|||
debugEvent("ClassFactoryMethod");
|
||||
Token bodyToken = pop() as Token;
|
||||
Object? name = pop();
|
||||
Token metadata = pop() as Token;
|
||||
Token? metadata = pop() as Token?;
|
||||
checkEmpty(beginToken.charOffset);
|
||||
if (name is ParserRecovery || currentClassIsParserRecovery) return;
|
||||
|
||||
|
@ -699,7 +699,7 @@ class DietListener extends StackListenerImpl {
|
|||
// in handleNoFormalParameters rather than the supplied token.
|
||||
pop(); // bodyToken
|
||||
Object? name = pop();
|
||||
Token metadata = pop() as Token;
|
||||
Token? metadata = pop() as Token?;
|
||||
checkEmpty(beginToken.charOffset);
|
||||
if (name is ParserRecovery || currentClassIsParserRecovery) return;
|
||||
FunctionBuilderImpl builder;
|
||||
|
|
|
@ -162,7 +162,8 @@ class OutlineBuilder extends StackListenerImpl {
|
|||
@override
|
||||
void endMetadataStar(int count) {
|
||||
debugEvent("MetadataStar");
|
||||
push(const FixedNullableList<MetadataBuilder>().pop(stack, count) ??
|
||||
push(const FixedNullableList<MetadataBuilder>()
|
||||
.popNonNullable(stack, count, dummyMetadataBuilder) ??
|
||||
NullValue.Metadata);
|
||||
}
|
||||
|
||||
|
@ -259,7 +260,8 @@ class OutlineBuilder extends StackListenerImpl {
|
|||
@override
|
||||
void endConditionalUris(int count) {
|
||||
debugEvent("EndConditionalUris");
|
||||
push(const FixedNullableList<Configuration>().pop(stack, count) ??
|
||||
push(const FixedNullableList<Configuration>()
|
||||
.popNonNullable(stack, count, dummyConfiguration) ??
|
||||
NullValue.ConditionalUris);
|
||||
}
|
||||
|
||||
|
@ -1369,7 +1371,8 @@ class OutlineBuilder extends StackListenerImpl {
|
|||
@override
|
||||
void endTypeArguments(int count, Token beginToken, Token endToken) {
|
||||
debugEvent("TypeArguments");
|
||||
push(const FixedNullableList<TypeBuilder>().pop(stack, count) ??
|
||||
push(const FixedNullableList<TypeBuilder>()
|
||||
.popNonNullable(stack, count, dummyTypeBuilder) ??
|
||||
NullValue.TypeArguments);
|
||||
}
|
||||
|
||||
|
@ -1468,8 +1471,14 @@ class OutlineBuilder extends StackListenerImpl {
|
|||
if (name is ParserRecovery) {
|
||||
push(name);
|
||||
} else {
|
||||
push(libraryBuilder.addFormalParameter(metadata, modifiers, type,
|
||||
name as String, thisKeyword != null, charOffset, initializerStart));
|
||||
push(libraryBuilder.addFormalParameter(
|
||||
metadata,
|
||||
modifiers,
|
||||
type,
|
||||
name == null ? FormalParameterBuilder.noNameSentinel : name as String,
|
||||
thisKeyword != null,
|
||||
charOffset,
|
||||
initializerStart));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1557,8 +1566,8 @@ class OutlineBuilder extends StackListenerImpl {
|
|||
assert(formals.isNotEmpty);
|
||||
if (formals.length == 2) {
|
||||
// The name may be null for generalized function types.
|
||||
// ignore: unnecessary_null_comparison
|
||||
if (formals[0].name != null && formals[0].name == formals[1].name) {
|
||||
if (formals[0].name != FormalParameterBuilder.noNameSentinel &&
|
||||
formals[0].name == formals[1].name) {
|
||||
addProblem(
|
||||
templateDuplicatedParameterName.withArguments(formals[1].name),
|
||||
formals[1].charOffset,
|
||||
|
@ -1574,8 +1583,7 @@ class OutlineBuilder extends StackListenerImpl {
|
|||
Map<String, FormalParameterBuilder> seenNames =
|
||||
<String, FormalParameterBuilder>{};
|
||||
for (FormalParameterBuilder formal in formals) {
|
||||
// ignore: unnecessary_null_comparison
|
||||
if (formal.name == null) continue;
|
||||
if (formal.name == FormalParameterBuilder.noNameSentinel) continue;
|
||||
if (seenNames.containsKey(formal.name)) {
|
||||
addProblem(
|
||||
templateDuplicatedParameterName.withArguments(formal.name),
|
||||
|
@ -1877,7 +1885,7 @@ class OutlineBuilder extends StackListenerImpl {
|
|||
bool isParserRecovery = false;
|
||||
for (int i = count - 1; i != -1; i--) {
|
||||
int charEndOffset = popCharOffset();
|
||||
Token beforeLast = pop() as Token;
|
||||
Token? beforeLast = pop() as Token?;
|
||||
Token? initializerTokenForInference = pop() as Token?;
|
||||
int charOffset = popCharOffset();
|
||||
Object? name = pop(NullValue.Identifier);
|
||||
|
@ -1909,7 +1917,8 @@ class OutlineBuilder extends StackListenerImpl {
|
|||
void handleTypeVariablesDefined(Token token, int count) {
|
||||
debugEvent("TypeVariablesDefined");
|
||||
assert(count > 0);
|
||||
push(const FixedNullableList<TypeVariableBuilder>().pop(stack, count) ??
|
||||
push(const FixedNullableList<TypeVariableBuilder>()
|
||||
.popNonNullable(stack, count, dummyTypeVariableBuilder) ??
|
||||
NullValue.TypeVariables);
|
||||
}
|
||||
|
||||
|
|
|
@ -803,7 +803,7 @@ class SourceLibraryBuilder extends LibraryBuilderImpl {
|
|||
if (startToken != null) {
|
||||
// Extract only the tokens for the initializer expression from the
|
||||
// token stream.
|
||||
Token endToken = info.beforeLast;
|
||||
Token endToken = info.beforeLast!;
|
||||
endToken.setNext(new Token.eof(endToken.next!.offset));
|
||||
new Token.eof(startToken.previous!.offset).setNext(startToken);
|
||||
}
|
||||
|
@ -4241,12 +4241,11 @@ class SourceLibraryBuilder extends LibraryBuilderImpl {
|
|||
Builder? declaration = iterator.current;
|
||||
while (declaration != null) {
|
||||
if (declaration is SourceTypeAliasBuilder) {
|
||||
declaration.buildTypedefTearOffs(this,
|
||||
(Procedure procedure) {
|
||||
procedure.isStatic = true;
|
||||
if (!declaration!.isPatch && !declaration.isDuplicate) {
|
||||
library.addProcedure(procedure);
|
||||
}
|
||||
declaration.buildTypedefTearOffs(this, (Procedure procedure) {
|
||||
procedure.isStatic = true;
|
||||
if (!declaration!.isPatch && !declaration.isDuplicate) {
|
||||
library.addProcedure(procedure);
|
||||
}
|
||||
});
|
||||
}
|
||||
declaration = declaration.next;
|
||||
|
@ -4523,7 +4522,7 @@ class FieldInfo {
|
|||
final String name;
|
||||
final int charOffset;
|
||||
final Token? initializerToken;
|
||||
final Token beforeLast;
|
||||
final Token? beforeLast;
|
||||
final int charEndOffset;
|
||||
|
||||
const FieldInfo(this.name, this.charOffset, this.initializerToken,
|
||||
|
|
|
@ -25,8 +25,8 @@ class BinaryPrinter implements Visitor<void>, BinarySink {
|
|||
final ConstantIndexer _constantIndexer;
|
||||
final UriIndexer _sourceUriIndexer = new UriIndexer();
|
||||
bool _currentlyInNonimplementation = false;
|
||||
final List<bool> _sourcesFromRealImplementation = <bool>[];
|
||||
final List<bool> _sourcesUsedInLibrary = <bool>[];
|
||||
final List<bool?> _sourcesFromRealImplementation = <bool?>[];
|
||||
final List<bool?> _sourcesUsedInLibrary = <bool?>[];
|
||||
Map<LibraryDependency, int> _libraryDependencyIndex =
|
||||
<LibraryDependency, int>{};
|
||||
NonNullableByDefaultCompiledMode? compilationMode;
|
||||
|
|
|
@ -1722,6 +1722,8 @@ class ClassSet extends IterableBase<Class> {
|
|||
/// are removed first; in the case of ties, classes with lower topological sort
|
||||
/// index are removed first.
|
||||
class _LubHeap extends Heap<_ClassInfo> {
|
||||
_LubHeap() : super(_dummyClassInfo);
|
||||
|
||||
@override
|
||||
bool sortsBefore(_ClassInfo a, _ClassInfo b) => sortsBeforeStatic(a, b);
|
||||
|
||||
|
@ -1731,3 +1733,5 @@ class _LubHeap extends Heap<_ClassInfo> {
|
|||
return a.topologicalIndex < b.topologicalIndex;
|
||||
}
|
||||
}
|
||||
|
||||
final _ClassInfo _dummyClassInfo = new _ClassInfo(dummyClass);
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
/// Basic implementation of a heap, with O(log n) insertion and removal.
|
||||
abstract class Heap<T> {
|
||||
final _items = <T>[];
|
||||
final T _dummyValue;
|
||||
|
||||
Heap(this._dummyValue);
|
||||
|
||||
bool get isEmpty => _items.isEmpty;
|
||||
|
||||
|
@ -12,7 +15,7 @@ abstract class Heap<T> {
|
|||
|
||||
void add(T item) {
|
||||
int index = _items.length;
|
||||
_items.length += 1;
|
||||
_items.add(_dummyValue);
|
||||
while (index > 0) {
|
||||
T parent = _items[_parentIndex(index)];
|
||||
if (sortsBefore(parent, item)) break;
|
||||
|
|
|
@ -36,5 +36,7 @@ main() {
|
|||
}
|
||||
|
||||
class _intHeap extends Heap<int> {
|
||||
_intHeap() : super(0);
|
||||
|
||||
bool sortsBefore(int a, int b) => a < b;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue