Chromium Code Reviews| Index: pkg/front_end/lib/src/fasta/scope.dart |
| diff --git a/pkg/front_end/lib/src/fasta/scope.dart b/pkg/front_end/lib/src/fasta/scope.dart |
| index c477ba95b303735a04e833cdc9f809eb24970cf6..2dd1656ef0bf633fb525fc4f7574981daa07c032 100644 |
| --- a/pkg/front_end/lib/src/fasta/scope.dart |
| +++ b/pkg/front_end/lib/src/fasta/scope.dart |
| @@ -4,21 +4,25 @@ |
| library fasta.scope; |
| -import 'builder/builder.dart' show Builder, MixedAccessor; |
| +import 'builder/builder.dart' show Builder, TypeVariableBuilder; |
| import 'errors.dart' show internalError; |
| -class Scope { |
| +class MutableScope { |
| /// Names declared in this scope. |
| - final Map<String, Builder> local; |
| + Map<String, Builder> local; |
| /// Setters declared in this scope. |
| - final Map<String, Builder> setters; |
| + Map<String, Builder> setters; |
| /// The scope that this scope is nested within, or `null` if this is the top |
| /// level scope. |
| - final Scope parent; |
| + Scope parent; |
| + MutableScope(this.local, this.setters, this.parent); |
| +} |
| + |
| +class Scope extends MutableScope { |
| /// Indicates whether an attempt to declare new names in this scope should |
| /// succeed. |
| final bool isModifiable; |
| @@ -27,9 +31,9 @@ class Scope { |
| Map<String, Builder> forwardDeclaredLabels; |
| - Scope(this.local, Map<String, Builder> setters, this.parent, |
| + Scope(Map<String, Builder> local, Map<String, Builder> setters, Scope parent, |
| {this.isModifiable: true}) |
| - : setters = setters ?? const <String, Builder>{}; |
| + : super(local, setters = setters ?? const <String, Builder>{}, parent); |
| Scope.top({bool isModifiable: false}) |
| : this(<String, Builder>{}, <String, Builder>{}, null, |
| @@ -42,10 +46,38 @@ class Scope { |
| Scope.nested(Scope parent, {bool isModifiable: true}) |
| : this(<String, Builder>{}, null, parent, isModifiable: isModifiable); |
| + /// Don't use this. Use [becomePartOf] instead. |
| + void set local(_) => internalError("Unsupported operation."); |
| + |
| + /// Don't use this. Use [becomePartOf] instead. |
| + void set setters(_) => internalError("Unsupported operation."); |
| + |
| + /// Don't use this. Use [becomePartOf] instead. |
| + void set parent(_) => internalError("Unsupported operation."); |
| + |
| + /// This scope becomes equivalent to [scope]. This is used for parts to |
| + /// become part of their library's scope. |
| + void becomePartOf(Scope scope) { |
| + assert(parent.parent == null); |
| + assert(scope.parent.parent == null); |
| + super.local = scope.local; |
| + super.setters = scope.setters; |
| + super.parent = scope.parent; |
| + } |
| + |
| Scope createNestedScope({bool isModifiable: true}) { |
| return new Scope.nested(this, isModifiable: isModifiable); |
| } |
| + Scope withTypeVariables(List<TypeVariableBuilder> typeVariables) { |
| + if (typeVariables == null) return this; |
| + Scope newScope = new Scope.nested(this, isModifiable: false); |
| + for (TypeVariableBuilder t in typeVariables) { |
| + newScope.local[t.name] = t; |
| + } |
| + return newScope; |
| + } |
| + |
| /// Create a special scope for use by labeled staments. This scope doesn't |
| /// introduce a new scope for local variables, only for labels. This deals |
| /// with corner cases like this: |
| @@ -57,66 +89,49 @@ class Scope { |
| return new Scope(local, setters, parent, isModifiable: true); |
| } |
| - Builder lookup(String name, int charOffset, Uri fileUri, |
| - {bool isInstanceScope: true}) { |
| - Builder builder = local[name]; |
| - if (builder != null) { |
| - if (builder.next != null) { |
| - return lookupAmbiguous(name, builder, false, charOffset, fileUri); |
| - } |
| - return builder.isSetter |
| - ? new AccessErrorBuilder(name, builder, charOffset, fileUri) |
| - : builder; |
| + Builder lookupIn(String name, int charOffset, Uri fileUri, |
| + Map<String, Builder> map, bool isInstanceScope) { |
| + Builder builder = map[name]; |
| + if (builder == null) return null; |
| + if (builder.next != null) { |
| + return new AmbiguousBuilder(name, builder, charOffset, fileUri); |
| + } else if (!isInstanceScope && builder.isInstanceMember) { |
| + return null; |
| } else { |
| - return parent?.lookup(name, charOffset, fileUri); |
| + return builder; |
| } |
| } |
| - Builder lookupSetter(String name, int charOffset, Uri fileUri, |
| + Builder lookup(String name, int charOffset, Uri fileUri, |
| {bool isInstanceScope: true}) { |
| - Builder builder = local[name]; |
| - if (builder != null) { |
| - if (builder.next != null) { |
| - return lookupAmbiguous(name, builder, true, charOffset, fileUri); |
| - } |
| - if (builder.isField) { |
| - if (builder.isFinal) { |
| - return new AccessErrorBuilder(name, builder, charOffset, fileUri); |
| - } else { |
| - return builder; |
| - } |
| - } else if (builder.isSetter) { |
| - return builder; |
| - } else { |
| - return new AccessErrorBuilder(name, builder, charOffset, fileUri); |
| - } |
| - } else { |
| - return parent?.lookupSetter(name, charOffset, fileUri); |
| + Builder builder = |
| + lookupIn(name, charOffset, fileUri, local, isInstanceScope); |
| + if (builder != null) return builder; |
| + builder = lookupIn(name, charOffset, fileUri, setters, isInstanceScope); |
| + if (builder != null && !builder.hasProblem) { |
| + return new AccessErrorBuilder(name, builder, charOffset, fileUri); |
| } |
| + if (!isInstanceScope) { |
| + // For static lookup, do not seach the parent scope. |
| + return builder; |
| + } |
| + return builder ?? parent?.lookup(name, charOffset, fileUri); |
| } |
| - Builder lookupAmbiguous( |
| - String name, Builder builder, bool setter, int charOffset, Uri fileUri) { |
| - assert(builder.next != null); |
| - if (builder is MixedAccessor) { |
| - return setter ? builder.setter : builder.getter; |
| + Builder lookupSetter(String name, int charOffset, Uri fileUri, |
| + {bool isInstanceScope: true}) { |
| + Builder builder = |
| + lookupIn(name, charOffset, fileUri, setters, isInstanceScope); |
| + if (builder != null) return builder; |
| + builder = lookupIn(name, charOffset, fileUri, local, isInstanceScope); |
| + if (builder != null && !builder.hasProblem) { |
| + return new AccessErrorBuilder(name, builder, charOffset, fileUri); |
| } |
| - Builder setterBuilder; |
| - Builder getterBuilder; |
| - Builder current = builder; |
| - while (current != null) { |
| - if (current.isGetter && getterBuilder == null) { |
| - getterBuilder = current; |
| - } else if (current.isSetter && setterBuilder == null) { |
| - setterBuilder = current; |
| - } else { |
| - return new AmbiguousBuilder(name, builder, charOffset, fileUri); |
| - } |
| - current = current.next; |
| + if (!isInstanceScope) { |
| + // For static lookup, do not seach the parent scope. |
| + return builder; |
| } |
| - assert(getterBuilder != null); |
| - assert(setterBuilder != null); |
| - return setter ? setterBuilder : getterBuilder; |
| + return builder ?? parent?.lookupSetter(name, charOffset, fileUri); |
| } |
| bool hasLocalLabel(String name) => labels != null && labels.containsKey(name); |
| @@ -161,8 +176,28 @@ class Scope { |
| } |
| } |
| + void merge(Scope scope, |
| + buildAmbiguousBuilder(String name, Builder existing, Builder member)) { |
|
karlklose
2017/04/03 08:05:37
Consider adding a typedef for this parameter's typ
ahe
2017/04/04 09:54:51
I prefer to not introduce new typedefs unless the
|
| + Map<String, Builder> map = local; |
| + |
| + void mergeMember(String name, Builder member) { |
| + Builder existing = map[name]; |
| + if (existing != null) { |
| + if (existing != member) { |
| + member = buildAmbiguousBuilder(name, existing, member); |
| + } |
| + } |
| + map[name] = member; |
| + } |
| + |
| + scope.local.forEach(mergeMember); |
| + map = setters; |
| + scope.setters.forEach(mergeMember); |
| + } |
| + |
| void forEach(f(String name, Builder member)) { |
| local.forEach(f); |
| + setters.forEach(f); |
| } |
| String get debugString { |
| @@ -188,6 +223,22 @@ class Scope { |
| } |
| } |
| +class ScopeBuilder { |
| + final Scope scope; |
| + |
| + ScopeBuilder(this.scope); |
| + |
| + void addMember(String name, Builder builder) { |
| + scope.local[name] = builder; |
| + } |
| + |
| + void addSetter(String name, Builder builder) { |
| + scope.setters[name] = builder; |
| + } |
| + |
| + Builder operator [](String name) => scope.local[name]; |
| +} |
| + |
| abstract class ProblemBuilder extends Builder { |
| final String name; |