blob: 5aa09cdd4a6a1eca11620281b14af18fa47ae88a [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/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<DartType, Element, Element, PrefixElement>>
_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) {
SimpleIdentifier constructorName = node.constructorName;
SyntacticEntity entity;
if (constructorName != null) {
entity = constructorName;
} else {
var name = node.name;
if (name is PrefixedIdentifier) {
entity = name.identifier;
} else {
entity = name;
}
}
var data = _get(entity);
SimpleIdentifier topEntity;
if (data.prefixInfo != null) {
PrefixedIdentifier prefixedIdentifier = node.name;
SimpleIdentifier prefix = prefixedIdentifier.prefix;
prefix.staticElement = data.prefixInfo;
topEntity = prefixedIdentifier.identifier;
} else {
topEntity = node.name;
}
Element element = data.reference;
DartType type = data.inferredType;
node.element = element;
if (element is ConstructorElement) {
topEntity.staticElement = element.enclosingElement;
if (constructorName != null) {
constructorName.staticElement = element;
constructorName.staticType = element.type;
}
ArgumentList argumentList = node.arguments;
if (argumentList != null) {
_applyResolutionToArguments(argumentList);
_resolveNamedArguments(argumentList, element.parameters);
}
} else {
topEntity.staticElement = element;
topEntity.staticType = type;
if (constructorName != null) {
constructorName.accept(this);
node.element = constructorName.staticElement;
}
}
}
ResolutionData<DartType, Element, Element, PrefixElement> _get(
SyntacticEntity entity,
{bool failIfAbsent: true}) {
int entityOffset = entity.offset;
var data = _data[entityOffset];
if (failIfAbsent && data == null) {
throw new StateError('No data for $entity at $entityOffset');
}
return data;
}
@override
void visitAsExpression(AsExpression node) {
node.expression.accept(this);
var data = _get(node.asOperator);
applyToTypeAnnotation(
_enclosingLibraryElement, data.literalType, node.type);
node.staticType = data.inferredType;
}
@override
void visitAssignmentExpression(AssignmentExpression node) {
node.leftHandSide.accept(this);
node.rightHandSide.accept(this);
SyntacticEntity entity = _getAssignmentEntity(node.leftHandSide);
var data = _get(entity);
node.staticElement = data.combiner;
node.staticType = 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 = data.reference;
}
// Record the return type of the expression.
node.staticType = 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) {
DartType guardType = _get(node.onKeyword ?? node.catchKeyword).literalType;
if (node.exceptionType != null) {
applyToTypeAnnotation(
_enclosingLibraryElement, guardType, node.exceptionType);
}
SimpleIdentifier exception = node.exceptionParameter;
if (exception != null) {
LocalVariableElementImpl element = exception.staticElement;
DartType type = _get(exception).literalType;
element.type = type;
exception.staticElement = element;
exception.staticType = type;
}
SimpleIdentifier stackTrace = node.stackTraceParameter;
if (stackTrace != null) {
LocalVariableElementImpl element = stackTrace.staticElement;
DartType type = _get(stackTrace).literalType;
element.type = type;
stackTrace.staticElement = element;
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 = _get(node.question).inferredType;
}
@override
void visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
var element = _get(node.equals).reference;
FieldElement fieldElement =
element is PropertyAccessorElement ? element.variable : null;
node.fieldName.staticElement = fieldElement;
node.fieldName.staticType = fieldElement.type;
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 = _get(node).inferredType;
}
@override
void visitForEachStatement(ForEachStatement node) {
DeclaredIdentifier loopVariable = node.loopVariable;
if (loopVariable != null) {
SimpleIdentifier identifier = loopVariable.identifier;
DartType type = _get(identifier).inferredType;
identifier.staticType = type;
if (loopVariable.type != null) {
applyToTypeAnnotation(
_enclosingLibraryElement, type, loopVariable.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) {
if (parameter is DefaultFormalParameter) {
if (parameter.defaultValue != null) {
parameter.defaultValue.accept(this);
}
}
}
}
@override
void visitFunctionDeclaration(FunctionDeclaration node) {
FunctionExpression functionExpression = node.functionExpression;
FormalParameterList parameterList = functionExpression.parameters;
// Apply resolution to default values.
parameterList.accept(this);
FunctionElementImpl element = node.element;
_typeContext.enterLocalFunction(element);
functionExpression.body?.accept(this);
_storeFunctionType(_get(node).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];
assert(typeParameter.bound == null);
typeParameter.name.staticElement = element.typeParameters[i];
typeParameter.name.staticType = _typeContext.typeType;
}
}
applyToTypeAnnotation(
_enclosingLibraryElement, element.returnType, node.returnType);
applyParameters(
_enclosingLibraryElement, element.parameters, parameterList);
}
_typeContext.exitLocalFunction(element);
}
@override
void visitFunctionExpression(FunctionExpression node) {
FormalParameterList parameterList = node.parameters;
FunctionElementImpl element = node.element;
_typeContext.enterLocalFunction(element);
// Apply resolution to default values.
parameterList.accept(this);
node.body.accept(this);
_storeFunctionType(_get(node).inferredType, element);
// Associate the elements with the nodes.
if (element != null) {
node.element = element;
node.staticType = element.type;
applyParameters(
_enclosingLibraryElement, element.parameters, parameterList);
}
_typeContext.exitLocalFunction(element);
}
void _storeFunctionType(DartType type, FunctionElementImpl element) {
if (type is FunctionType && element != null) {
element.returnType = type.returnType;
int normalParameterIndex = 0;
int optionalParameterIndex = 0;
for (ParameterElementImpl parameter in element.parameters) {
if (parameter.isNamed) {
parameter.type = type.namedParameterTypes[parameter.name];
} else if (normalParameterIndex < type.normalParameterTypes.length) {
parameter.type = type.normalParameterTypes[normalParameterIndex++];
} else if (optionalParameterIndex <
type.optionalParameterTypes.length) {
parameter.type =
type.optionalParameterTypes[optionalParameterIndex++];
}
}
}
}
@override
void visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
node.function.accept(this);
var data = _get(node.argumentList);
DartType invokeType = data.invokeType;
node.staticInvokeType = invokeType;
List<DartType> typeArguments = data.argumentTypes;
if (node.typeArguments != null && typeArguments is TypeArgumentsDartType) {
_applyTypeArgumentsToList(
_enclosingLibraryElement,
new TypeArgumentsDartType(typeArguments),
node.typeArguments.arguments);
}
DartType resultType = data.inferredType;
node.staticType = resultType;
node.argumentList.accept(this);
}
@override
void visitIndexExpression(IndexExpression node) {
node.target.accept(this);
DartType targetType = node.target.staticType;
var data = _get(node.leftBracket);
MethodElement element = data.reference;
// Convert the raw element into a member.
if (targetType is InterfaceType) {
MethodElement member = MethodMember.from(element, targetType);
node.staticElement = member;
}
node.staticType = data.inferredType;
node.index.accept(this);
}
@override
void visitInstanceCreationExpression(InstanceCreationExpression node) {
ConstructorName constructorName = node.constructorName;
var data = _get(constructorName);
PrefixElement prefix = data.prefixInfo;
ConstructorElement constructor = data.reference;
DartType type = data.inferredType;
applyConstructorElement(
_enclosingLibraryElement, prefix, constructor, type, constructorName);
node.staticElement = constructor;
node.staticType = type;
ArgumentList argumentList = node.argumentList;
_applyResolutionToArguments(argumentList);
_resolveNamedArguments(argumentList, constructor?.parameters);
}
@override
void visitIsExpression(IsExpression node) {
node.expression.accept(this);
var data = _get(node.isOperator);
applyToTypeAnnotation(
_enclosingLibraryElement, data.literalType, node.type);
node.staticType = 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.elements.accept(this);
DartType type = _get(node.constKeyword ?? node.leftBracket).inferredType;
node.staticType = type;
if (node.typeArguments != null) {
_applyTypeArgumentsToList(
_enclosingLibraryElement, type, node.typeArguments.arguments);
}
}
@override
void visitMapLiteral(MapLiteral node) {
node.entries.accept(this);
DartType type = _get(node.constKeyword ?? node.leftBracket).inferredType;
node.staticType = type;
if (node.typeArguments != null) {
_applyTypeArgumentsToList(
_enclosingLibraryElement, type, node.typeArguments.arguments);
}
}
@override
void visitMethodInvocation(MethodInvocation node) {
node.target?.accept(this);
ArgumentList argumentList = node.argumentList;
var data = _get(argumentList);
Element invokeElement;
if (data.isImplicitCall) {
if (node.methodName != null) {
node.methodName.accept(this);
invokeElement = node.methodName.staticElement;
}
} else {
invokeElement = data.reference;
}
DartType invokeType = data.invokeType;
List<DartType> typeArguments = data.argumentTypes;
DartType resultType = 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, failIfAbsent: false) != null) {
node.methodName.accept(this);
} else {
node.methodName.staticElement = invokeElement;
node.methodName.staticType = invokeType;
}
if (invokeType is FunctionType) {
if (node.typeArguments != null && typeArguments != null) {
_applyTypeArgumentsToList(
_enclosingLibraryElement,
new TypeArgumentsDartType(typeArguments),
node.typeArguments.arguments);
}
}
_applyResolutionToArguments(argumentList);
{
var elementForParameters = invokeElement;
if (elementForParameters is PropertyAccessorElement) {
PropertyAccessorElement accessor = elementForParameters;
elementForParameters = accessor.returnType.element;
}
if (elementForParameters is FunctionTypedElement) {
List<ParameterElement> parameters = elementForParameters.parameters;
_resolveNamedArguments(argumentList, parameters);
}
}
}
@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);
var data = _get(entity);
node.staticElement = data.combiner;
node.staticType = 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);
var data = _get(entity);
node.staticElement = data.combiner;
node.staticType = data.inferredType;
} else if (tokenType == TokenType.BANG) {
// !boolExpression;
node.staticType = _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 = data.reference;
node.staticType = 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 = _get(constructorName ?? node).reference;
node.staticElement = element;
constructorName?.staticElement = element;
ArgumentList argumentList = node.argumentList;
_applyResolutionToArguments(argumentList);
_resolveNamedArguments(argumentList, element?.parameters);
}
@override
void visitSimpleIdentifier(SimpleIdentifier node) {
var data = _get(node);
if (data.prefixInfo != null) {
node.staticElement = data.prefixInfo;
} else if (data.declaration != null) {
node.staticElement = data.declaration;
} else if (data.reference != null) {
node.staticElement = data.reference;
} else {
node.staticElement = null;
}
node.staticType =
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;
_applyResolutionToArguments(argumentList);
_resolveNamedArguments(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 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 = _get(node.name).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);
}
@override
void visitVariableDeclarationList(VariableDeclarationList node) {
if (node.parent is TopLevelVariableDeclaration) {
node.variables.accept(this);
} else {
if (node.metadata.isNotEmpty) {
// TODO(paulberry): handle this case
throw new UnimplementedError('Metadata on a variable declaration list');
}
node.variables.accept(this);
if (node.type != null) {
DartType type = node.variables[0].name.staticType;
// TODO(brianwilkerson) Understand why the type is sometimes `null`.
if (type != null) {
applyToTypeAnnotation(_enclosingLibraryElement, type, node.type);
}
}
}
}
/// Apply resolution to arguments of the [argumentList].
void _applyResolutionToArguments(ArgumentList argumentList) {
for (var argument in argumentList.arguments) {
if (argument is NamedExpression) {
argument.expression.accept(this);
} else {
argument.accept(this);
}
}
}
/// 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 {
throw new StateError(
'Unexpected LHS (${leftHandSide.runtimeType}) $leftHandSide');
}
}
/// Apply resolution to named arguments of the [argumentList].
void _resolveNamedArguments(
ArgumentList argumentList, List<ParameterElement> parameters) {
if (parameters != null) {
for (var argument in argumentList.arguments) {
if (argument is NamedExpression) {
SimpleIdentifier identifier = argument.name.label;
for (var parameter in parameters) {
if (parameter.name == identifier.name) {
identifier.staticElement = parameter;
break;
}
}
}
}
}
}
/// Apply the [type] that is created by the [constructorName] and the
/// [constructorElement] it references.
static void applyConstructorElement(
LibraryElement enclosingLibraryElement,
PrefixElement prefixElement,
ConstructorElement constructorElement,
DartType type,
ConstructorName constructorName) {
constructorName.staticElement = constructorElement;
ClassElement classElement = constructorElement?.enclosingElement;
Identifier typeIdentifier = constructorName.type.name;
if (prefixElement != null) {
PrefixedIdentifier prefixedTypeIdentifier = typeIdentifier;
prefixedTypeIdentifier.staticType = type;
prefixedTypeIdentifier.prefix.staticElement = prefixElement;
SimpleIdentifier classNode = prefixedTypeIdentifier.identifier;
classNode.staticElement = classElement;
classNode.staticType = type;
} else {
if (typeIdentifier is SimpleIdentifier) {
typeIdentifier.staticElement = classElement;
typeIdentifier.staticType = type;
} else if (typeIdentifier is PrefixedIdentifier) {
constructorName.type = astFactory.typeName(typeIdentifier.prefix, null);
constructorName.period = typeIdentifier.period;
constructorName.name = typeIdentifier.identifier;
}
}
constructorName.name?.staticElement = constructorElement;
applyToTypeAnnotation(enclosingLibraryElement, type, constructorName.type);
}
/// Apply the types of the [parameterElements] to the [parameterList] that
/// have an explicit type annotation.
static void applyParameters(
LibraryElement enclosingLibraryElement,
List<ParameterElement> parameterElements,
FormalParameterList parameterList) {
List<FormalParameter> parameters = parameterList.parameters;
int length = parameterElements.length;
if (parameters.length != length) {
throw new StateError('Parameter counts do not match');
}
for (int i = 0; i < length; i++) {
ParameterElementImpl element = parameterElements[i];
FormalParameter parameter = parameters[i];
NormalFormalParameter normalParameter;
if (parameter is NormalFormalParameter) {
normalParameter = parameter;
} else if (parameter is DefaultFormalParameter) {
normalParameter = parameter.parameter;
}
assert(normalParameter != null);
if (normalParameter is SimpleFormalParameterImpl) {
normalParameter.element = element;
}
if (normalParameter.identifier != null) {
element.nameOffset = normalParameter.identifier.offset;
normalParameter.identifier.staticElement = element;
normalParameter.identifier.staticType = element.type;
}
// Apply the type or the return type, if a function typed parameter.
TypeAnnotation functionReturnType;
FormalParameterList functionParameterList;
if (normalParameter is SimpleFormalParameter) {
applyToTypeAnnotation(
enclosingLibraryElement, element.type, normalParameter.type);
} else if (normalParameter is FunctionTypedFormalParameter) {
functionReturnType = normalParameter.returnType;
functionParameterList = normalParameter.parameters;
} else if (normalParameter is FieldFormalParameter) {
if (normalParameter.parameters == null) {
applyToTypeAnnotation(
enclosingLibraryElement, element.type, normalParameter.type);
} else {
functionReturnType = normalParameter.type;
functionParameterList = normalParameter.parameters;
}
}
if (functionParameterList != null) {
FunctionType elementType = element.type;
if (functionReturnType != null) {
applyToTypeAnnotation(enclosingLibraryElement, elementType.returnType,
functionReturnType);
}
applyParameters(enclosingLibraryElement, elementType.parameters,
functionParameterList);
}
}
}
/// Apply the [type] to the [typeAnnotation] by setting the type of the
/// [typeAnnotation] to the [type] and recursively applying each of the type
/// arguments of the [type] to the corresponding type arguments of the
/// [typeAnnotation].
static void applyToTypeAnnotation(LibraryElement enclosingLibraryElement,
DartType type, TypeAnnotation typeAnnotation) {
if (typeAnnotation is GenericFunctionTypeImpl) {
if (type is! FunctionType) {
throw new StateError('Non-function type ($type) '
'for generic function annotation ($typeAnnotation)');
}
FunctionType functionType = type;
typeAnnotation.type = type;
applyToTypeAnnotation(enclosingLibraryElement, functionType.returnType,
typeAnnotation.returnType);
applyParameters(enclosingLibraryElement, functionType.parameters,
typeAnnotation.parameters);
} else if (typeAnnotation is TypeNameImpl) {
typeAnnotation.type = type;
Identifier typeIdentifier = typeAnnotation.name;
SimpleIdentifier typeName;
if (typeIdentifier is PrefixedIdentifier) {
if (enclosingLibraryElement != null) {
String prefixName = typeIdentifier.prefix.name;
for (var import in enclosingLibraryElement.imports) {
if (import.prefix?.name == prefixName) {
typeIdentifier.prefix.staticElement = import.prefix;
break;
}
}
}
typeName = typeIdentifier.identifier;
} else {
typeName = typeIdentifier;
}
Element typeElement = type.element;
if (typeElement is GenericFunctionTypeElement &&
typeElement.enclosingElement is GenericTypeAliasElement) {
typeElement = typeElement.enclosingElement;
}
typeName.staticElement = typeElement;
typeName.staticType = type;
}
if (typeAnnotation is NamedType) {
TypeArgumentList typeArguments = typeAnnotation.typeArguments;
if (typeArguments != null) {
_applyTypeArgumentsToList(
enclosingLibraryElement, type, typeArguments.arguments);
}
}
}
/// Recursively apply each of the type arguments of the [type] to the
/// corresponding type arguments of the [typeArguments].
static void _applyTypeArgumentsToList(LibraryElement enclosingLibraryElement,
DartType type, List<TypeAnnotation> typeArguments) {
if (type != null && type.isUndefined) {
for (TypeAnnotation argument in typeArguments) {
applyToTypeAnnotation(enclosingLibraryElement, type, argument);
}
} else if (type is ParameterizedType) {
List<DartType> argumentTypes = type.typeArguments;
int argumentCount = argumentTypes.length;
if (argumentCount != typeArguments.length) {
throw new StateError('Found $argumentCount argument types '
'for ${typeArguments.length} type arguments');
}
for (int i = 0; i < argumentCount; i++) {
applyToTypeAnnotation(
enclosingLibraryElement, argumentTypes[i], typeArguments[i]);
}
} else {
throw new StateError('Attempting to apply a non-parameterized type '
'(${type.runtimeType}) to type arguments');
}
}
}
/// 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(FunctionElementImpl element);
/// Restore the current executable that was before the [element].
void exitLocalFunction(FunctionElementImpl element);
/// 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;
}
}