Implements support for ignoring method type arguments in resolution.

Extends `FunctionExpression` to hold the formal type variable
declaration syntax. Introduces `GenericElement` as a new superclass of
`TypeDeclarationElement`, allowing `FunctionElement` to have a getter
`typeVariables`. Changes `SignatureResolver.analyze` in several ways
to create and handle the new type variables. In order to avoid circular
ordering dependencies, introduced new scope classes such that the
function signatures can be computed without relying on themselves to
look up type variables (e.g., `FunctionSignatureBuildingScope`).

Finally, the mock_compiler and resolver_test.dart were adjusted to give
a `scope` argument to `new ResolverVisitor(..)` in order to get the
correct scopes in the new setup.

A few words about the approach:

The type of every method type parameter behaves as `dynamic`, because
its bound is (unconditionally, ignoring any bound syntax that might be
present) set to `const DynamicType()`. This preserves the property
that diagnostic messages about the type variables will refer to the
correct location in the source code.

Type arguments passed in send expressions are parsed but not added to
the abstract syntax and therefore not passed on to the resolution
phase; this means that all sends are treated as if they had no actual
type arguments, even when they do have them. Hence, actual method type
arguments are completely ignored.

R=johnniwinther@google.com

Review URL: https://codereview.chromium.org/1915123008 .
This commit is contained in:
Erik Ernst 2016-04-29 19:46:12 +02:00
parent 3ae8c18359
commit e44e667ca7
16 changed files with 264 additions and 93 deletions

View file

@ -495,6 +495,8 @@ class TreePrinter {
: makeFunctionBody(exp.body);
result = new tree.FunctionExpression(
constructorName(exp),
// TODO(eernst): retrieve and pass the actual type variables.
null, // typeVariables
parameters,
body,
null, // return type
@ -514,6 +516,8 @@ class TreePrinter {
tree.Node body = makeFunctionBody(exp.body);
result = new tree.FunctionExpression(
functionName(exp),
// TODO(eernst): retrieve and pass the actual type variables.
null, // typeVariables
parameters,
body,
exp.returnType == null || exp.element.isConstructor
@ -798,6 +802,8 @@ class TreePrinter {
} else if (stmt is FunctionDeclaration) {
tree.FunctionExpression function = new tree.FunctionExpression(
stmt.name != null ? makeIdentifier(stmt.name) : null,
// TODO(eernst): retrieve and pass the actual type variables.
null, // typeVariables
makeParameters(stmt.parameters),
makeFunctionBody(stmt.body),
stmt.returnType != null ? makeType(stmt.returnType) : null,
@ -965,6 +971,8 @@ class TreePrinter {
if (param.isFunction) {
tree.Node definition = new tree.FunctionExpression(
makeIdentifier(param.name),
// TODO(eernst): retrieve and pass the actual type variables.
null, // typeVariables
makeParameters(param.parameters),
null, // body
param.type == null ? null : makeType(param.type),

View file

@ -486,7 +486,12 @@ class Elements {
return true;
}
static bool hasAccessToTypeVariables(Element element) {
static bool hasAccessToTypeVariable(Element element,
TypeVariableElement typeVariable) {
GenericElement declaration = typeVariable.typeDeclaration;
if (declaration is FunctionElement || declaration is ParameterElement) {
return true;
}
Element outer = element.outermostEnclosingMemberOrTopLevel;
return (outer != null && outer.isFactoryConstructor) ||
!isInStaticContext(element);
@ -1107,6 +1112,7 @@ abstract class AbstractFieldElement extends Element {
abstract class FunctionSignature {
FunctionType get type;
List<DartType> get typeVariables;
List<FormalElement> get requiredParameters;
List<FormalElement> get optionalParameters;
@ -1134,7 +1140,8 @@ abstract class FunctionElement extends Element
AstElement,
TypedElement,
FunctionTypedElement,
ExecutableElement {
ExecutableElement,
GenericElement {
FunctionExpression get node;
FunctionElement get patch;
@ -1142,7 +1149,7 @@ abstract class FunctionElement extends Element
bool get hasFunctionSignature;
/// The parameters of this functions.
/// The parameters of this function.
List<ParameterElement> get parameters;
/// The type of this function.
@ -1322,9 +1329,20 @@ abstract class ConstructorBodyElement extends MethodElement {
FunctionElement get constructor;
}
/// [GenericElement] defines the common interface for generic functions and
/// [TypeDeclarationElement].
abstract class GenericElement extends Element implements AstElement {
/**
* The type variables declared on this declaration. The type variables are not
* available until the type of the element has been computed through
* [computeType].
*/
List<DartType> get typeVariables;
}
/// [TypeDeclarationElement] defines the common interface for class/interface
/// declarations and typedefs.
abstract class TypeDeclarationElement extends Element implements AstElement {
abstract class TypeDeclarationElement extends GenericElement {
/// The name of this type declaration, taking privacy into account.
Name get memberName;
@ -1366,13 +1384,6 @@ abstract class TypeDeclarationElement extends Element implements AstElement {
*/
GenericType get rawType;
/**
* The type variables declared on this declaration. The type variables are not
* available until the type of the element has been computed through
* [computeType].
*/
List<DartType> get typeVariables;
bool get isResolved;
void ensureResolved(Resolution resolution);
@ -1569,8 +1580,9 @@ abstract class TypeVariableElement extends Element
@deprecated
get enclosingElement;
/// The class or typedef on which this type variable is defined.
TypeDeclarationElement get typeDeclaration;
/// The class, typedef, function, method, or function typed parameter on
/// which this type variable is defined.
GenericElement get typeDeclaration;
/// The index of this type variable within its type declaration.
int get index;
@ -1612,7 +1624,7 @@ abstract class TypedElement extends Element {
}
/// An [Element] that can define a function type.
abstract class FunctionTypedElement extends Element {
abstract class FunctionTypedElement extends Element implements GenericElement {
/// The function signature for the function type defined by this element,
/// if any.
FunctionSignature get functionSignature;

View file

@ -15,7 +15,11 @@ import '../diagnostics/messages.dart' show MessageTemplate;
import '../ordered_typeset.dart' show OrderedTypeSet;
import '../resolution/class_members.dart' show ClassMemberMixin;
import '../resolution/scope.dart'
show ClassScope, LibraryScope, Scope, TypeDeclarationScope;
show
ClassScope,
LibraryScope,
Scope,
TypeDeclarationScope;
import '../resolution/resolution.dart' show AnalyzableElementX;
import '../resolution/tree_elements.dart' show TreeElements;
import '../resolution/typedefs.dart' show TypedefCyclicVisitor;
@ -283,6 +287,9 @@ class ErroneousElementX extends ElementX implements ErroneousElement {
@override
bool get isFromEnvironmentConstructor => false;
@override
List<DartType> get typeVariables => unsupported();
}
/// A constructor that was synthesized to recover from a compile-time error.
@ -1664,6 +1671,9 @@ class FormalElementX extends ElementX
final Identifier identifier;
DartType typeCache;
@override
List<DartType> get typeVariables => functionSignature.typeVariables;
/**
* Function signature for a variable with a function type. The signature is
* kept to provide full information about parameter names through the mirror
@ -1893,6 +1903,7 @@ class AbstractFieldElementX extends ElementX implements AbstractFieldElement {
// TODO(karlklose): all these lists should have element type [FormalElement].
class FunctionSignatureX extends FunctionSignatureCommon
implements FunctionSignature {
final List<DartType> typeVariables;
final List<Element> requiredParameters;
final List<Element> optionalParameters;
final int requiredParameterCount;
@ -1903,7 +1914,8 @@ class FunctionSignatureX extends FunctionSignatureCommon
final bool hasOptionalParameters;
FunctionSignatureX(
{this.requiredParameters: const <Element>[],
{this.typeVariables: const <DartType>[],
this.requiredParameters: const <Element>[],
this.requiredParameterCount: 0,
List<Element> optionalParameters: const <Element>[],
this.optionalParameterCount: 0,
@ -1984,6 +1996,9 @@ abstract class BaseFunctionElementX extends ElementX
FunctionElement asFunctionElement() => this;
@override
Scope buildScope() => new TypeDeclarationScope(super.buildScope(), this);
String toString() {
if (isPatch) {
return 'patch ${super.toString()}';
@ -1998,6 +2013,9 @@ abstract class BaseFunctionElementX extends ElementX
// A function is defined by the implementation element.
AstElement get definingElement => implementation;
@override
List<DartType> get typeVariables => functionSignature.typeVariables;
}
abstract class FunctionElementX extends BaseFunctionElementX
@ -2155,6 +2173,10 @@ abstract class ConstantConstructorMixin implements ConstructorElement {
enclosingClass.name == 'int' ||
enclosingClass.name == 'String');
}
/// Returns the empty list of type variables by default.
@override
List<DartType> get typeVariables => functionSignature.typeVariables;
}
abstract class ConstructorElementX extends FunctionElementX
@ -3085,10 +3107,10 @@ class TypeVariableElementX extends ElementX
DartType boundCache;
TypeVariableElementX(
String name, TypeDeclarationElement enclosing, this.index, this.node)
String name, GenericElement enclosing, this.index, this.node)
: super(name, ElementKind.TYPE_VARIABLE, enclosing);
TypeDeclarationElement get typeDeclaration => enclosingElement;
GenericElement get typeDeclaration => enclosingElement;
TypeVariableType computeType(Resolution resolution) => type;

View file

@ -344,13 +344,13 @@ class NodeListener extends ElementListener {
AsyncModifier asyncModifier = popNode();
NodeList initializers = popNode();
NodeList formals = popNode();
popNode(); // typeVariables
NodeList typeVariables = popNode();
// The name can be an identifier or a send in case of named constructors.
Expression name = popNode();
TypeAnnotation type = popNode();
Modifiers modifiers = popNode();
pushNode(new FunctionExpression(name, formals, body, type, modifiers,
initializers, getOrSet, asyncModifier));
pushNode(new FunctionExpression(name, typeVariables, formals, body, type,
modifiers, initializers, getOrSet, asyncModifier));
}
void endFunctionDeclaration(Token endToken) {
@ -493,12 +493,12 @@ class NodeListener extends ElementListener {
AsyncModifier asyncModifier = popNode();
NodeList initializers = popNode();
NodeList formalParameters = popNode();
popNode(); // typeVariables
NodeList typeVariables = popNode();
Expression name = popNode();
TypeAnnotation returnType = popNode();
Modifiers modifiers = popNode();
pushNode(new FunctionExpression(name, formalParameters, body, returnType,
modifiers, initializers, getOrSet, asyncModifier));
pushNode(new FunctionExpression(name, typeVariables, formalParameters,
body, returnType, modifiers, initializers, getOrSet, asyncModifier));
}
void handleLiteralMap(
@ -564,12 +564,12 @@ class NodeListener extends ElementListener {
void handleFunctionTypedFormalParameter(Token endToken) {
NodeList formals = popNode();
popNode(); // typeVariables
NodeList typeVariables = popNode();
Identifier name = popNode();
TypeAnnotation returnType = popNode();
pushNode(null); // Signal "no type" to endFormalParameter.
pushNode(new FunctionExpression(
name, formals, null, returnType, Modifiers.EMPTY, null, null, null));
pushNode(new FunctionExpression(name, typeVariables, formals, null,
returnType, Modifiers.EMPTY, null, null, null));
}
void handleValuedFormalParameter(Token equals, Token token) {
@ -675,7 +675,7 @@ class NodeListener extends ElementListener {
Modifiers modifiers = popNode();
pushNode(new FunctionExpression(
name, formals, body, null, modifiers, null, null, asyncModifier));
name, null, formals, body, null, modifiers, null, null, asyncModifier));
}
void endForIn(
@ -754,9 +754,9 @@ class NodeListener extends ElementListener {
Statement body = popNode();
AsyncModifier asyncModifier = popNode();
NodeList formals = popNode();
popNode(); // typeVariables
pushNode(new FunctionExpression(
null, formals, body, null, Modifiers.EMPTY, null, null, asyncModifier));
NodeList typeVariables = popNode();
pushNode(new FunctionExpression(null, typeVariables, formals, body, null,
Modifiers.EMPTY, null, null, asyncModifier));
}
void handleIsOperator(Token operathor, Token not, Token endToken) {

View file

@ -82,11 +82,12 @@ class AstBuilder {
symbolToken(Precedence.SEMICOLON_INFO), expression);
}
FunctionExpression functionExpression(
Modifiers modifiers, String name, NodeList argumentList, Statement body,
FunctionExpression functionExpression(Modifiers modifiers, String name,
NodeList typeVariables, NodeList argumentList, Statement body,
[TypeAnnotation returnType]) {
return new FunctionExpression(
identifier(name),
typeVariables,
argumentList,
body,
returnType,
@ -229,6 +230,7 @@ class EnumCreator {
FunctionExpression constructorNode = builder.functionExpression(
builder.modifiers(isConst: true),
enumClass.name,
null, // typeVariables
builder.argumentList([indexDefinition]),
builder.emptyStatement());
@ -298,6 +300,7 @@ class EnumCreator {
FunctionExpression toStringNode = builder.functionExpression(
Modifiers.EMPTY,
'toString',
null, // typeVariables
builder.argumentList([]),
builder.returnStatement(builder.indexGet(
builder.mapLiteral(mapEntries, isConst: true),

View file

@ -17,6 +17,7 @@ import '../dart_types.dart';
import '../elements/elements.dart';
import '../elements/modelx.dart'
show
BaseFunctionElementX,
ConstructorElementX,
ErroneousElementX,
FunctionElementX,
@ -143,7 +144,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
ResolverVisitor(
Compiler compiler, Element element, ResolutionRegistry registry,
{bool useEnclosingScope: false})
{Scope scope, bool useEnclosingScope: false})
: this.enclosingElement = element,
// When the element is a field, we are actually resolving its
// initial value, which should not have access to instance
@ -153,9 +154,9 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
this.currentClass =
element.isClassMember ? element.enclosingClass : null,
this.statementScope = new StatementScope(),
scope = useEnclosingScope
this.scope = scope ?? (useEnclosingScope
? Scope.buildEnclosingScope(element)
: element.buildScope(),
: element.buildScope()),
// The type annotations on a typedef do not imply type checks.
// TODO(karlklose): clean this up (dartbug.com/8870).
inCheckContext = compiler.options.enableTypeAssertions &&
@ -408,16 +409,21 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
if (node.modifiers.isStatic && enclosingElement.kind != ElementKind.CLASS) {
reporter.reportErrorMessage(node, MessageKind.ILLEGAL_STATIC);
}
FunctionSignature functionSignature = function.functionSignature;
// Create the scope where the type variables are introduced, if any.
scope = new MethodScope(scope, function);
// Put the parameters in scope.
FunctionSignature functionParameters = function.functionSignature;
functionSignature.typeVariables.forEach(
(DartType type) => addToScope(type.element));
// Create the scope for the function body, and put the parameters in scope.
scope = new BlockScope(scope);
Link<Node> parameterNodes =
(node.parameters == null) ? const Link<Node>() : node.parameters.nodes;
functionParameters.forEachParameter((ParameterElementX element) {
functionSignature.forEachParameter((ParameterElementX element) {
// TODO(karlklose): should be a list of [FormalElement]s, but the actual
// implementation uses [Element].
List<Element> optionals = functionParameters.optionalParameters;
List<Element> optionals = functionSignature.optionalParameters;
if (!optionals.isEmpty && element == optionals.first) {
NodeList nodes = parameterNodes.head;
parameterNodes = nodes.nodes;
@ -446,14 +452,14 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
parameterNodes = parameterNodes.tail;
});
addDeferredAction(enclosingElement, () {
functionParameters
functionSignature
.forEachOptionalParameter((ParameterElementX parameter) {
parameter.constant =
compiler.resolver.constantCompiler.compileConstant(parameter);
});
});
if (inCheckContext) {
functionParameters.forEachParameter((ParameterElement element) {
functionSignature.forEachParameter((ParameterElement element) {
registry.registerTypeUse(new TypeUse.checkedModeCheck(element.type));
});
}
@ -570,7 +576,13 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
name, node, ElementKind.FUNCTION, Modifiers.EMPTY, enclosingElement);
ResolverTask.processAsyncMarker(compiler, function, registry);
function.functionSignature = SignatureResolver.analyze(
compiler, node.parameters, node.returnType, function, registry,
compiler,
scope,
node.typeVariables,
node.parameters,
node.returnType,
function,
registry,
createRealParameters: true,
isFunctionExpression: !inFunctionDeclaration);
checkLocalDefinitionName(node, function);
@ -1864,7 +1876,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
ResolutionResult handleTypeVariableTypeLiteralAccess(
Send node, Name name, TypeVariableElement element) {
AccessSemantics semantics;
if (!Elements.hasAccessToTypeVariables(enclosingElement)) {
if (!Elements.hasAccessToTypeVariable(enclosingElement, element)) {
// TODO(johnniwinther): Add another access semantics for this.
ErroneousElement error = reportAndCreateErroneousElement(
node,
@ -1905,7 +1917,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
ResolutionResult handleTypeVariableTypeLiteralUpdate(
SendSet node, Name name, TypeVariableElement element) {
AccessSemantics semantics;
if (!Elements.hasAccessToTypeVariables(enclosingElement)) {
if (!Elements.hasAccessToTypeVariable(enclosingElement, element)) {
// TODO(johnniwinther): Add another access semantics for this.
ErroneousElement error = reportAndCreateErroneousElement(
node,

View file

@ -979,6 +979,8 @@ class ResolverTask extends CompilerTask {
FunctionExpression node = element.parseNode(parsingContext);
return measure(() => SignatureResolver.analyze(
compiler,
element.enclosingElement.buildScope(),
node.typeVariables,
node.parameters,
node.returnType,
element,

View file

@ -58,17 +58,14 @@ class VariableDefinitionScope extends NestedScope {
}
}
/**
* [TypeDeclarationScope] defines the outer scope of a type declaration in
* which the declared type variables and the entities in the enclosing scope are
* available but where declared and inherited members are not available. This
* scope is only used for class declarations during resolution of the
* class hierarchy. In all other cases [ClassScope] is used.
*/
class TypeDeclarationScope extends NestedScope {
final TypeDeclarationElement element;
/// [TypeVariablesScope] defines the outer scope in a context where some type
/// variables are declared and the entities in the enclosing scope are
/// available, but where locally declared and inherited members are not
/// available.
abstract class TypeVariablesScope extends NestedScope {
List<DartType> get typeVariables;
TypeDeclarationScope(parent, this.element) : super(parent) {
TypeVariablesScope(Scope parent) : super(parent) {
assert(parent != null);
}
@ -77,7 +74,6 @@ class TypeDeclarationScope extends NestedScope {
}
Element lookupTypeVariable(String name) {
List<DartType> typeVariables = element.typeVariables;
for (TypeVariableType type in typeVariables) {
if (type.name == name) {
return type.element;
@ -87,6 +83,22 @@ class TypeDeclarationScope extends NestedScope {
}
Element localLookup(String name) => lookupTypeVariable(name);
}
/**
* [TypeDeclarationScope] defines the outer scope of a type declaration in
* which the declared type variables and the entities in the enclosing scope are
* available but where declared and inherited members are not available. This
* scope is used for class declarations during resolution of the class hierarchy
* and when resolving typedef signatures. In other cases [ClassScope] is used.
*/
class TypeDeclarationScope extends TypeVariablesScope {
final GenericElement element;
@override
List<DartType> get typeVariables => element.typeVariables;
TypeDeclarationScope(Scope parent, this.element) : super(parent);
String toString() => 'TypeDeclarationScope($element)';
}

View file

@ -15,14 +15,15 @@ import '../elements/modelx.dart'
FormalElementX,
FunctionSignatureX,
InitializingFormalElementX,
LocalParameterElementX;
LocalParameterElementX,
TypeVariableElementX;
import '../tree/tree.dart';
import '../universe/use.dart' show TypeUse;
import '../util/util.dart' show Link, LinkBuilder;
import 'members.dart' show ResolverVisitor;
import 'registry.dart' show ResolutionRegistry;
import 'resolution_common.dart' show MappingVisitor;
import 'scope.dart' show Scope;
import 'scope.dart' show Scope, TypeVariablesScope;
/**
* [SignatureResolver] resolves function signatures.
@ -40,12 +41,13 @@ class SignatureResolver extends MappingVisitor<FormalElementX> {
VariableDefinitions currentDefinitions;
SignatureResolver(Compiler compiler, FunctionTypedElement enclosingElement,
Scope scope,
ResolutionRegistry registry,
{this.defaultValuesError, this.createRealParameters})
: this.enclosingElement = enclosingElement,
this.scope = enclosingElement.buildScope(),
this.resolver =
new ResolverVisitor(compiler, enclosingElement, registry),
: this.scope = scope,
this.enclosingElement = enclosingElement,
this.resolver = new ResolverVisitor(
compiler, enclosingElement, registry, scope: scope),
super(compiler, registry);
bool get defaultValuesAllowed => defaultValuesError == null;
@ -110,6 +112,8 @@ class SignatureResolver extends MappingVisitor<FormalElementX> {
void computeFunctionType(FunctionExpression functionExpression) {
FunctionSignature functionSignature = SignatureResolver.analyze(
compiler,
scope,
functionExpression.typeVariables,
functionExpression.parameters,
functionExpression.returnType,
element,
@ -287,6 +291,8 @@ class SignatureResolver extends MappingVisitor<FormalElementX> {
*/
static FunctionSignature analyze(
Compiler compiler,
Scope scope,
NodeList typeVariables,
NodeList formalParameters,
Node returnNode,
FunctionTypedElement element,
@ -296,8 +302,32 @@ class SignatureResolver extends MappingVisitor<FormalElementX> {
bool isFunctionExpression: false}) {
DiagnosticReporter reporter = compiler.reporter;
List<DartType> createTypeVariables(NodeList typeVariableNodes) {
if (typeVariableNodes == null) return const <DartType>[];
// Create the types and elements corresponding to [typeVariableNodes].
Link<Node> nodes = typeVariableNodes.nodes;
List<DartType> arguments =
new List.generate(nodes.slowLength(), (int index) {
TypeVariable node = nodes.head;
String variableName = node.name.source;
nodes = nodes.tail;
TypeVariableElementX variableElement =
new TypeVariableElementX(variableName, element, index, node);
// TODO(eernst): When type variables are implemented fully we will need
// to resolve the actual bounds; currently we just claim [dynamic].
variableElement.boundCache = const DynamicType();
TypeVariableType variableType = new TypeVariableType(variableElement);
variableElement.typeCache = variableType;
return variableType;
}, growable: false);
return arguments;
}
List<DartType> typeVariableTypes = createTypeVariables(typeVariables);
scope = new FunctionSignatureBuildingScope(scope, typeVariableTypes);
SignatureResolver visitor = new SignatureResolver(
compiler, element, registry,
compiler, element, scope, registry,
defaultValuesError: defaultValuesError,
createRealParameters: createRealParameters);
List<Element> parameters = const <Element>[];
@ -411,6 +441,7 @@ class SignatureResolver extends MappingVisitor<FormalElementX> {
namedParameters,
namedParameterTypes);
return new FunctionSignatureX(
typeVariables: typeVariableTypes,
requiredParameters: parameters,
optionalParameters: visitor.optionalParameters,
requiredParameterCount: requiredParameterCount,
@ -437,3 +468,15 @@ class SignatureResolver extends MappingVisitor<FormalElementX> {
return result;
}
}
/// Used during `SignatureResolver.analyze` to provide access to the type
/// variables of the function signature itself when its signature is analyzed.
class FunctionSignatureBuildingScope extends TypeVariablesScope {
@override
final List<DartType> typeVariables;
FunctionSignatureBuildingScope(Scope parent, this.typeVariables)
: super(parent);
String toString() => 'FunctionSignatureBuildingScope($typeVariables)';
}

View file

@ -18,6 +18,7 @@ import '../elements/elements.dart'
ErroneousElement,
PrefixElement,
TypedefElement,
TypeDeclarationElement,
TypeVariableElement;
import '../elements/modelx.dart' show ErroneousElementX;
import '../tree/tree.dart';
@ -205,12 +206,17 @@ class TypeResolver {
}
}
} else if (element.isTypeVariable) {
// FIXME: check enclosing, which may be not class, not typedef (so
// it's a generic method) then set the type to `const DynamicType()`.
// This should later be fixed such that we don't tell the user that they
// wrote `dynamic` anywhere.
TypeVariableElement typeVariable = element;
Element outer =
visitor.enclosingElement.outermostEnclosingMemberOrTopLevel;
if (!outer.isClass &&
!outer.isTypedef &&
!Elements.hasAccessToTypeVariables(visitor.enclosingElement)) {
!Elements.hasAccessToTypeVariable(
visitor.enclosingElement, typeVariable)) {
registry.registerFeature(Feature.THROW_RUNTIME_ERROR);
type = reportFailureAndCreateType(
MessageKind.TYPE_VARIABLE_WITHIN_STATIC_MEMBER,

View file

@ -31,7 +31,13 @@ class TypedefResolverVisitor extends TypeDefinitionVisitor {
resolveTypeVariableBounds(node.typeParameters);
FunctionSignature signature = SignatureResolver.analyze(
compiler, node.formals, node.returnType, element, registry,
compiler,
scope,
null /* typeVariables */,
node.formals,
node.returnType,
element,
registry,
defaultValuesError: MessageKind.TYPEDEF_FORMAL_WITH_DEFAULT);
element.functionSignature = signature;

View file

@ -758,6 +758,9 @@ abstract class FunctionTypedElementMixin
return _decoder.getBool(Key.IS_EXTERNAL,
isOptional: true, defaultValue: false);
}
@override
List<DartType> get typeVariables => functionSignature.typeVariables;
}
abstract class ClassElementMixin implements ElementZ, ClassElement {
@ -1329,6 +1332,9 @@ class ForwardingConstructorElementZ extends ElementZ
// variables correctly.
return definingConstructor.type;
}
@override
List<DartType> get typeVariables => _unsupported("typeVariables");
}
abstract class MemberElementMixin
@ -1868,6 +1874,9 @@ abstract class ParameterElementZ extends DeserializedElementZ
@override
MemberElement get memberContext => executableContext.memberContext;
@override
List<DartType> get typeVariables => functionSignature.typeVariables;
}
class LocalParameterElementZ extends ParameterElementZ

View file

@ -425,6 +425,7 @@ class ResolvedAstDeserializer {
FunctionExpression toStringNode = builder.functionExpression(
Modifiers.EMPTY,
'toString',
null,
builder.argumentList([]),
builder.returnStatement(builder.indexGet(
builder.mapLiteral(mapEntries, isConst: true),
@ -437,6 +438,7 @@ class ResolvedAstDeserializer {
FunctionExpression constructorNode = builder.functionExpression(
builder.modifiers(isConst: true),
element.enclosingClass.name,
null,
builder.argumentList([indexDefinition]),
builder.emptyStatement());
return constructorNode;

View file

@ -1076,6 +1076,7 @@ class AsyncModifier extends Node {
class FunctionExpression extends Expression with StoredTreeElementMixin {
final Node name;
final NodeList typeVariables;
/**
* List of VariableDefinitions or NodeList.
@ -1092,8 +1093,16 @@ class FunctionExpression extends Expression with StoredTreeElementMixin {
final Token getOrSet;
final AsyncModifier asyncModifier;
FunctionExpression(this.name, this.parameters, this.body, this.returnType,
this.modifiers, this.initializers, this.getOrSet, this.asyncModifier) {
FunctionExpression(
this.name,
this.typeVariables,
this.parameters,
this.body,
this.returnType,
this.modifiers,
this.initializers,
this.getOrSet,
this.asyncModifier) {
assert(modifiers != null);
}
@ -1111,6 +1120,7 @@ class FunctionExpression extends Expression with StoredTreeElementMixin {
if (modifiers != null) modifiers.accept(visitor);
if (returnType != null) returnType.accept(visitor);
if (name != null) name.accept(visitor);
if (typeVariables != null) typeVariables.accept(visitor);
if (parameters != null) parameters.accept(visitor);
if (initializers != null) initializers.accept(visitor);
if (asyncModifier != null) asyncModifier.accept(visitor);
@ -1121,6 +1131,7 @@ class FunctionExpression extends Expression with StoredTreeElementMixin {
if (modifiers != null) modifiers.accept1(visitor, arg);
if (returnType != null) returnType.accept1(visitor, arg);
if (name != null) name.accept1(visitor, arg);
if (typeVariables != null) typeVariables.accept1(visitor, arg);
if (parameters != null) parameters.accept1(visitor, arg);
if (initializers != null) initializers.accept1(visitor, arg);
if (asyncModifier != null) asyncModifier.accept1(visitor, arg);
@ -3102,6 +3113,7 @@ class ErrorNode extends Node
// FunctionExpression.
get asyncModifier => null;
get typeVariables => null;
get parameters => null;
get body => null;
get returnType => null;

View file

@ -11,6 +11,7 @@ import 'package:compiler/compiler.dart' as api;
import 'package:compiler/src/common/names.dart' show
Uris;
import 'package:compiler/src/constants/expressions.dart';
import 'package:compiler/src/dart_types.dart' show DartType;
import 'package:compiler/src/diagnostics/diagnostic_listener.dart';
import 'package:compiler/src/diagnostics/source_span.dart';
import 'package:compiler/src/diagnostics/spannable.dart';
@ -224,10 +225,15 @@ class MockCompiler extends Compiler {
TreeElementMapping resolveNodeStatement(Node tree,
ExecutableElement element) {
ResolverVisitor visitor =
new ResolverVisitor(this, element,
new ResolverVisitor(
this,
element,
new ResolutionRegistry(this,
new CollectingTreeElements(element)));
if (visitor.scope is LibraryScope) {
new CollectingTreeElements(element)),
scope: new MockTypeVariablesScope(
element.enclosingElement.buildScope()));
if (visitor.scope is LibraryScope ||
visitor.scope is MockTypeVariablesScope) {
visitor.scope = new MethodScope(visitor.scope, element);
}
visitor.visit(tree);
@ -238,9 +244,12 @@ class MockCompiler extends Compiler {
resolverVisitor() {
Element mockElement = new MockElement(mainApp.entryCompilationUnit);
ResolverVisitor visitor =
new ResolverVisitor(this, mockElement,
new ResolutionRegistry(this,
new CollectingTreeElements(mockElement)));
new ResolverVisitor(
this,
mockElement,
new ResolutionRegistry(
this, new CollectingTreeElements(mockElement)),
scope: mockElement.enclosingElement.buildScope());
visitor.scope = new MethodScope(visitor.scope, mockElement);
return visitor;
}
@ -321,6 +330,13 @@ class CollectingTreeElements extends TreeElementMapping {
}
}
class MockTypeVariablesScope extends TypeVariablesScope {
@override
List<DartType> get typeVariables => <DartType>[];
MockTypeVariablesScope(Scope parent) : super(parent);
String toString() => 'MockTypeVariablesScope($parent)';
}
// The mock compiler does not split the program in output units.
class MockDeferredLoadTask extends DeferredLoadTask {
MockDeferredLoadTask(Compiler compiler) : super(compiler);

View file

@ -222,10 +222,11 @@ Future testSuperCalls() {
ClassElement classA = compiler.mainApp.find("A");
FunctionElement fooA = classA.lookupLocalMember("foo");
ResolverVisitor visitor =
new ResolverVisitor(compiler, fooB,
new ResolutionRegistry(compiler,
new CollectingTreeElements(fooB)));
ResolverVisitor visitor = new ResolverVisitor(
compiler,
fooB,
new ResolutionRegistry(compiler, new CollectingTreeElements(fooB)),
scope: new MockTypeVariablesScope(classB.buildScope()));
FunctionExpression node =
(fooB as FunctionElementX).parseNode(compiler.parsingContext);
visitor.visit(node.body);
@ -266,10 +267,12 @@ Future testThis() {
compiler.resolveStatement("Foo foo;");
ClassElement fooElement = compiler.mainApp.find("Foo");
FunctionElement funElement = fooElement.lookupLocalMember("foo");
ResolverVisitor visitor =
new ResolverVisitor(compiler, funElement,
new ResolutionRegistry(compiler,
new CollectingTreeElements(funElement)));
ResolverVisitor visitor = new ResolverVisitor(
compiler,
funElement,
new ResolutionRegistry(
compiler, new CollectingTreeElements(funElement)),
scope: new MockTypeVariablesScope(fooElement.buildScope()));
FunctionExpression function =
(funElement as FunctionElementX).parseNode(compiler.parsingContext);
visitor.visit(function.body);
@ -292,9 +295,12 @@ Future testThis() {
compiler.resolveStatement("Foo foo;");
ClassElement fooElement = compiler.mainApp.find("Foo");
FunctionElement funElement = fooElement.lookupLocalMember("foo");
ResolverVisitor visitor = new ResolverVisitor(compiler, funElement,
new ResolutionRegistry(compiler,
new CollectingTreeElements(funElement)));
ResolverVisitor visitor = new ResolverVisitor(
compiler,
funElement,
new ResolutionRegistry(
compiler, new CollectingTreeElements(funElement)),
scope: new MockTypeVariablesScope(fooElement.buildScope()));
FunctionExpression function =
(funElement as FunctionElementX).parseNode(compiler.parsingContext);
visitor.visit(function.body);
@ -581,10 +587,10 @@ Future testOneInterface() {
// correctly.
compiler.parseScript("abstract class Bar {}");
ResolverVisitor visitor =
new ResolverVisitor(compiler, null,
new ResolutionRegistry(compiler,
new CollectingTreeElements(null)));
ResolverVisitor visitor = new ResolverVisitor(
compiler,
null,
new ResolutionRegistry(compiler, new CollectingTreeElements(null)));
compiler.resolveStatement("Foo bar;");
ClassElement fooElement = compiler.mainApp.find('Foo');
@ -619,7 +625,6 @@ Future testTwoInterfaces() {
Future testFunctionExpression() {
return MockCompiler.create((MockCompiler compiler) {
ResolverVisitor visitor = compiler.resolverVisitor();
Map mapping = compiler.resolveStatement("int f() {}").map;
Expect.equals(2, mapping.length);
Element element;
@ -701,10 +706,11 @@ Future resolveConstructor(
Element element;
element = classElement.lookupConstructor(constructor);
FunctionExpression tree = (element as FunctionElement).node;
ResolverVisitor visitor =
new ResolverVisitor(compiler, element,
new ResolutionRegistry(compiler,
new CollectingTreeElements(element)));
ResolverVisitor visitor = new ResolverVisitor(
compiler,
element,
new ResolutionRegistry(compiler, new CollectingTreeElements(element)),
scope: classElement.buildScope());
new InitializerResolver(visitor, element, tree).resolveInitializers();
visitor.visit(tree.body);
Expect.equals(expectedElementCount, map(visitor).length,