blob: a48b328c345b430bb85cc65d5de957edb5ace38c [file] [log] [blame]
// Copyright (c) 2017, 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.md file.
import 'kernel_builder.dart'
show
TypeBuilder,
TypeVariableBuilder,
KernelFormalParameterBuilder,
KernelTypeBuilder,
KernelNamedTypeBuilder,
KernelTypeVariableBuilder,
KernelClassBuilder,
KernelFunctionTypeAliasBuilder,
KernelFunctionTypeBuilder,
NamedTypeBuilder,
FormalParameterBuilder,
FunctionTypeBuilder,
TypeDeclarationBuilder;
import 'package:kernel/util/graph.dart' show Graph, computeStrongComponents;
KernelTypeBuilder substituteRange(
KernelTypeBuilder type,
Map<TypeVariableBuilder, KernelTypeBuilder> upperSubstitution,
Map<TypeVariableBuilder, KernelTypeBuilder> lowerSubstitution,
{bool isCovariant = true}) {
if (type is KernelNamedTypeBuilder) {
if (type.builder is KernelTypeVariableBuilder) {
if (isCovariant) {
return upperSubstitution[type.builder] ?? type;
}
return lowerSubstitution[type.builder] ?? type;
}
if (type.arguments == null || type.arguments.length == 0) {
return type;
}
List<TypeBuilder> arguments;
for (int i = 0; i < type.arguments.length; i++) {
TypeBuilder substitutedArgument = substituteRange(
type.arguments[i], upperSubstitution, lowerSubstitution,
isCovariant: isCovariant);
if (substitutedArgument != type.arguments[i]) {
arguments ??= type.arguments.toList();
arguments[i] = substitutedArgument;
}
}
if (arguments != null) {
return new KernelNamedTypeBuilder(type.name, arguments)
..bind(type.builder);
}
return type;
}
if (type is KernelFunctionTypeBuilder) {
List<KernelTypeVariableBuilder> variables;
if (type.typeVariables != null) {
variables =
new List<KernelTypeVariableBuilder>(type.typeVariables.length);
}
List<KernelFormalParameterBuilder> formals;
if (type.formals != null) {
formals = new List<KernelFormalParameterBuilder>(type.formals.length);
}
KernelTypeBuilder returnType;
bool changed = false;
if (type.typeVariables != null) {
for (int i = 0; i < variables.length; i++) {
KernelTypeVariableBuilder variable = type.typeVariables[i];
KernelTypeBuilder bound = substituteRange(
variable.bound, upperSubstitution, lowerSubstitution,
isCovariant: isCovariant);
if (bound != variable.bound) {
variables[i] = new KernelTypeVariableBuilder(
variable.name, variable.parent, variable.charOffset, bound);
changed = true;
} else {
variables[i] = variable;
}
}
}
if (type.formals != null) {
for (int i = 0; i < formals.length; i++) {
KernelFormalParameterBuilder formal = type.formals[i];
KernelTypeBuilder parameterType = substituteRange(
formal.type, upperSubstitution, lowerSubstitution,
isCovariant: !isCovariant);
if (parameterType != formal.type) {
formals[i] = new KernelFormalParameterBuilder(
formal.metadata,
formal.modifiers,
parameterType,
formal.name,
formal.hasThis,
formal.parent,
formal.charOffset);
changed = true;
} else {
formals[i] = formal;
}
}
}
returnType = substituteRange(
type.returnType, upperSubstitution, lowerSubstitution,
isCovariant: true);
if (returnType != type.returnType) {
changed = true;
}
if (changed) {
return new KernelFunctionTypeBuilder(returnType, variables, formals);
}
return type;
}
return type;
}
KernelTypeBuilder substitute(KernelTypeBuilder type,
Map<TypeVariableBuilder, KernelTypeBuilder> substitution) {
return substituteRange(type, substitution, substitution, isCovariant: true);
}
/// Calculates bounds to be provided as type arguments in place of missing type
/// arguments on raw types with the given type parameters.
///
/// See the [description]
/// (https://github.com/dart-lang/sdk/blob/master/docs/language/informal/instantiate-to-bound.md)
/// of the algorithm for details.
List<KernelTypeBuilder> calculateBounds(
List<TypeVariableBuilder> variables,
KernelTypeBuilder dynamicType,
KernelTypeBuilder bottomType,
KernelClassBuilder objectClass) {
List<KernelTypeBuilder> bounds =
new List<KernelTypeBuilder>(variables.length);
for (int i = 0; i < variables.length; i++) {
KernelTypeBuilder type = variables[i].bound;
if (type == null ||
type is KernelNamedTypeBuilder &&
type.builder is KernelClassBuilder &&
(type.builder as KernelClassBuilder).cls == objectClass?.cls) {
type = dynamicType;
}
bounds[i] = type;
}
TypeVariablesGraph graph = new TypeVariablesGraph(variables, bounds);
List<List<int>> stronglyConnected = computeStrongComponents(graph);
for (List<int> component in stronglyConnected) {
Map<TypeVariableBuilder, KernelTypeBuilder> dynamicSubstitution =
<TypeVariableBuilder, KernelTypeBuilder>{};
Map<TypeVariableBuilder, KernelTypeBuilder> nullSubstitution =
<TypeVariableBuilder, KernelTypeBuilder>{};
for (int variableIndex in component) {
dynamicSubstitution[variables[variableIndex]] = dynamicType;
nullSubstitution[variables[variableIndex]] = bottomType;
}
for (int variableIndex in component) {
bounds[variableIndex] = substituteRange(
bounds[variableIndex], dynamicSubstitution, nullSubstitution,
isCovariant: true);
}
}
for (int i = 0; i < variables.length; i++) {
Map<TypeVariableBuilder, KernelTypeBuilder> substitution =
<TypeVariableBuilder, KernelTypeBuilder>{};
Map<TypeVariableBuilder, KernelTypeBuilder> nullSubstitution =
<TypeVariableBuilder, KernelTypeBuilder>{};
substitution[variables[i]] = bounds[i];
nullSubstitution[variables[i]] = bottomType;
for (int j = 0; j < variables.length; j++) {
bounds[j] = substituteRange(bounds[j], substitution, nullSubstitution,
isCovariant: true);
}
}
return bounds;
}
List<KernelTypeBuilder> calculateBoundsForDeclaration(
TypeDeclarationBuilder typeDeclarationBuilder,
KernelTypeBuilder dynamicType,
KernelTypeBuilder nullType,
KernelClassBuilder objectClass) {
List<TypeVariableBuilder> typeParameters;
if (typeDeclarationBuilder is KernelClassBuilder) {
typeParameters = typeDeclarationBuilder.typeVariables;
} else if (typeDeclarationBuilder is KernelFunctionTypeAliasBuilder) {
typeParameters = typeDeclarationBuilder.typeVariables;
}
if (typeParameters == null || typeParameters.length == 0) {
return null;
}
return calculateBounds(typeParameters, dynamicType, nullType, objectClass);
}
int instantiateToBoundInPlace(
NamedTypeBuilder typeBuilder,
KernelTypeBuilder dynamicType,
KernelTypeBuilder nullType,
KernelClassBuilder objectClass) {
int count = 0;
if (typeBuilder.arguments == null) {
typeBuilder.arguments = calculateBoundsForDeclaration(
typeBuilder.builder, dynamicType, nullType, objectClass);
count = typeBuilder.arguments?.length ?? 0;
}
return count;
}
/// Graph of mutual dependencies of type variables from the same declaration.
/// Type variables are represented by their indices in the corresponding
/// declaration.
class TypeVariablesGraph implements Graph<int> {
List<int> vertices;
List<TypeVariableBuilder> variables;
List<TypeBuilder> bounds;
// `edges[i]` is the list of indices of type variables that reference the type
// variable with the index `i` in their bounds.
List<List<int>> edges;
TypeVariablesGraph(this.variables, this.bounds) {
assert(variables.length == bounds.length);
vertices = new List<int>(variables.length);
Map<TypeVariableBuilder, int> variableIndices =
<TypeVariableBuilder, int>{};
edges = new List<List<int>>(variables.length);
for (int i = 0; i < vertices.length; i++) {
vertices[i] = i;
variableIndices[variables[i]] = i;
edges[i] = <int>[];
}
void collectReferencesFrom(int index, TypeBuilder type) {
if (type is NamedTypeBuilder) {
if (type.builder is TypeVariableBuilder &&
this.variables.contains(type.builder)) {
edges[variableIndices[type.builder]].add(index);
}
if (type.arguments != null) {
for (TypeBuilder argument in type.arguments) {
collectReferencesFrom(index, argument);
}
}
} else if (type is FunctionTypeBuilder) {
if (type.typeVariables != null) {
for (TypeVariableBuilder typeVariable in type.typeVariables) {
collectReferencesFrom(index, typeVariable.bound);
}
}
if (type.formals != null) {
for (FormalParameterBuilder parameter in type.formals) {
collectReferencesFrom(index, parameter.type);
}
}
collectReferencesFrom(index, type.returnType);
}
}
for (int i = 0; i < vertices.length; i++) {
collectReferencesFrom(i, bounds[i]);
}
}
/// Returns indices of type variables that depend on the type variable with
/// [index].
Iterable<int> neighborsOf(int index) {
return edges[index];
}
}