Chromium Code Reviews| Index: pkg/front_end/lib/src/fasta/kernel/body_builder.dart |
| diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart |
| index 37d5f8c7345f878bcfd7f6358d90f026ef76ebe2..bdd87d8e9d5f4132504a1bf2d079aab5e079ec68 100644 |
| --- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart |
| +++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart |
| @@ -1697,13 +1697,38 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper { |
| } |
| } |
| + @override |
| + void beginFunctionType(Token beginToken) { |
| + debugEvent("beginFunctionType"); |
| + List typeVariables = pop(); |
| + enterLocalScope(scope.createNestedScope(isModifiable: false)); |
| + push(typeVariables ?? NullValue.TypeVariables); |
| + if (typeVariables != null) { |
| + ScopeBuilder scopeBuilder = new ScopeBuilder(scope); |
| + for (KernelTypeVariableBuilder builder in typeVariables) { |
| + String name = builder.name; |
| + KernelTypeVariableBuilder existing = scopeBuilder[name]; |
| + if (existing == null) { |
| + scopeBuilder.addMember(name, builder); |
| + } else { |
| + addCompileTimeError( |
| + builder.charOffset, "'$name' already declared in this scope."); |
| + addCompileTimeError( |
| + existing.charOffset, "Previous definition of '$name'."); |
| + } |
| + } |
| + } |
| + } |
| + |
| @override |
| void endFunctionType(Token functionToken, Token endToken) { |
| debugEvent("FunctionType"); |
| FormalParameters formals = pop(); |
| DartType returnType = pop(); |
| - ignore(Unhandled.TypeVariables); |
| - push(formals.toFunctionType(returnType)); |
| + List<TypeParameter> typeVariables = typeVariableBuildersToKernel(pop()); |
| + FunctionType type = formals.toFunctionType(returnType, typeVariables); |
| + exitLocalScope(); |
| + push(type); |
| } |
| @override |
| @@ -2403,7 +2428,7 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper { |
| exitLocalScope(); |
| } |
| FormalParameters formals = pop(); |
| - List<TypeParameter> typeParameters = pop(); |
| + List<TypeParameter> typeParameters = typeVariableBuildersToKernel(pop()); |
| push(formals.addToFunction(new FunctionNode(body, |
| typeParameters: typeParameters, asyncMarker: asyncModifier) |
| ..fileOffset = formals.charOffset |
| @@ -2447,7 +2472,7 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper { |
| exitLocalScope(); |
| FormalParameters formals = pop(); |
| exitFunction(); |
| - List<TypeParameter> typeParameters = pop(); |
| + List<TypeParameter> typeParameters = typeVariableBuildersToKernel(pop()); |
| FunctionNode function = formals.addToFunction(new FunctionNode(body, |
| typeParameters: typeParameters, asyncMarker: asyncModifier) |
| ..fileOffset = beginToken.charOffset |
| @@ -2915,17 +2940,36 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper { |
| @override |
| void endTypeVariable(Token token, Token extendsOrSuper) { |
| debugEvent("TypeVariable"); |
| - // TODO(ahe): Do not discard these when enabling generic method syntax. |
| - pop(); // Bound. |
| - pop(); // Name. |
| + DartType bound = pop(); |
| + if (bound != null) { |
| + // TODO(ahe): To handle F-bounded types, this needs to be a TypeBuilder. |
| + warningNotError("Type variable bounds not implemented yet.", |
| + offsetForToken(extendsOrSuper.next)); |
| + } |
| + Identifier name = pop(); |
| + // TODO(ahe): Do not discard metadata. |
| pop(); // Metadata. |
| + push(new KernelTypeVariableBuilder( |
| + name.name, library, offsetForToken(name.token), null) |
| + ..finish(library, library.loader.coreLibrary["Object"])); |
| } |
| @override |
| void endTypeVariables(int count, Token beginToken, Token endToken) { |
| debugEvent("TypeVariables"); |
| - // TODO(ahe): Implement this when enabling generic method syntax. |
| - push(NullValue.TypeVariables); |
| + push(popList(count) ?? NullValue.TypeVariables); |
| + } |
| + |
| + List<TypeParameter> typeVariableBuildersToKernel(List typeVariableBuilders) { |
| + if (typeVariableBuilders == null) return null; |
| + List<TypeParameter> typeParameters = new List<TypeParameter>.filled( |
|
Paul Berry
2017/06/29 17:45:40
Nit: why not use map()?
ahe
2017/07/04 11:07:45
I try to avoid methods like that because they aren
|
| + typeVariableBuilders.length, null, |
| + growable: true); |
| + int i = 0; |
| + for (KernelTypeVariableBuilder builder in typeVariableBuilders) { |
| + typeParameters[i++] = builder.target; |
| + } |
| + return typeParameters; |
| } |
| @override |
| @@ -3571,8 +3615,10 @@ class FormalParameters { |
| return function; |
| } |
| - FunctionType toFunctionType(DartType returnType) { |
| + FunctionType toFunctionType(DartType returnType, |
| + [List<TypeParameter> typeParameters]) { |
| returnType ??= const DynamicType(); |
| + typeParameters ??= const <TypeParameter>[]; |
| int requiredParameterCount = required.length; |
| List<DartType> positionalParameters = <DartType>[]; |
| List<NamedType> namedParameters = const <NamedType>[]; |
| @@ -3594,7 +3640,8 @@ class FormalParameters { |
| } |
| return new FunctionType(positionalParameters, returnType, |
| namedParameters: namedParameters, |
| - requiredParameterCount: requiredParameterCount); |
| + requiredParameterCount: requiredParameterCount, |
| + typeParameters: typeParameters); |
| } |
| Scope computeFormalParameterScope( |