blob: 3c913ce0d453ef2bc5f71d6aea896a49daada97a [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 file.
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/standard_ast_factory.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/ast/ast.dart';
import 'package:analyzer/src/dart/ast/utilities.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/member.dart';
import 'package:analyzer/src/fasta/resolution_storer.dart';
import 'package:front_end/src/base/syntactic_entity.dart';
import 'package:front_end/src/scanner/token.dart';
import 'package:kernel/kernel.dart' as kernel;
/// Visitor that applies resolution data from the front end (obtained via
/// [ResolutionStorer]) to an analyzer AST.
class ResolutionApplier extends GeneralizingAstVisitor {
final LibraryElement _enclosingLibraryElement;
final TypeContext _typeContext;
final Map<int, ResolutionData> _data;
/// The current label scope. Each [Block] adds a new one.
_LabelScope _labelScope = new _LabelScope(null);
ResolutionApplier(
this._enclosingLibraryElement, this._typeContext, this._data);
/// Apply resolution to annotations of the given [node].
void applyToAnnotations(AnnotatedNode node) {
node.metadata.accept(this);
}
@override
void visitAdjacentStrings(AdjacentStrings node) {
node.strings.accept(this);
node.staticType = _typeContext.stringType;
}
@override
void visitAnnotation(Annotation node) {
Identifier name = node.name;
ArgumentList argumentList = node.arguments;
SimpleIdentifier fieldName;
SimpleIdentifier constructorName;
var data = _get(name);
if (name is SimpleIdentifier) {
var translatedReference = _translateReference(data);
name.staticElement = translatedReference;
name.staticType = _translateType(data.inferredType);
node.element = translatedReference;
} else if (name is PrefixedIdentifier) {
if (data.prefixInfo != null) {
name.prefix.staticElement = _translatePrefixInfo(data.prefixInfo);
data = _get(name.identifier);
name.identifier.staticElement = _translateReference(data);
name.identifier.staticType = _translateType(data.inferredType);
if (argumentList == null) {
fieldName = node.constructorName;
} else {
constructorName = node.constructorName;
}
} else {
name.prefix.staticElement = _translateReference(data);
name.prefix.staticType = _translateType(data.inferredType);
if (argumentList == null) {
fieldName = name.identifier;
} else {
constructorName = name.identifier;
}
}
}
if (fieldName != null) {
data = _get(fieldName);
var translatedReference = _translateReference(data);
node.element = translatedReference;
fieldName.staticElement = translatedReference;
fieldName.staticType = _translateType(data.inferredType);
}
if (argumentList != null) {
var data = _get(argumentList);
ConstructorElement element = _translateReference(data);
node.element = element;
if (constructorName != null) {
constructorName.staticElement = element;
constructorName.staticType = element.type;
}
argumentList.accept(this);
_resolveArgumentsToParameters(argumentList, element.parameters);
}
}
@override
void visitArgumentList(ArgumentList node) {
for (var argument in node.arguments) {
if (argument is NamedExpression) {
argument.expression.accept(this);
argument.staticType = argument.expression.staticType;
} else {
argument.accept(this);
}
}
}
@override
void visitAsExpression(AsExpression node) {
node.expression.accept(this);
node.type.accept(this);
var data = _get(node.asOperator);
node.staticType = _translateType(data.inferredType);
}
@override
void visitAssignmentExpression(AssignmentExpression node) {
node.leftHandSide.accept(this);
node.rightHandSide.accept(this);
SyntacticEntity entity =
_getAssignmentEntity(node.leftHandSide) ?? node.operator;
var data = _get(entity,
isSynthetic: entity is SimpleIdentifier && entity.isSynthetic);
node.staticElement = _translateAuxiliaryReference(data.combiner);
node.staticType = _translateType(data.inferredType);
}
@override
void visitBinaryExpression(BinaryExpression node) {
node.leftOperand.accept(this);
var data = _get(node.operator);
TokenType operatorType = node.operator.type;
if (operatorType != TokenType.QUESTION_QUESTION &&
operatorType != TokenType.AMPERSAND_AMPERSAND &&
operatorType != TokenType.BAR_BAR) {
node.staticElement = _translateReference(data);
}
// Record the return type of the expression.
node.staticType = _translateType(data.inferredType);
node.rightOperand.accept(this);
}
@override
void visitBlock(Block node) {
_labelScope = new _LabelScope(_labelScope);
super.visitBlock(node);
_labelScope = _labelScope.parent;
}
@override
void visitBreakStatement(BreakStatement node) {
SimpleIdentifier label = node.label;
if (label != null) {
LabelElement labelElement = _labelScope[label.name];
label.staticElement = labelElement;
}
}
@override
void visitCascadeExpression(CascadeExpression node) {
visitNode(node);
node.staticType = node.target.staticType;
}
@override
void visitCatchClause(CatchClause node) {
node.exceptionType?.accept(this);
SimpleIdentifier exception = node.exceptionParameter;
if (exception != null) {
LocalVariableElementImpl element = exception.staticElement;
DartType type = _translateType(
_get(exception, isSynthetic: exception.isSynthetic).inferredType);
element.type = type;
exception.staticType = type;
}
SimpleIdentifier stackTrace = node.stackTraceParameter;
if (stackTrace != null) {
LocalVariableElementImpl element = stackTrace.staticElement;
DartType type = _translateType(_get(stackTrace).inferredType);
element.type = type;
stackTrace.staticType = type;
}
node.body.accept(this);
}
@override
void visitConditionalExpression(ConditionalExpression node) {
node.condition.accept(this);
node.thenExpression.accept(this);
node.elseExpression.accept(this);
node.staticType = _translateType(_get(node.question).inferredType);
}
@override
void visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
var element = _translateReference(_get(node.equals));
if (element is PropertyAccessorElement) {
node.fieldName.staticElement = element.variable;
} else {
node.fieldName.staticElement = element;
}
node.expression.accept(this);
}
@override
void visitContinueStatement(ContinueStatement node) {
SimpleIdentifier label = node.label;
if (label != null) {
LabelElement labelElement = _labelScope[label.name];
label.staticElement = labelElement;
}
}
@override
void visitExpression(Expression node) {
visitNode(node);
node.staticType = _translateType(_get(node).inferredType);
}
@override
void visitForEachStatement(ForEachStatement node) {
DeclaredIdentifier loopVariable = node.loopVariable;
if (loopVariable != null) {
loopVariable.type?.accept(this);
SimpleIdentifier identifier = loopVariable.identifier;
DartType type = _translateType(_get(identifier).inferredType);
identifier.staticType = type;
VariableElementImpl element = identifier.staticElement;
if (element != null) {
_typeContext.encloseVariable(element);
identifier.staticElement = element;
element.type = type;
}
} else {
node.identifier.accept(this);
}
node.iterable.accept(this);
node.body.accept(this);
}
@override
void visitFormalParameterList(FormalParameterList parameterList) {
for (var parameter in parameterList.parameters) {
parameter.metadata?.accept(this);
NormalFormalParameter normalParameter;
if (parameter is DefaultFormalParameter) {
parameter.defaultValue?.accept(this);
normalParameter = parameter.parameter;
} else if (parameter is NormalFormalParameter) {
normalParameter = parameter;
} else {
// All parameters should either be DefaultFormalParameter or
// NormalFormalParameter.
throw new UnimplementedError('${parameter.runtimeType}');
}
if (normalParameter is SimpleFormalParameter) {
normalParameter.type?.accept(this);
} else if (normalParameter is FieldFormalParameter) {
normalParameter.type?.accept(this);
} else if (normalParameter is FunctionTypedFormalParameter) {
normalParameter.returnType?.accept(this);
normalParameter.typeParameters?.accept(this);
normalParameter.parameters?.accept(this);
var data = _get(normalParameter.identifier);
normalParameter.identifier.staticType =
_translateType(data.inferredType);
} else {
// Now that DefaultFormalParameter has been handled, all parameters
// should be SimpleFormalParameter, FieldFormalParameter, or
// FunctionTypedFormalParameter.
throw new UnimplementedError('${normalParameter.runtimeType}');
}
}
}
@override
void visitFunctionDeclaration(FunctionDeclaration node) {
FunctionElementImpl element = node.declaredElement;
_typeContext.enterLocalFunction(element);
node.returnType?.accept(this);
FunctionExpression functionExpression = node.functionExpression;
FormalParameterList parameterList = functionExpression.parameters;
// Apply resolution to default values.
parameterList.accept(this);
functionExpression.body?.accept(this);
_storeFunctionType(_translateType(_get(node.name).inferredType), element);
// Associate the elements with the nodes.
if (element != null) {
functionExpression.element = element;
node.name.staticElement = element;
node.name.staticType = element.type;
TypeParameterList typeParameterList = functionExpression.typeParameters;
if (typeParameterList != null) {
List<TypeParameter> typeParameters = typeParameterList.typeParameters;
for (var i = 0; i < typeParameters.length; i++) {
TypeParameter typeParameter = typeParameters[i];
typeParameter.name.staticElement = element.typeParameters[i];
typeParameter.name.staticType = _typeContext.typeType;
}
}
}
_typeContext.exitLocalFunction(element);
}
@override
void visitFunctionExpression(FunctionExpression node) {
FormalParameterList parameterList = node.parameters;
FunctionElementImpl element = node.declaredElement;
_typeContext.enterLocalFunction(element);
// Apply resolution to default values.
parameterList.accept(this);
node.body.accept(this);
_storeFunctionType(
_translateType(_get(node.parameters).inferredType), element);
// Associate the elements with the nodes.
if (element != null) {
node.element = element;
node.staticType = element.type;
}
_typeContext.exitLocalFunction(element);
}
@override
void visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
node.function.accept(this);
node.typeArguments?.accept(this);
var data = _get(node.argumentList);
DartType invokeType = _translateType(data.invokeType);
node.staticInvokeType = invokeType;
DartType resultType = _translateType(data.inferredType);
node.staticType = resultType;
node.argumentList.accept(this);
}
@override
void visitGenericFunctionType(covariant GenericFunctionTypeImpl node) {
var data = _get(node.functionKeyword);
FunctionType type = _translateType(data.inferredType);
node.type = type;
_typeContext.enterLocalFunction(type.element);
super.visitGenericFunctionType(node);
_typeContext.exitLocalFunction(type.element);
}
@override
void visitIndexExpression(IndexExpression node) {
node.target?.accept(this);
var data = _get(node.leftBracket);
node.staticElement = _translateReference(data);
node.staticType = _translateType(data.inferredType);
node.index.accept(this);
}
@override
void visitInstanceCreationExpression(InstanceCreationExpression node) {
ConstructorName constructorName = node.constructorName;
Identifier typeIdentifier = constructorName.type.name;
SimpleIdentifier classIdentifier;
SimpleIdentifier constructorIdentifier;
constructorName.type.typeArguments?.accept(this);
var data = _get(typeIdentifier);
TypeName newTypeName;
if (typeIdentifier is SimpleIdentifier) {
classIdentifier = typeIdentifier;
constructorIdentifier = constructorName.name;
} else if (typeIdentifier is PrefixedIdentifier) {
if (data.isPrefixReference) {
typeIdentifier.prefix.staticElement =
_translatePrefixInfo(data.prefixInfo);
classIdentifier = typeIdentifier.identifier;
constructorIdentifier = node.constructorName.name;
data = _get(classIdentifier);
} else {
classIdentifier = typeIdentifier.prefix;
constructorIdentifier = typeIdentifier.identifier;
TypeArgumentList typeArguments = constructorName.type.typeArguments;
newTypeName = astFactory.typeName(classIdentifier, typeArguments);
constructorName.type = newTypeName;
constructorName.period = typeIdentifier.period;
constructorName.name = constructorIdentifier;
}
}
classIdentifier.staticElement = _translateReference(data);
data = _get(node.argumentList);
ConstructorElement constructor = _translateReference(data);
DartType type = _translateType(data.inferredType);
node.staticElement = constructor;
node.staticType = type;
node.constructorName.staticElement = constructor;
node.constructorName.type.type = type;
typeIdentifier.staticType = type;
classIdentifier.staticType = type;
constructorIdentifier?.staticElement = constructor;
ArgumentList argumentList = node.argumentList;
argumentList.accept(this);
_resolveArgumentsToParameters(argumentList, constructor?.parameters);
}
@override
void visitIsExpression(IsExpression node) {
node.expression.accept(this);
node.type.accept(this);
var data = _get(node.isOperator);
node.staticType = _translateType(data.inferredType);
}
@override
void visitLabel(Label node) {
SimpleIdentifier label = node.label;
String name = label.name;
var element = new LabelElementImpl(name, label.offset, false, false);
_labelScope.add(name, element);
label.staticElement = element;
}
@override
void visitListLiteral(ListLiteral node) {
node.typeArguments?.accept(this);
node.elements.accept(this);
DartType type = _translateType(
_get(node.constKeyword ?? node.leftBracket).inferredType);
node.staticType = type;
}
@override
void visitMapLiteral(MapLiteral node) {
node.typeArguments?.accept(this);
node.entries.accept(this);
DartType type = _translateType(
_get(node.constKeyword ?? node.leftBracket).inferredType);
node.staticType = type;
}
@override
void visitMethodInvocation(MethodInvocation node) {
node.target?.accept(this);
node.typeArguments?.accept(this);
ArgumentList argumentList = node.argumentList;
var data = _get(argumentList);
Element invokeElement;
if (data.loadLibrary != null) {
LibraryElement libraryElement =
_translateAuxiliaryReference(data.loadLibrary);
invokeElement = libraryElement.loadLibraryFunction;
} else if (data.isImplicitCall) {
if (node.methodName != null) {
node.methodName.accept(this);
invokeElement = node.methodName.staticElement;
}
} else {
invokeElement = _translateReference(data);
}
DartType invokeType = _translateType(data.invokeType);
DartType resultType = _translateType(data.inferredType);
if (invokeElement is PropertyInducingElement) {
PropertyInducingElement property = invokeElement;
invokeElement = property.getter;
}
node.staticInvokeType = invokeType;
node.staticType = resultType;
if (node.methodName.name == 'call' && invokeElement == null) {
// Don't resolve explicit call() invocation of function types.
} else if (_get(node.methodName.token,
isSynthetic: node.methodName.isSynthetic, failIfAbsent: false) !=
null) {
node.methodName.accept(this);
} else {
node.methodName.staticElement = invokeElement;
node.methodName.staticType = invokeType;
}
argumentList.accept(this);
{
var elementForParameters = invokeElement;
if (elementForParameters is PropertyAccessorElement) {
PropertyAccessorElement accessor = elementForParameters;
elementForParameters = accessor.returnType.element;
}
List<ParameterElement> parameters;
if (elementForParameters is FunctionTypedElement) {
parameters = elementForParameters.parameters;
} else if (elementForParameters is ParameterElement) {
var type = elementForParameters.type;
if (type is FunctionType) {
parameters = type.parameters;
}
}
_resolveArgumentsToParameters(argumentList, parameters);
}
if (invokeElement is ConstructorElement) {
_rewriteIntoInstanceCreation(node, invokeElement, invokeType, resultType);
}
}
@override
void visitNativeFunctionBody(NativeFunctionBody node) {
// nothing to resolve
}
@override
void visitParenthesizedExpression(ParenthesizedExpression node) {
node.visitChildren(this);
node.staticType = node.expression.staticType;
}
@override
void visitPostfixExpression(PostfixExpression node) {
node.operand.accept(this);
SyntacticEntity entity =
_getAssignmentEntity(node.operand) ?? node.operator;
var data = _get(entity);
node.staticElement = _translateAuxiliaryReference(data.combiner);
node.staticType = _translateType(data.inferredType);
}
@override
void visitPrefixedIdentifier(PrefixedIdentifier node) {
node.prefix.accept(this);
node.identifier.accept(this);
node.staticType = node.identifier.staticType;
}
@override
void visitPrefixExpression(PrefixExpression node) {
node.operand.accept(this);
TokenType tokenType = node.operator.type;
if (tokenType.isIncrementOperator) {
// ++v;
// This is an assignment, it is associated with the operand.
SyntacticEntity entity =
_getAssignmentEntity(node.operand) ?? node.operator;
var data = _get(entity);
node.staticElement = _translateAuxiliaryReference(data.combiner);
node.staticType = _translateType(data.inferredType);
} else if (tokenType == TokenType.BANG) {
// !boolExpression;
node.staticType = _translateType(_get(node).inferredType);
} else {
// ~v;
// This is a method invocation, it is associated with the operator.
SyntacticEntity entity = node.operator;
var data = _get(entity);
node.staticElement = _translateReference(data);
node.staticType = _translateType(data.inferredType);
}
}
@override
void visitPropertyAccess(PropertyAccess node) {
node.target?.accept(this);
node.propertyName.accept(this);
node.staticType = node.propertyName.staticType;
}
@override
void visitRedirectingConstructorInvocation(
RedirectingConstructorInvocation node) {
SimpleIdentifier constructorName = node.constructorName;
ConstructorElement element =
_translateReference(_get(constructorName ?? node));
node.staticElement = element;
constructorName?.staticElement = element;
ArgumentList argumentList = node.argumentList;
argumentList.accept(this);
_resolveArgumentsToParameters(argumentList, element?.parameters);
}
@override
void visitSimpleIdentifier(SimpleIdentifier node) {
var data = _get(node, isSynthetic: node.token.isSynthetic);
if (data.prefixInfo != null) {
node.staticElement = _translatePrefixInfo(data.prefixInfo);
} else if (data.declaration != null) {
node.staticElement = _translateDeclaration(data.declaration);
} else if (data.loadLibrary != null) {
LibraryElement library = _translateAuxiliaryReference(data.loadLibrary);
node.staticElement = library.loadLibraryFunction;
} else {
node.staticElement = _translateReference(data);
}
node.staticType = _translateType(
data.isWriteReference ? data.writeContext : data.inferredType);
}
@override
void visitStringInterpolation(StringInterpolation node) {
for (var element in node.elements) {
if (element is InterpolationExpression) {
element.expression.accept(this);
}
}
node.staticType = _typeContext.stringType;
}
@override
void visitSuperConstructorInvocation(SuperConstructorInvocation node) {
SimpleIdentifier constructorName = node.constructorName;
var superElement = _typeContext.enclosingClassElement.supertype.element;
ConstructorElement element;
if (constructorName == null) {
element = superElement.unnamedConstructor;
} else {
String name = constructorName.name;
element = superElement.getNamedConstructor(name);
constructorName.staticElement = element;
}
node.staticElement = element;
ArgumentList argumentList = node.argumentList;
argumentList.accept(this);
_resolveArgumentsToParameters(argumentList, element?.parameters);
}
@override
void visitSuperExpression(SuperExpression node) {
node.staticType = _typeContext.enclosingClassElement?.type;
}
@override
void visitThisExpression(ThisExpression node) {
node.staticType = _typeContext.enclosingClassElement?.type;
}
@override
void visitTypeName(TypeName node) {
super.visitTypeName(node);
node.type = node.name.staticType;
}
@override
visitTypeParameter(TypeParameter node) {
node.bound?.accept(this);
}
@override
void visitVariableDeclaration(VariableDeclaration node) {
AstNode parent = node.parent;
if (parent is VariableDeclarationList &&
(parent.parent is TopLevelVariableDeclaration ||
parent.parent is FieldDeclaration)) {
// Don't visit the name; resolution for it will come from the outline.
} else {
DartType type = _translateType(
_get(node.name, isSynthetic: node.name.isSynthetic).inferredType);
node.name.staticType = type;
VariableElementImpl element = node.name.staticElement;
if (element != null) {
_typeContext.encloseVariable(element);
node.name.staticElement = element;
element.type = type;
}
node.initializer?.accept(this);
if (element is ConstVariableElement) {
(element as ConstVariableElement).constantInitializer =
node.initializer;
}
}
}
@override
void visitVariableDeclarationList(VariableDeclarationList node) {
if (node.parent is TopLevelVariableDeclaration) {
node.variables.accept(this);
} else {
node.type?.accept(this);
node.metadata.accept(this);
node.variables.accept(this);
}
}
ResolutionData _get(SyntacticEntity entity,
{bool failIfAbsent = true, bool isSynthetic = false}) {
int entityOffset = entity.offset;
var encodedLocation = 2 * entityOffset + (isSynthetic ? 1 : 0);
var data = _data[encodedLocation];
if (failIfAbsent && data == null) {
String fileName = _enclosingLibraryElement.source.fullName;
throw new StateError('No data for $entity at (offset=$entityOffset, '
'isSynthetic=$isSynthetic) in $fileName');
}
return data;
}
/// Return the [SyntacticEntity] with which the front-end associates
/// assignment to the given [leftHandSide].
SyntacticEntity _getAssignmentEntity(Expression leftHandSide) {
if (leftHandSide is SimpleIdentifier) {
return leftHandSide;
} else if (leftHandSide is PrefixedIdentifier) {
return leftHandSide.identifier;
} else if (leftHandSide is PropertyAccess) {
return leftHandSide.propertyName;
} else if (leftHandSide is IndexExpressionImpl) {
return leftHandSide.leftBracket;
} else if (leftHandSide is ParenthesizedExpression) {
return leftHandSide.rightParenthesis;
} else {
return null;
}
}
/// Resolve arguments of the [argumentList] to corresponding [parameters].
void _resolveArgumentsToParameters(
ArgumentList argumentList, List<ParameterElement> parameters) {
if (parameters != null) {
var numberOfPositionalParameters = 0;
for (var parameter in parameters) {
if (parameter.isPositional) {
numberOfPositionalParameters++;
}
}
var numberOfArguments = argumentList.arguments.length;
if (numberOfArguments == numberOfPositionalParameters &&
numberOfPositionalParameters == parameters.length) {
argumentList.correspondingStaticParameters = parameters;
return;
}
var resolvedParameters = new List<ParameterElement>(numberOfArguments);
for (var i = 0; i < numberOfArguments; i++) {
var argument = argumentList.arguments[i];
ParameterElement argumentParameter;
if (argument is NamedExpression) {
SimpleIdentifier identifier = argument.name.label;
for (var parameter in parameters) {
if (parameter.name == identifier.name) {
argumentParameter = parameter;
identifier.staticElement = parameter;
break;
}
}
} else if (i < parameters.length && parameters[i].isPositional) {
argumentParameter = parameters[i];
}
resolvedParameters[i] = argumentParameter;
}
argumentList.correspondingStaticParameters = resolvedParameters;
}
}
/// Rewrite AST if the [node] represents an instance creation.
void _rewriteIntoInstanceCreation(
MethodInvocation node,
ConstructorElement invokeElement,
DartType invokeType,
DartType resultType) {
if (node.isCascaded) {
return;
}
Identifier typeIdentifier;
Token constructorIdentifierPeriod;
SimpleIdentifier constructorIdentifier;
var target = node.target;
if (target == null) {
SimpleIdentifier simpleTypeIdentifier = node.methodName;
simpleTypeIdentifier.staticElement = resultType.element;
simpleTypeIdentifier.staticType = resultType;
typeIdentifier = simpleTypeIdentifier;
} else if (target is SimpleIdentifier) {
if (target.staticElement is PrefixElement) {
SimpleIdentifier simpleTypeIdentifier = node.methodName;
simpleTypeIdentifier.staticElement = resultType.element;
simpleTypeIdentifier.staticType = resultType;
typeIdentifier = astFactory.prefixedIdentifier(
target, node.operator, simpleTypeIdentifier);
} else {
typeIdentifier = target;
constructorIdentifierPeriod = node.operator;
constructorIdentifier = node.methodName;
}
} else {
PrefixedIdentifier prefixed = target;
typeIdentifier = prefixed;
constructorIdentifierPeriod = prefixed.period;
constructorIdentifier = node.methodName;
}
var typeName = astFactory.typeName(typeIdentifier, node.typeArguments);
typeName.type = resultType;
var creation = astFactory.instanceCreationExpression(
null,
astFactory.constructorName(
typeName,
constructorIdentifierPeriod,
constructorIdentifier,
),
node.argumentList,
);
creation.staticElement = invokeElement;
creation.staticType = resultType;
NodeReplacer.replace(node, creation);
}
void _storeFunctionType(DartType type, FunctionTypedElementImpl element) {
if (type is FunctionType && element != null) {
DartType Function(DartType) substituteConstituentType;
if (type.typeFormals.length == element.typeParameters.length &&
type.typeFormals.length != 0) {
var argumentTypes = element.typeParameters.map((e) => e.type).toList();
var parameterTypes = type.typeFormals.map((e) {
var type = e.type;
var element = type.element;
if (element is TypeParameterMember) {
return element.baseElement.type;
} else {
return type;
}
}).toList();
substituteConstituentType =
(DartType t) => t.substitute2(argumentTypes, parameterTypes);
for (int i = 0; i < type.typeFormals.length; i++) {
(element.typeParameters[i] as TypeParameterElementImpl).bound =
type.typeFormals[i].bound == null
? null
: substituteConstituentType(type.typeFormals[i].bound);
}
} else {
substituteConstituentType = (DartType t) => t;
}
element.returnType = substituteConstituentType(type.returnType);
int normalParameterIndex = 0;
int optionalParameterIndex = 0;
for (ParameterElementImpl parameter in element.parameters) {
if (parameter.isNamed) {
parameter.type = substituteConstituentType(
type.namedParameterTypes[parameter.name]);
} else if (normalParameterIndex < type.normalParameterTypes.length) {
parameter.type = substituteConstituentType(
type.normalParameterTypes[normalParameterIndex++]);
} else if (optionalParameterIndex <
type.optionalParameterTypes.length) {
parameter.type = substituteConstituentType(
type.optionalParameterTypes[optionalParameterIndex++]);
}
}
}
}
Element _translateAuxiliaryReference(kernel.Node reference) {
return _typeContext.translateReference(reference);
}
Element _translateDeclaration(int declaration) {
return _typeContext.translateDeclaration(declaration);
}
Element _translatePrefixInfo(int prefixInfo) {
return _typeContext.translatePrefixInfo(prefixInfo);
}
Element _translateReference(ResolutionData data) {
if (data.isPrefixReference) {
return _translatePrefixInfo(data.prefixInfo);
}
return _typeContext.translateReference(data.reference,
isNamespaceCombinatorReference: data.isNamespaceCombinatorReference,
isTypeReference: data.isTypeReference,
isWriteReference: data.isWriteReference,
inferredType: data.inferredType,
receiverType: data.receiverType);
}
DartType _translateType(kernel.DartType type) {
return _typeContext.translateType(type);
}
}
/// A container with [typeArguments].
class TypeArgumentsDartType implements ParameterizedType {
@override
final List<DartType> typeArguments;
TypeArgumentsDartType(this.typeArguments);
@override
bool get isUndefined => false;
noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
@override
String toString() {
return '<${typeArguments.join(', ')}>';
}
}
/// Context for translating types.
abstract class TypeContext {
/// The enclosing [ClassElement], or `null` if not in a class.
ClassElement get enclosingClassElement;
DartType get stringType;
DartType get typeType;
/// Attach the variable [element] to the current executable.
void encloseVariable(ElementImpl element);
/// Finalize the given function [element] - set all types for it.
/// Then make it the current executable.
void enterLocalFunction(FunctionTypedElementImpl element);
/// Restore the current executable that was before the [element].
void exitLocalFunction(FunctionTypedElementImpl element);
/// Return the Analyzer [Element] for the local declaration having the given
/// offset.
Element translateDeclaration(int declarationOffset);
/// Return the analyzer [Element] for the import prefix corresponding to the
/// import having the given offset.
PrefixElement translatePrefixInfo(int importIndex);
/// Return the analyzer [Element] for the given kernel node.
Element translateReference(kernel.Node referencedNode,
{bool isNamespaceCombinatorReference = false,
bool isTypeReference = false,
bool isWriteReference = false,
kernel.DartType inferredType,
kernel.DartType receiverType});
/// Return the Analyzer [DartType] for the given [kernelType].
DartType translateType(kernel.DartType kernelType);
}
/// The hierarchical scope for labels.
class _LabelScope {
final _LabelScope parent;
final Map<String, LabelElement> elements = {};
_LabelScope(this.parent);
LabelElement operator [](String name) {
var element = elements[name];
if (element != null) {
return element;
}
if (parent != null) {
return parent[name];
}
return null;
}
void add(String name, LabelElement element) {
elements[name] = element;
}
}